怎样得到bean中的所有字段

怎样得到bean中的所有字段,第1张

利用java 反射机制,运行时获取类信息

package comtestdoemo;

import javalangreflectField;

import javalangreflectMethod;

public class MainTest {

/

@param args

/

public static void main(String[] args) throws Exception{

Class demo=ClassforName("comtestdoemoStudent");

Field[] fields=demogetDeclaredFields();

Method[] methods=demogetDeclaredMethods();

for(Field f:fields){

Systemoutprintln("字段:"+fgetName());

}

for(Method method:methods){

String m=methodgetName();

if( mcontains("set")){

Systemoutprintln("方法:"+m+"()");

}

}

}

}

class Student{

private String name;

private int age;

private String address;

public String getName() {

return name;

}

public void setName(String name) {

thisname = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

thisage = age;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

thisaddress = address;

}

}

私有、公有这些访问控制,主要是针对类的扩展或子类化设置的,针对现实世界的抽象和封装。

一般都是一些Web框架需要用反射,日常代码里面一般不用,用到的时候一般来说破坏了面向对象的特性。

@Autowired 注解的实现过程,其实就是Spring Bean的自动装配过程。通过看@Autowired源码注释部分我们可以看到 @Autowired 的实现是通过 AutowiredAnnotationBeanPostProcessor 后置处理器中实现的。

在分析自动装配前我们先来介绍一下上面的这些后置处理器。

BeanPostProcessor有两个方法, postProcessBeforeInitialization 和 postProcessAfterInitialization 。它们分别在任何bean初始化回调之前或之后执行(例如InitializingBean的afterPropertiesSet方法或自定义init-method方法之前或者之后), 在这个时候该bean的属性值已经填充完成了,并且我们返回的bean实例可能已经是原始实例的包装类型了。例如返回一个 FactoryBean 。

InstantiationAwareBeanPostProcessor 继承自 BeanPostProcessor 接口。主要多提供了以下三个方法。

该方法是在Bean实例化目标对象之前调用,返回的Bean对象可以代理目标,从而有效的阻止了目标Bean的默认实例化。

跟进源码我们可以看出,如果此方法返回一个非null对象,则Bean创建过程将被短路。唯一应用的进一步处理是来自已配置BeanPostProcessors的postProcessAfterInitialization回调。

该方法执行在通过构造函数或工厂方法在实例化bean之后但在发生Spring属性填充(通过显式属性或自动装配)之前执行 *** 作。这是在Spring的自动装配开始之前对给定的bean实例执行自定义字段注入的理想回调。如果该方法返回false,那么它会阻断后续 InstantiationAwareBeanPostProcessor 后置处理器的执行,并且会阻止后续属性填充的执行逻辑。

在工厂将给定属性值应用于给定bean之前,对它们进行后处理。允许检查是否满足所有依赖关系,例如基于bean属性设置器上的“ Required”注解。还允许替换要应用的属性值,通常是通过基于原始PropertyValues创建新的MutablePropertyValues实例,添加或删除特定值来实现。

智能实例化Bean的后处理器,主要提供了三个方法。

预测从此处理器的postProcessBeforeInstantiation回调最终返回的bean的类型。

确定使用实例化Bean的构造函数。

获取提早暴露的Bean的引用,提早暴露的Bean就是只完成了实例化,还未完成属性赋值和初始化的Bean。

合并Bean的定义信息的后处理方法,该方法是在Bean的实例化之后设置值之前调用。

AutowiredAnnotationBeanPostProcessor 后置处理器主要负责对添加了@Autowired和@Value注解的元素实现自动装配。所以找到需要自动装配的元素,其实就是对@Autowired和@Value注解的解析。

AutowiredAnnotationBeanPostProcessor 后置处理器,找出需要自动装配的元素是在 MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition 这个方法中实现的,调用链路如下:

从链路上我们可以看到,找到需要自动装配的元素是在 findAutowiringMetadata 方法中实现的,该方法会去调用 buildAutowiringMetadata 方法构建元数据信息。如果注解被加载属性上将会被封装成 AutowiredFieldElement 对象;如果注解加在方法上,那么元素会被封装成 AutowiredMethodElement 对象。这里两个对象的 inject 方法将最后完成属性值的注入,主要区别就是使用反射注入值的方式不一样。源码如下:

寻找需要自动装配过程:

AutowiredAnnotationBeanPostProcessor 后置处理器注入属性值是在 postProcessPropertyValues 方法中实现的。源码如下:

从这里的源码我们可以看出 AutowiredFieldElement 和 AutowiredMethodElement 完成自动装配都是先去容器中找对应的Bean,然后通过反射将获取到的Bean设置到目标对象中,来完成Bean的自动装配。

我们可以看出Spring Bean的自动装配过程就是:

在自动装配过程中还涉及循环依赖的问题,有兴趣的可以看下这篇文章 Spring 源码(八)循环依赖

(1)获得对象的类型:

–Class classType=objectgetClass();

–Systemoutprintln("Class:"+classTypegetName());

在javalangObject类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API 中的核心类,它有以下方法

–getName():获得类的完整名字。

–getFields():获得类的public类型的属性。

–getDeclaredFields():获得类的所有属性。

–getMethods():获得类的public类型的方法。

–getDeclaredMethods():获得类的所有方法。

•getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。

•getConstructors():获得类的public类型的构造方法。

•getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。

•newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

(2)通过默认构造方法创建一个新对象:

•Object objectCopy=classTypegetConstructor(new Class[]{})newInstance(new Object[]{});

•以上代码先调用Class类的getConstructor()方法获得一个Constructor 对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。

(3)获得对象的所有属性:

•Field fields[]=classTypegetDeclaredFields();

•Class 类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性

给你一段属性反射的代码,你自己看着改吧

       Field[] fs = userClagetDeclaredFields();

       for(int i = 0 ; i < fslength; i++){

           Field f = fs[i];

           fsetAccessible(true); //设置些属性是可以访问的

           Object val = fget(bean);//得到此属性的值   

      

           Systemoutprintln("name:"+fgetName()+"\t value = "+val);

          

           String type = fgetType()toString();//得到此属性的类型

           if (typeendsWith("String")) {

              Systemoutprintln(fgetType()+"\t是String");

              fset(bean,"12") ;        //给属性设值

           }else if(typeendsWith("int") || typeendsWith("Integer")){

              Systemoutprintln(fgetType()+"\t是int");

              fset(bean,12) ;       //给属性设值

           }else{

              Systemoutprintln(fgetType()+"\t");

           }

          

       }

基本就是getType()之后,根据type的类型来反射

   spring框架的原理其实主要是dom4j+反射+xml原理就是将xml用dmo4j解析,然后取出xml中的元素赋值到实体类中,实体类用反射机制获取其中的属性。下面具体来说明一下。

首先创建一个UserEntity的实体类

第一步:创建一个实体类

<xml version="10" encoding="UTF-8">

<beans>

 <bean id="user1" class="entityUserEntity">

  <property name="userId" value="0001"></property>

  <property name="userName" value="余胜军"></property>

 </bean>

 <bean id="user2" class="entityUserEntity">

  <property name="userId" value="0002"></property>

  <property name="userName" value="张三"></property>

 </bean>

</beans>

第二步:手写一个简单的xml

<xml version="10" encoding="UTF-8"> 

<students> 

    <student1 id="001"> 

        <>@听风_与你</> 

        <学号>20140101</学号> 

        <地址>上海市浦东新区世纪大道</地址> 

        <座右铭>要么强大,要么听话</座右铭> 

    </student1> 

    <student2 id="002"> 

        <>@听风_与你</> 

        <学号>20140102</学号> 

        <地址>上海市浦东新区世纪大道</地址> 

        <座右铭>自信不自大,失败不气馁,倒了爬起来</座右铭> 

    </student2> 

</students>

第三步:创建一个解析xml并且反射将值赋值的类。

package classForm;

import javalangreflectField;

import javautilList;

import orgapachecommonslangStringUtils;

import orgdom4jDocument;

import orgdom4jElement;

import orgdom4jioSAXReader;

import entityUserEntity;

public class ClassPathXmlApplicationContext {

 private String xmlPath;

 public ClassPathXmlApplicationContext(String xmlPath) {

  thisxmlPath = xmlPath;

 }

 public Object getBean(String beanId) throws Exception {

  // 解析xml器

  SAXReader saxReader = new SAXReader();

  Document read = null;

  try {

   // 从项目根目录路径下 读取

   read = saxReaderread(thisgetClass()getClassLoader()

     getResourceAsStream(xmlPath));

  } catch (Exception e) {

   eprintStackTrace();

  }

  if (read == null) {

   return null;

  }

  // 获取根节点资源

  Element root = readgetRootElement();

  List<Element> elements = rootelements();

  if (elementssize() <= 0) {

   return null;

  }

  Object oj = null;

  for (Element element : elements) {

   String id = elementattributeValue("id");

   if (StringUtilsisEmpty(id)) {

    return null;

   }

   if (!idequals(beanId)) {

    continue;

    // throw new Exception("使用beanId:" + beanId + ",未找到该bean");

   }

   // 获取实体bean class地址

   String beanClass = elementattributeValue("class");

   // 使用反射实例化bean

   Class<> forNameClass = ClassforName(beanClass);

   oj = forNameClassnewInstance();

   // 获取子类对象

   List<Element> attributes = elementelements();

   if (attributessize() <= 0) {

    return null;

   }

   for (Element et : attributes) {

    // 使用反射技术为方法赋值

    String name = etattributeValue("name");

    String value = etattributeValue("value");

    Field field = forNameClassgetDeclaredField(name);

    fieldsetAccessible(true);

    fieldset(oj, value);

   }

  }

  return oj;

  // 1使用beanId查找配置文件中的bean。

  // 2获取对应bean中的classpath配置

  // 3使用java反射机制实体化对象Class

 }

 

 public static void main(String[] args) throws Exception {

  ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(

    "applicationContextxml");

  UserEntity bean = (UserEntity) applicationContextgetBean("user2");

  Systemoutprintln("使用反射获取bean" + beangetUserId() + "---" + beangetUserName());

 }

}

当然这是最简单的手写spring这是原理希望各位有什么好建议提出来,虚心求教。

背景介绍:在一个Bean类中,需要通过反射机制获得private字段属性时,如果用通常获得步骤获得会报如下错误: javalangIllegalAccessException: Class Test can not access a member of class Bean with modifiers "private" at sunreflectReflectionensureMemberAccess(Reflectionjava:57) at javalangreflectFielddoSecurityCheck(Fieldjava:811) at javalangreflectFieldgetFieldAccessor(Fieldjava:758) at javalangreflectFieldget(Fieldjava:228) 解决如下代码实现代码: 1Beanclass内容如下: public class Bean { private String aa; } 2Testclass内容如下: public class Test { public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Bean test = new Bean(); Field f = BeanclassgetDeclaredField("aa"); //其中,最关键的代码是: //fsetAccessible(true); //这行代码把对象data上的name字段设置为public访问属性 fsetAccessible(true); Systemoutprintln(fget(test)); fset(test, "t2"); Systemoutprintln(fget(test)); } } 运行Test类输出如下: null t2

以上就是关于怎样得到bean中的所有字段全部的内容,包括:怎样得到bean中的所有字段、java中私有属性可以通过反射获取,那设置成私有是不是没多大意思、Spring 源码(九)@Autowired注解实现原理(Spring Bean的自动装配)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/10628068.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-10
下一篇 2023-05-10

发表评论

登录后才能评论

评论列表(0条)

保存