前言
前一阵子,给公司内部做了一个网络管理的系统,对调用交换机获取数据,需要一些提前定制化的检测方法。所以使用了反射,同时也有一个问题困扰了我一天,下面先说说反射。
正文
什么是反射?
在java工程中,对任意一个运行中的对象,可以调用其任意属性及方法,这就是反射。
一般情况下,根据面向对象封装原则,Java实体类的属性都是私有的,我们不能获取类中的属性。但我们可以根据反射,获取私有变量、方法、构造器,甚至是注解。
如何使用?
可以参考这篇文章,特别详细,我就不多说了:
https://zwz99.blog.youkuaiyun.com/article/details/109248009
newInstance的问题?
在使用反射的过程中,遇到了@Autowired失效的问题,想到可能是反射获得的类并没有由spring容器管理,所以造成了null pointer,空指针问题。
Class<?> taskTypeClass = Class.forName("方法的名字");
//出错的地方
Object taskTypeInstance = taskTypeClass.newInstance();
Method taskTypeClassMethod = taskTypeClass.getDeclaredMethod(taskType.getMethodName());
//返回值
Object invoke = taskTypeClassMethod.invoke(taskTypeInstance);
原因就是在这个方法的内部,虽然可以拿到方法,但如果类里面使用了@Autowird,就会得到空了,
因为,class.newInstance() 这个方法,没有和spring关联起来获取Bean
知道问题,那就不用反射的方式获取了,直接用spring的上下文获取就可以了,
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
/**
* 获取bean
*/
public static <T> T popBean(Class<T> clazz) {
//先判断是否为空
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(clazz);
}
}
将class.newInstance()活成上面的方法就可以了!
Spring会检测容器中所有的Bean,当Spring发现某个Bean实现了ApplicationContextAware接口,Spring会在创建Bean后,自动调用setApplicationContextAware()的方法。
当调用他时,会将容器本身当作参数传递给这个方法,赋值给该类的applicationContext实例,所以就可以这个实例来访问其本身了。
白话说,要借助spring实现某个功能,必须让Bean找到Spring才能用。
比如说,反射的 newInstance() 没和 Spring 关联,那就直接用Spring的方式,告诉调用这个功能的人,我处理过了,你可以用了。
这个处理的人就是Spring的接口ApplicationContextAware
总结
反射这个东东,看起来很简单,实际上他掺杂了很多关于java底层的东西,为什么他可以获取所有运行中的对象?嗯,需要深入了解下!
参考文章:https://blog.youkuaiyun.com/hao134838/article/details/103537443
希望对大家有点帮助!我是阿昊,一个独自在大城市努力的年轻人。