BeanFactory的实现
- 1. 环境准备
- 2. 初始化DefaultListableBeanFactory
- 3. 手动注册BeanDefinition
- 4. 手动添加后置处理器
- 5. 获取被依赖注入的Bean对象
- 6. 让所有的单例bean初始化时加载
- 7. 总结
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
- DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转和依赖注入功能,都是它来实现
- ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)
- FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)
- XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)
- AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)
- AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)
- AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)
- AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是***组合***了 DefaultListableBeanFactory 的功能,并非继承而来。
1. 环境准备
在开始之前,先准备如下代码:
/*** 测试BeanFactory的实现类** @Date 2023/8/20 15:20*/
@Slf4j
public class FactoryImplApplication {public static void main(String[] args) {// TODO}@Configurationstatic class Config{@Beanpublic Component01 bean1() {return new Component01();}@Beanpublic Component02 bean2() {return new Component02();}}static class Component01 {@Resourceprivate Component02 bean02;public Component01() {System.out.println("Component01构造器~~~");}public Component02 getBean02() {return bean02;}
}static class Component02 {public Component02() {System.out.println("Component02构造器~~~");}}
}
BeanDefinition 描述了这个 bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
2. 初始化DefaultListableBeanFactory
// 仅创建BeanFactory,并没有创建ApplicationContext,此时打印容器中的BeanDefinition个数,一个都没有。
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
log.info("仅创建beanFactory时,不会自动创建其他的BeanDefinition,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());
3. 手动注册BeanDefinition
手动创建Config.class的BeanDefinition并注册到BeanFactory中。
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", configBeanDefinition);
log.info("向BeanFactory手动注册一个BeanDefinition,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());
4. 手动添加后置处理器
学过Spring的应该都知道,Config类上@Configuration,并且里面的方法上有@Bean,那么这个方法的返回对象应该也会被注入容器中。但这边为什么没有呢?这是因为@Configuration并没有被解析,它是由BeanFactory后置处理器来处理的(ConfigurationClassPostProcessor
)。主要功能是补充了一些BeanDefinition。
接着,我们给它添加一些常用的后置处理器并调用postProcessBeanFactory()
,重新打印日志。
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
log.info("向BeanFactory添加一些常用的BeanFactory后置处理器后,此时BeanDefinition个数为:{}", beanFactory.getBeanDefinitionCount());
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).forEach((key, value) -> {// 调用BeanFactory后置处理器value.postProcessBeanFactory(beanFactory);
});Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);
此时,BeanFactory中就有我们需要的BeanDefinition了。
注意:这几个后置处理器非常重要!!!下面会用得到!!!
注意:这几个后置处理器非常重要!!!下面会用得到!!!
注意:这几个后置处理器非常重要!!!下面会用得到!!!
BeanFactory后置处理器:补充BeanDefinition
Bean后置处理器:针对Bean的生命周期的各个阶段提供扩展,例如解析@Autowired、@Resource等
5. 获取被依赖注入的Bean对象
有了BeanDefinition之后,就可以获取Bean了。但BeanFactory不会主动创建Bean,调用getBean()
的时候才会被创建。
我们试着获取bean01:
Component01 bean01 = beanFactory.getBean(Component01.class);
System.out.println("从容器中获取的bean01:" + bean01);
System.out.println("被依赖注入的bean02:" + bean01.getBean02());
运行结果:
bean01被成功创建,但是bean02好像并没有被依赖注入???
这是因为创建bean01之后,beanFactory并不会主动依赖注入,还需要添加Bean后置处理器进行处理。由于第4步注册过BeanDefinition了(registerAnnotationConfigProcessors),我们现在只需要将它们添加到beanFactory的beanPostProcessors中就行了。
- internalAutowiredAnnotationProcessor:@Autowired
- internalCommonAnnotationProcessor:@Resource
因此,在geanBean()
之前,执行添加如下代码:
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
重新运行:
bean02被成功注入了。
6. 让所有的单例bean初始化时加载
目前所有的单例bean都是懒加载的,只有在getBean()
时才会创建。但是实际上应该在应用启动的时候就把大部分的bean加载,而不是使用到时才加载的。
只需开启beanFactory的初始化加载就行了。
// 初始化所有的单例Bean
beanFactory.preInstantiateSingletons();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Component01 bean01 = beanFactory.getBean(Component01.class);
System.out.println("从容器中获取的bean01:" + bean01);
System.out.println("被依赖注入的bean02:" + bean01.getBean02());
如何去验证呢?我们在getBean()
之前,先输出了一行分隔符。可以看到构造方法在分割符之前就被调用了。
7. 总结
BeanFactory不会做:
- 不会主动调用BeanFactory后置处理器(对应本文第4点)
- 不会主动添加Bean后置处理器(对应本文第4、5点)
- 不会主动初始化单例(对应本文第6点)
- 不会解析beanFactory,不会解析${}和#{}