3_@Autowired注解失效分析

news/2024/10/7 10:17:51

1. Aware 接口

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

InitializingBean 接口提供了一种[内置]的初始化手段。

Aware的作用就是注入与容器相关的信息,例如:

  1. BeanNameAware: 注入bean的名字
  2. BeanFactoryAware: 注入BeanFactory容器
  3. ApplicationContextAware: 注入ApplicationContext 容器
  4. EmbededValueResolverAware: 注入解析器,解析${}

当某一个Bean实现了Aware的接口,就会在Bean的初始化之前,回调实现的方法setBean():

public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {@Overridepublic void setBeanName(String name) {System.out.println("当前bean"+this+"名字叫:"+name);}@Overridepublic void setApplicationContext(ApplicationContext context) throws BeansException {System.out.println("当前bean" +this+"容器是:"+context);}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("当前bean"+this+"执行初始化操作");}
}

编写主方法运行:

public class A06ApplicationTest {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("myBean",MyBean.class);context.refresh();context.close();}
}
当前beancom.cherry.a06.MyBean@4d50efb8名字叫:myBean
当前beancom.cherry.a06.MyBean@4d50efb8容器是:org.springframework.context.support.GenericApplicationContext@6debcae2, started on Mon Jun 10 08:06:01 CST 2024
当前beancom.cherry.a06.MyBean@4d50efb8执行初始化操作

明明@Autowired和 @PostConstruct注解可以实现注入bean和初始化bean,为什么还需要实现BeanNameAware, ApplicationContextAware, InitializingBean接口来实现注入和初始化的功能?这是因为:

  1. @Autowired等注解解析要用到@Bean后处理器,属于扩展功能
  2. 而Aware接口属于内置的功能,即使不加任何功能,Spring也能识别
  3. 在某些情况下,扩展功能可能会失效,而内置功能并不会失效

2. @Autowired 失效分析

首先编写一个配置类:

@Configuration
public class MyConfig {@Autowiredpublic void setApplicationContext(ApplicationContext context){System.out.println("注入 ApplicationContext");}@PostConstructpublic void init(){System.out.println("初始化");}
}

编写主方法:

public class A06ApplicationTest {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("myConfig",MyConfig.class);context.registerBean(AutowiredAnnotationBeanPostProcessor.class);context.registerBean(CommonAnnotationBeanPostProcessor.class);context.registerBean(ConfigurationClassPostProcessor.class);context.refresh();context.close();}
}

运行:

注入 ApplicationContext
初始化

紧接着在MyConfig中添加一个Bean工厂后处理器:

// 添加一个Bean工厂后处理器@Beanpublic BeanFactoryPostProcessor processor1(){return beanFactory -> {System.out.println("执行 processor1");};}

运行:

08:52:42.280 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer -- @Bean method MyConfig.processor1 is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
执行 processor1

我们发现Bean的注入和初始化功能都失效了。

这里首先了解一下context.refresh()方法的执行流程:

  1. 首先找到容器中所有BeanFactoryPostProcessor来执行
  2. 添加Bean的后处理器
  3. 执行初始化所有单例

首先看一下Bean单例创建流程:

image-20240610125227277

Java配置类包含BeanFactoryPostProcessor的情况,因此在创建BeanFactoryPostProcessor的前提是要把配置类创建好,才能调用Bean工厂方法,才能调用BeanFactoryPostProcessor。配置类本身就是一个单例对象,而此时的BeanFactoryPostProcessor还未创建好,这就导致了@Autowired注解失效。变成了下面的执行流程:

image-20240610125711892

解决方法就是直接在配置类中使用Spring内置的Bean注入和初始化方法:

如下面的配置类:

@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("初始化");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("注入 ApplicationContext");}@Beanpublic BeanFactoryPostProcessor processor2(){return beanFactory -> {System.out.println("执行 processor2");};}
}

修改main方法并运行:

context.registerBean("myConfig2",MyConfig2.class);
注入 ApplicationContext
初始化
13:05:55.772 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer -- @Bean method MyConfig2.processor2 is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
执行 processor2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/42794.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

【内存管理】内存布局

ARM32位系统的内存布局图 32位操作系统的内存布局很经典,很多书籍都是以32位系统为例子去讲解的。32位的系统可访问的地址空间为4GB,用户空间为1GB ~ 3GB,内核空间为3GB ~ 4GB。为什么要划分为用户空间和内核空间呢? 一般处理器会把运行模式分为好几个,比如x86分为rang0 ~…

【esp32 项目】中断读取按键

原理图:图 按键部分图 单片机部分 程序:KEY_USR 引脚配置成上拉输入 在Arduino中,配置一个IO为上拉输入可以使用pinMode()函数和digitalWrite()函数。pinMode()函数用于设置引脚模式,而digitalWrite()函数用于设置上拉电阻。 以下是一个示例代码,展示如何将Arduino的数字引…

【操作系统】页表映射

页表的一些术语 现在Linux内核中支持四级页表的映射,我们先看下内核中关于页表的一些术语:全局目录项,PGD(Page Global Directory)上级目录项,PUD(Page Upper Directory)中间目录项,PMD(Page Middle Directory)页表项,(Page Table)大家在看内核代码时会经常看的以…

算法金 | AI 基石,无处不在的朴素贝叶斯算法

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」历史上,许多杰出人才在他们有生之年默默无闻, 却在逝世后被人们广泛追忆和崇拜。 18世纪的数学家托马斯贝叶斯(Thomas Bayes)便是这样一位人物贝叶斯的研究,初看似…

OO第五、六次大作业总结

一、前言在经过了第一阶段的迭代大作业之后,我们迎来了新的迭代大作业-智能电器模拟系统。 在这个阶段的大作业中,我们需要编写模拟家用电器与电路的程序。 二、设计与分析在经过了第一次迭代大作业的折磨之后,我总结之前出现的问题,在之前的大作业中,我在类的设计方面做的…

【转载】GDB高级技巧:边Debug边修复BUG,无需修改代码,无需重新编译

调试是每个程序员都逃不过的宿命! 程序调试是一件非常考验耐心的事情,因为调试过程中经常会需要反复的修改源码,重新编译、重新部署、重新运行,这个过程通常是非常枯燥和繁琐的。尤其对于大型项目,光是编译可能需要几十分钟,甚至几个小时,部署过程则可能更为复杂漫长! …

【转载】C 语言有什么奇技淫巧

快速范围判断 经常要批量判断某些值在不在范围内,如果 int 检测是 [0, N) 的话: if (x >= 0 && x < N) ...众所周知,现代 CPU 优化,减分支是重要手段,上述两次判断可以简写为: if (((unsigned int)x) < N) ...减少判断次数。如果 int 检测范围是 [minx,…

出现java.lang.NoSuchMethodError: xxx.xxx.xxx.xxxDto.getxxx()Ljava/lang/String

参考博客:https://blog.csdn.net/weixin_43530696/article/details/115732807 修改字段后JPA自动生成的代码未及时更新。删除JPA相关jar包后,重启项目。 直接rebuild项目 重启 ,如果没有用的话,先invalid Chches清缓存之后,再重启动项目一般即可解决您的资助是我最大的动力…