利用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的自动装配)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)