前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >慎用ApplicationContextAware的实现类来操作Spring容器的bean

慎用ApplicationContextAware的实现类来操作Spring容器的bean

作者头像
IT大咖说
发布2022-08-26 14:17:47
3800
发布2022-08-26 14:17:47
举报
文章被收录于专栏:IT大咖说IT大咖说

禁止在项目中在Spring容器管理类的静态代码块里通过调用ApplicationContextAware的实现类来操作Spring容器的bean!!!

反例如下:

代码语言:javascript
复制
 @Service public class TestBeanB {     private static TestBeanC testBeanC;      static {         testBeanC = BeanContext.getBean(TestBeanC.class);     } }

ServiceA也是Spring容器管理的类

代码语言:javascript
复制
 @Service public class TestBeanC {     //  }

其中,BeanContext是ApplicationContextAware的实现类

代码语言:javascript
复制
 @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实例化。

  • 在Spring中,当主函数启动的时候会对@ComponentScan注解中指定的路径进行扫描,如果不指定value,则会默认扫描当前类所在的包及其子包下所有带有注解的类(比如,@Controller、@Service、@Component、@Configuration等)
  • 将其扫描进Spring容器,并存储每个bean的信息为BeanDefinition,并且里面维护一个集合list,负责存每个扫描进容器的beanNames,当实例化的就从这个list获取beanName
  • 通过反射实例化和初始化bean。

问题就出来第3步,当我们TestServiceImpl在list顺序低于BeanContext时,就会出现空指针异常问题。

比如

代码语言:javascript
复制
List<String> beanNames = {"testServiceImpl", "beanContext"};

那么这个顺序是怎么指定的呢,其实,这跟Spring默认扫描的资源路径有关。其扫描指定的顺序是先按包名排序,同包下面的按类名排序。

然后根据这些类的注解,来将其放入到beanNames里。这里面TestBeanA是以@Configuration+@Bean注入的,所以顺序是在最后。

因此,会出现以下情况,当初始化TestBeanB时,会先在没有父类的条件下,会首先初始化其静态变量和静态代码块,而此时beanContext尚未初始化,因此BeanContext里的applicationContext为null,因为setApplicationContext只有其在初始化之后才会执行,所以当调用getBean的时候会出现空指针异常。

正例:

使用Spring注入的方式注入其它实体类。

代码语言:javascript
复制
 @Service public class TestServiceImpl {     @Autowired     private ServiceA serviceA; }

ApplicationContextAware的应用场景

当你想定义一个类,比如工具类,它不交给Spring来管理,而你又想去获取Spring容器管理的类时候,此时ApplicationContextAware就能派上用场了。

比如,

代码语言:javascript
复制
 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大咖说的热心支持!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT大咖说 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档