海洋网络专业网站建设,单位网络建设的设计方案,上海工信部网站备案,网站空间管理地址BeanFactory的实现 1. 环境准备2. 初始化DefaultListableBeanFactory3. 手动注册BeanDefinition4. 手动添加后置处理器5. 获取被依赖注入的Bean对象6. 让所有的单例bean初始化时加载7. 总结 Spring 的发展历史较为悠久#xff0c;因此很多资料还在讲解它较旧的实现#xff0c… BeanFactory的实现 1. 环境准备2. 初始化DefaultListableBeanFactory3. 手动注册BeanDefinition4. 手动添加后置处理器5. 获取被依赖注入的Bean对象6. 让所有的单例bean初始化时加载7. 总结 Spring 的发展历史较为悠久因此很多资料还在讲解它较旧的实现这里出于怀旧的原因把它们都列出来供大家参考
DefaultListableBeanFactory是 BeanFactory 最重要的实现像控制反转和依赖注入功能都是它来实现ClassPathXmlApplicationContext从类路径查找 XML 配置文件创建容器旧FileSystemXmlApplicationContext从磁盘路径查找 XML 配置文件创建容器旧XmlWebApplicationContext传统 SSM 整合时基于 XML 配置文件的容器旧AnnotationConfigWebApplicationContext传统 SSM 整合时基于 java 配置类的容器旧AnnotationConfigApplicationContextSpring boot 中非 web 环境容器新AnnotationConfigServletWebServerApplicationContextSpring boot 中 servlet web 环境容器新AnnotationConfigReactiveWebServerApplicationContextSpring 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中就行了。 internalAutowiredAnnotationProcessorAutowiredinternalCommonAnnotationProcessorResource 因此在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不会解析${}和#{}