容器与Bean
1. 容器接口
1.1 什么是 BeanFactory
- 它是
ApplicationContext
的父接口 - 它才是 Spring 的核心容器,主要的
ApplicationContext
实现组合了它的功能,也就是说,BeanFactory
是ApplicationContext
中的一个成员变量。
常用的 context.getBean("xxx")
方法,其实是调用了 BeanFactory
的 getBean()
方法。
1.2 BeanFactory 能做什么?
进入 BeanFactory 接口,在 IDEA 中使用快捷键 Ctrl + F12
查看这个接口中所有的方法定义:
可以看到,虽然 BeanFactory
表面上只有 getBean()
方法,但是实际上 Spring 中的控制反转、依赖注入、生命周期中的各个功能都由它的实现类提供。
查看 DefaultListableBeanFactory
的类图,按住 Ctrl + Alt + u
,DefaultListableBeanFactory
实现了 BeanFactory
接口,
它能管理 Spring 容器中的所有 bean。
也包含单例的 bean 对象:
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.forEach((k, v) -> {
logger.info("k: {}, v: {}", k, v);
});
}
}
上面的单例的对象是通过反射拿到的,在类 DefaultSingletonBeanRegistry
里面:
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
1.3 ApplicationContext 的功能
ApplicationContext
除了实现 BeanFactory
外,还继承了:
MessageSource
:处理国际资源ResourcePatternResolver
:通过通配符进行资源匹配EnvironmentCapable
:读取 Spring 环境信息、配置信息ApplicationEventPublisher
:使其具备发布事件的功能
MessageResource 的使用
在 resources
目录下创建资源文件:
内容分别是:
# messages_en.properties
hi=hi
# messages_zh.properties
hi=你好
在main函数中:
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
logger.info(context.getMessage("hi", null, Locale.ENGLISH));
logger.info(context.getMessage("hi", null, Locale.CHINA));
context.close();
}
}
控制台输出
2024-12-28T21:41:43.127+08:00 INFO 29460 --- [ main] com.jie.demo01.Demo01Application : hi
2024-12-28T21:41:43.129+08:00 INFO 29460 --- [ main] com.jie.demo01.Demo01Application : 你好
ResourcePatternResolver 使用
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
Resource[] resources = context.getResources("classpath:application.yml");
logger.info("resources: {}", resources);
context.close();
}
}
使用 classpath*
可以加载 jar 里类路径下的 resource
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
logger.info("resources: {}", resources);
context.close();
}
}
EnvironmentCapable 的使用
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
ConfigurableEnvironment environment = context.getEnvironment();
logger.info(environment.getProperty("java_home"));
logger.info(environment.getProperty("test.user.name"));
context.close();
}
}
输出:
2024-12-28T21:51:59.134+08:00 INFO 3444 --- [ main] com.jie.demo01.Demo01Application : C:\dev\jdk\jdk-1.8
2024-12-28T21:51:59.135+08:00 INFO 3444 --- [ main] com.jie.demo01.Demo01Application : test
其中,“java_home” 是从环境变量中读取,“test.user.name” 是从 application.yml
文件中读取。
ApplicationEventPublisher 使用
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
context.publishEvent(new Event(context));
context.close();
}
static class Event extends ApplicationEvent {
public Event(Object source) {
super(source);
}
}
@Component
static class Listener {
@EventListener
public void on(Event event) {
logger.info("event: {}", event);
}
}
}
输出:
2024-12-28T21:58:31.809+08:00 INFO 16796 --- [ main] com.jie.demo01.Demo01Application : event: com.jie.demo01
就是事件的发布与监听。
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
public static void main(String[] args) throws Exception {
// 定义 bean
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
genericBeanDefinition(Config.class) // Bean 类型
.setScope("singleton") // Bean 范围
.getBeanDefinition();
// 注册 bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
// 执行 BeanFactory 的后处理器
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
logger.info("name:{}", name);
}
}
@Configuration
static class Config {
public Config() {
}
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
@Autowired
private Bean2 bean2;
public Bean1() {
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
public Bean2() {
}
}
}
2. 容器的实现
2.1 BeanFactory 的实现
现有如下类,尝试将 Config 添加到 Bean 工厂中:
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
public static void main(String[] args) throws Exception {
// 定义 bean
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
genericBeanDefinition(Config.class) // Bean 类型
.setScope("singleton") // Bean 范围
.getBeanDefinition();
// 注册 bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
// 执行 BeanFactory 的后处理器
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
logger.info("name:{}", name);
}
}
@Configuration
static class Config {
public Config() {
}
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
@Autowired
private Bean2 bean2;
public Bean1() {
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
public Bean2() {
}
}
}
输出:
22:19:25.854 [main] INFO com.jie.demo01.Demo01Application -- name:config
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalCommonAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.event.internalEventListenerProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.event.internalEventListenerFactory
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:bean1
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:bean2
BeanFactory
的后处理器主要是为了扩展 BeanFactory
的功能的,比如添加对 @Bean
注解的解析。
Bean
的处理器和 BeanFactory
是不一样的:
@SpringBootApplication
public class Demo01Application {
private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);
public static void main(String[] args) throws Exception {
// 定义 bean
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
genericBeanDefinition(Config.class) // Bean 类型
.setScope("singleton") // Bean 范围
.getBeanDefinition();
// 注册 bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
// 执行 BeanFactory 的后处理器
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
logger.info("name:{}", name);
}
// Bean 后处理器 针对 bean 的每个生命周期的各个阶段提供扩展,例如 @Autowried @Resource
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach((
beanPostProcessor -> beanFactory.addBeanPostProcessor(beanPostProcessor)));
logger.info("beanFactory:{}", beanFactory);
// 获取 bean
Bean1 bean1 = beanFactory.getBean(Bean1.class);
logger.info("bean1:{}", bean1);
logger.info("bean2:{}", bean1.getBean2());
}
@Configuration
static class Config {
public Config() {
}
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
@Autowired
private Bean2 bean2;
public Bean1() {
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
public Bean2() {
}
}
}
Bean
的处理器主要是扩展 Bean
生命周期中的一些功能的,比如 @Autowired
@Resource
。
总结
BeanFactory
不会:
- 主动调用 BeanFactory 后置处理器;
- 主动初始化单例对象;
- 主动添加 Bean 后置处理器;
- 解析 ${} 和 #{}
BeanFactory
是一个基础的,很多功能没有加入进来。接下来介绍的 ApplicationContext
就包含了所有的功能。
2.2 ApplicationContext 的实现
以下xml配置方式的了解即可,现在基本不用了。
ClassPathXmlApplicationContext 使用
Bean1.java:
public class Bean1 {
public Bean1() {
}
}
Bean2.java:
public class Bean2 {
private Bean1 bean1;
public Bean2() {
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean1" class="com.jie.demo01.beans.Bean1" />
<bean id="bean2" class="com.jie.demo01.beans.Bean2">
<property name="bean1" ref="bean1" />
</bean>
</beans>
启动类:
@SpringBootApplication
public class Demo01Application {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
System.out.println(context.getBean("bean2"));
context.close();
}
}
原理类似如下:
@SpringBootApplication
public class Demo01Application {
public static void main(String[] args) throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前的");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("读取之后的");
// 读取xml文件的信息,放到beanFactory里面
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions("test.xml");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
通过 XmlBeanDefinitionReader
读取 xml 文件里面的信息,放到 beanFactory
里面。
输出:
读取之前的
读取之后的
bean1
bean2
AnnotationConfigApplicationContext 的使用
这是基于配置类实现 bean
对象的处理的:
定义 config 类:
@Configuration
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
实现:
@SpringBootApplication
public class Demo01Application {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config
bean1
bean2
这种方式会把 config 类也加入到容器中。
AnnotationConfigServletWebApplicationContext 的使用
使用 AnnotationConfigServletWebApplicationContext
必须要实现三个 bean
:
@Configuration
public class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory() {
// 返回服务器的工厂
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
// 控制器
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
// 注册 dispatcherServlet 到 tomcat 服务器
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
其中写了一个测试用的controller。
启动类:
public class Demo01Application {
public static void main(String[] args) throws Exception {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
}
浏览器访问:localhost:8080/hello
这里我们可以看出,内嵌Tomcat是如何工作的。
2.3 常见的 Bean 后处理器
bean 后处理器的作用:为 Bean 生命周期各个阶段提供扩展
AutowireAnnotationBeanPostProcessor 解析
执行依赖注入的源码:
public void processInjection(Object bean) throws BeanCreationException {
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null);
try {
metadata.inject(bean, (String)null, (PropertyValues)null);
} catch (BeanCreationException var5) {
BeanCreationException ex = var5;
throw ex;
} catch (Throwable var6) {
Throwable ex = var6;
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
}
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
if (this.shouldInject(pvs)) {
if (this.isField) {
Field field = (Field)this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, this.getResourceToInject(target, requestingBeanName));
} else {
try {
Method method = (Method)this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, this.getResourceToInject(target, requestingBeanName));
} catch (InvocationTargetException var5) {
InvocationTargetException ex = var5;
throw ex.getTargetException();
}
}
}
}
执行流程分析:
- 首先调用
InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null);
找到加了@Autowired
@Value
注解的方法或者字段 - 然后调用
metadata.inject(bean, (String)null, (PropertyValues)null);
通过反射注入 - 在
inject
方法中,判断需要注入的是方法还是字段,调用反射API
3. Aware 接口
3.1 Aware 接口
Aware
接口用来实现一些和容器相关的信息,比如:
BeanNameAware
注入 Bean 的名字BeanFactoryAware
注入BeanFactory
容器ApplicationContextAware
注入ApplicationContext
容器EmbeddedValueResolverAware
解析${}
@Slf4j
public class MyBean implements BeanNameAware, ApplicationContextAware {
@Override
public void setBeanName(String name) {
log.info("当前bean【{}】的名字是【{}】", this, name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("当前bean【{}】容器是【{}】", this, applicationContext);
}
}
public class Demo03Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myBean", MyBean.class);
context.refresh();
context.close();
}
}
输出:
13:07:46.510 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@782663d3】的名字是【myBean】
13:07:46.518 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@782663d3】容器是【org.springframework.context.support.GenericApplicationContext@22f71333, started on Sun Dec 29 13:07:46 CST 2024】
这些实现的方法会在 AbstractAutowireCapableBeanFactory
下的 invokeAwareMethods
调用:
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
BeanNameAware beanNameAware = (BeanNameAware)bean;
beanNameAware.setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
BeanClassLoaderAware beanClassLoaderAware = (BeanClassLoaderAware)bean;
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
beanClassLoaderAware.setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
BeanFactoryAware beanFactoryAware = (BeanFactoryAware)bean;
beanFactoryAware.setBeanFactory(this);
}
}
}
3.2 InitializingBean
@Slf4j
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String name) {
log.info("当前bean【{}】的名字是【{}】", this, name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("当前bean【{}】容器是【{}】", this, applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("当前bean【{}】初始化完成", this);
}
}
输出:
13:16:54.196 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】的名字是【myBean】
13:16:54.206 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】容器是【org.springframework.context.support.GenericApplicationContext@35f983a6, started on Sun Dec 29 13:16:54 CST 2024】
13:16:54.206 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】初始化完成
该方法会在 Aware
接口之后调用。
这个方法会在 AbstractAutowireCapableBeanFactory
下的 invokeInitMethods
调用:
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
boolean isInitializingBean = bean instanceof InitializingBean;
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
((InitializingBean)bean).afterPropertiesSet(); // 调用方法
}
if (mbd != null && bean.getClass() != NullBean.class) {
String[] initMethodNames = mbd.getInitMethodNames();
if (initMethodNames != null) {
String[] var6 = initMethodNames;
int var7 = initMethodNames.length;
for(int var8 = 0; var8 < var7; ++var8) {
String initMethodName = var6[var8];
if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
this.invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
}
}
}
}
}
BeanFactoryAware
、ApplicationContextAware
和 EmbeddedValueResolverAware
三个接口的功能可以使用 @Autowired
注解实现,InitializingBean
接口的功能也可以使用 @PostConstruct
注解实现,为什么还要使用接口呢?
@Autowired
和 @PostConstruct
注解的解析需要使用 Bean 后置处理器,属于拓展功能,而这些接口属于内置功能,不加任何拓展 Spring 就能识别。在某些情况下,拓展功能会失效,而内容功能不会失效
3.3 @Autowired 失效
如下代码:
@Slf4j
@Configuration
public class MyConfig {
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("注入 ApplicationContext");
}
@PostConstruct
public void init() {
log.info("初始化");
}
@Bean
public BeanFactoryPostProcessor processor1() {
return processor -> log.info("执行 processor1");
}
}
public class Demo03Application {
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();
}
}
输出:
13:29:43.666 [main] INFO com.jie.demo03.beans.MyConfig -- 执行 processor1
可以看见,@Autowired
失效了,但是 processor1()
方法却没有。
为什么?
对于 context.refresh();
方法来说,它主要按照以下顺序干了三件事:
- 执行
BeanFactory
后置处理器; - 添加 Bean 后置处理器;
- 创建和初始化单例对象。
当 Java 配置类中定义了 BeanFactoryPostProcessor
时,如果要创建配置类中的 BeanFactoryPostProcessor
就必须提前创建和初始化 Java 配置类。
在创建配置类时,由于 BeanPostProcessor
还没配置好,这时候就不能解析 @Autowired
注解,导致注解失效。
要解决这个问题也很简单,使用相关接口的功能实现注入和初始化:
@Slf4j
@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {
@Override
public void afterPropertiesSet() throws Exception {
log.info("初始化");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("注入 ApplicationContext");
}
@Bean
public BeanFactoryPostProcessor processor2() {
return processor -> log.info("执行 processor2");
}
}
3.4 总结
Aware
接口提供了一种 内置 的注入手段,可以注入BeanFactory
、ApplicationContext
;InitializingBean
接口提供了一种内置的初始化手段;- 内置的注入和初始化不受拓展功能的影响,总会被执行,因此 Spring 框架内部的类总是使用这些接口。
喜欢的点个关注,博客链接:何事秋风悲画扇,另外有想一起做项目的给个留言。