高级Spring之Aware 接口

深碍√TFBOYSˉ_ 2024-03-27 10:22 139阅读 0赞

Aware 接口功能阐述:

  1. Aware 接口提供了一种【内置】 的注入手段,例如

    a.BeanNameAware 注入 bean 的名字

b.BeanFactoryAware 注入 BeanFactory 容器

c.ApplicationContextAware 注入 ApplicationContext 容器

d.EmbeddedValueResolverAware 注入 ${} 解析器

功能案例演示:

  1. public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
  2. private static final Logger log = LoggerFactory.getLogger(MyBean.class);
  3. @Override
  4. public void setBeanName(String name) {
  5. log.debug("当前bean " + this + " 名字叫:" + name);
  6. }
  7. @Override
  8. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  9. log.debug("当前bean " + this + " 容器是:" + applicationContext);
  10. }
  11. @Override
  12. public void afterPropertiesSet() throws Exception {
  13. log.debug("当前bean " + this + " 初始化");
  14. }
  15. @Autowired
  16. public void aaa(ApplicationContext applicationContext) {
  17. log.debug("当前bean " + this + " 使用@Autowired 容器是:" + applicationContext);
  18. }
  19. @PostConstruct
  20. public void init() {
  21. log.debug("当前bean " + this + " 使用@PostConstruct 初始化");
  22. }
  23. }

测试:

  1. GenericApplicationContext context = new GenericApplicationContext();
  2. context.registerBean("myBean", MyBean.class);
  3. context.refresh();
  4. context.close();

可能这里有人会有疑问: b、c、d 的功能用 @Autowired 就能实现啊, 为啥还要用 Aware 接口呢

简单地说:
a. @Autowired 的解析需要用到 bean 后处理器, 属于扩展功能
b. 而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别
某些情况下, 扩展功能会失效, 而内置功能不会失效

如下所示:

  1. @Autowired
  2. public void aaa(ApplicationContext applicationContext) {
  3. log.debug("当前bean " + this + " 使用@Autowired 容器是:" + applicationContext);
  4. }
  5. @PostConstruct
  6. public void init() {
  7. log.debug("当前bean " + this + " 使用@PostConstruct 初始化");
  8. }

在这里 ,你会发现用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失败

扩展功能失效场景分析:

  1. @Configuration
  2. public class MyConfig1 {
  3. private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);
  4. @Autowired
  5. public void setApplicationContext(ApplicationContext applicationContext) {
  6. log.debug("注入 ApplicationContext");
  7. }
  8. @PostConstruct
  9. public void init() {
  10. log.debug("初始化");
  11. }
  12. @Bean // beanFactory 后处理器
  13. public BeanFactoryPostProcessor processor1() {
  14. return beanFactory -> {
  15. log.debug("执行 processor1");
  16. };
  17. }
  18. }
  19. context.refresh();

这行代码的执行顺序,到容器里找到所有的.beanFactory 后处理器来执行,添加 bean 后处理器,初始化单例。

Java 配置类不包含 BeanFactoryPostProcessor 的情况

b9252d51c81f4b7493a415b97a1a9f72.png

Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效

6878b348ad834b2996a8388a7594efc6.png

对应代码

  1. @Configuration
  2. public class MyConfig1 {
  3. private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);
  4. @Autowired
  5. public void setApplicationContext(ApplicationContext applicationContext) {
  6. log.debug("注入 ApplicationContext");
  7. }
  8. @PostConstruct
  9. public void init() {
  10. log.debug("初始化");
  11. }
  12. @Bean // ⬅️ 注释或添加 beanFactory 后处理器对应上方两种情况
  13. public BeanFactoryPostProcessor processor1() {
  14. return beanFactory -> {
  15. log.debug("执行 processor1");
  16. };
  17. }
  18. }

注意

解决方法:

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化
  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建

测试:

  1. GenericApplicationContext context = new GenericApplicationContext();
  2. context.registerBean("myConfig2", MyConfig2.class);
  3. context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
  4. context.registerBean(CommonAnnotationBeanPostProcessor.class);
  5. context.registerBean(ConfigurationClassPostProcessor.class);
  6. context.refresh();
  7. context.close();

输出结果:

c01c894832c94597b8a7d3057c4381e8.png

总结:

  • Aware 接口提供了一种【内置】 的注入手段, 可以注入 BeanFactory, ApplicationContext
  • InitializingBean 接口提供了一种【内置】的初始化手段
  • 内置的注入和初始化不受扩展功能的影响, 总会被执行, 因此 Spring 框架内部的类常用它们

发表评论

表情:
评论列表 (有 0 条评论,139人围观)

还没有评论,来说两句吧...

相关阅读

    相关 spring-aware接口

    在springmvc中如果某个bean需要获取spring 的某些容器,可以通过实现其接口的方式,来获得,以此达到在Bean被初始后,能进行CRUD、数据源动态注入到全局应用等