禁止在项目中在Spring容器管理类的静态代码块里通过调用ApplicationContextAware的实现类来操作Spring容器的bean!!!
反例如下:
@Service public class TestBeanB { private static TestBeanC testBeanC; static { testBeanC = BeanContext.getBean(TestBeanC.class); } }
ServiceA也是Spring容器管理的类
@Service public class TestBeanC { // }
其中,BeanContext是ApplicationContextAware的实现类
@Component public class BeanContext implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * Spring容器上下文赋值给BeanContext类的变量applicationContext,后续通过getBean的方式获取Spring容器的对象 */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { BeanContext.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 获取方式1:通过名称来获取实例对象,如果初始化实例的时候没有指定对象名称,默认为类名的首字母小写 */ public static T getBean(String name) throws BeansException { return (T) applicationContext.getBean(name); } /** * 获取方式2:通过指定的类.class来获取实例对象 */ public static <T> T getBean(Class<T> clz) throws BeansException { return (T) applicationContext.getBean(clz); } }
原因:可能会出现NullPointerException,当BeanContext实例化顺序晚于TestServiceImpl实例化。
问题就出来第3步,当我们TestServiceImpl在list顺序低于BeanContext时,就会出现空指针异常问题。
比如
List<String> beanNames = {"testServiceImpl", "beanContext"};
那么这个顺序是怎么指定的呢,其实,这跟Spring默认扫描的资源路径有关。其扫描指定的顺序是先按包名排序,同包下面的按类名排序。
然后根据这些类的注解,来将其放入到beanNames里。这里面TestBeanA是以@Configuration+@Bean注入的,所以顺序是在最后。
因此,会出现以下情况,当初始化TestBeanB时,会先在没有父类的条件下,会首先初始化其静态变量和静态代码块,而此时beanContext尚未初始化,因此BeanContext里的applicationContext为null,因为setApplicationContext只有其在初始化之后才会执行,所以当调用getBean的时候会出现空指针异常。
正例:
使用Spring注入的方式注入其它实体类。
@Service public class TestServiceImpl { @Autowired private ServiceA serviceA; }
ApplicationContextAware的应用场景
当你想定义一个类,比如工具类,它不交给Spring来管理,而你又想去获取Spring容器管理的类时候,此时ApplicationContextAware就能派上用场了。
比如,
public class Utils { private static TestBeanA testBeanA; private static TestBeanB testBeanB; private static TestBeanC testBeanC; static { testBeanA = BeanContext.getBean(TestBeanA.class); testBeanB = BeanContext.getBean(TestBeanB.class); testBeanC = BeanContext.getBean(TestBeanC.class); } public static Object doSomething(){ //testBeanA.do //testBeanB.do //testBeanC.do } }
来源:
https://www.toutiao.com/article/6982729116798108163/?log_from=90ce6327b8e0f_1659585303309
“IT大咖说”欢迎广大技术人员投稿,投稿邮箱:aliang@itdks.com
来都来了,走啥走,留个言呗~
IT大咖说 | 关于版权
由“IT大咖说(ID:itdakashuo)”原创的文章,转载时请注明作者、出处及微信公众号。投稿、约稿、转载请加微信:ITDKS10(备注:投稿),茉莉小姐姐会及时与您联系!
感谢您对IT大咖说的热心支持!