简介
- 参考: https://javadoop.com/post/spring-ioc
- Spring扩展点参考: https://mp.weixin.qq.com/s/O0W6vCuqQfeAH0UB7elpeA
类关系
类关系图 ^1
- ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean。最顶层 BeanFactory 接口的方法都是获取单个 Bean 的
- ApplicationContext 继承了 HierarchicalBeanFactory, Hierarchical 单词本身(分层的)已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系
- AutowireCapableBeanFactory 这个名字中的 Autowire,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,但是使用组合可以获取它,从 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 可说明
- ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有
- AnnotationConfigApplicationContext
- 实现接口: ApplicationContext - ListableBeanFactory - BeanFactory
- 继承自: DefaultListableBeanFactory
- AnnotationConfigRegistry
- BeanDefinitionRegistry
- DefaultListableBeanFactory
- 实现接口: BeanFactory、BeanDefinitionRegistry
- 子类: AnnotationConfigApplicationContext
- BeanDefinition 描述了一个Bean实例的属性值,构造函数参数值
基于ClassPathXmlApplicationContext执行流程
测试入口代码
1 | public class AppXml { |
AnnotationConfigApplicationContext创建
1 | public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { |
refresh方法概览
1 | // AbstractApplicationContext.java |
创建Bean容器前的准备工作
prepareRefresh创建Bean容器前的准备工作
1 | protected void prepareRefresh() { |
创建Bean容器,加载并注册Bean
- obtainFreshBeanFactory 创建 Bean 容器,加载并注册 Bean
- customizeBeanFactory 配置是否允许 BeanDefinition 覆盖、循环引用
- loadBeanDefinitions 加载并注册 Bean
- registerBeanDefinition 注册Bean
obtainFreshBeanFactory
- 这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。当然,这步结束后,Bean 并没有完成初始化,即 Bean 实例并未在这一步生成
- AbstractApplicationContext.java
1 | protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { |
- AbstractRefreshableApplicationContext.java
1 |
|
customizeBeanFactory配置是否允许BeanDefinition覆盖、循环引用
- BeanDefinition 的覆盖问题
- 就是在配置文件中定义 bean 时使用了相同的 id 或 name,默认情况下,allowBeanDefinitionOverriding 属性为 null,如果在同一配置文件中重复了,会抛错,但是如果不是同一配置文件中,会发生覆盖
- 参考:解决spring中不同配置文件中存在name或者id相同的bean可能引起的问题
- BeanDefinition 的循环引用
- 如:A 依赖 B,而 B 依赖 A。或 A 依赖 B,B 依赖 C,而 C 依赖 A
- 默认情况下,Spring 允许循环依赖,当然如果你在 A 的构造方法中依赖 B,在 B 的构造方法中依赖 A 是不行的
1 | protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { |
loadBeanDefinitions加载并注册Bean
- AbstractXmlApplicationContext.java
1 | // 这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中。读取配置的操作在 XmlBeanDefinitionReader 中,其负责加载配置、解析 |
解析Resource
- XmlBeanDefinitionReader.java 上面转换后的 Resource 进行循环处理,单个的处理如下
1 |
|
- DefaultBeanDefinitionDocumentReader.java
1 |
|
- BeanDefinitionParserDelegate.java
1 | public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { |
registerBeanDefinition注册Bean
- BeanDefinitionReaderUtils.java 上文 BeanDefinitionReaderUtils.registerBeanDefinition 进行调用的
1 | public static void registerBeanDefinition( |
- DefaultListableBeanFactory.java 注册Bean
1 |
|
Bean容器实例化完成后
- prepareBeanFactory 准备 Bean 容器
- finishBeanFactoryInitialization 初始化所有的 singleton beans
- preInstantiateSingletons 开始初始化
- getBean 获取或创建Bean
- createBean 创建Bean
- getBean 获取或创建Bean
- preInstantiateSingletons 开始初始化
prepareBeanFactory准备Bean容器
1 | protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { |
finishBeanFactoryInitialization初始化所有的singleton-beans
- 到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment、systemProperties 等
- AbstractApplicationContext.java
1 | protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { |
preInstantiateSingletons开始初始化
- DefaultListableBeanFactory.java
1 |
|
getBean获取或创建Bean
- AbstractBeanFactory.java
1 |
|
createBean创建Bean
- AbstractAutowireCapableBeanFactory.java 在Bean属性赋值时,可自动对 @Autowired 注解的属性注入属性值
1 |
|
createBeanInstance创建Bean实例
- AbstractAutowireCapableBeanFactory.java
1 | protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { |
- SimpleInstantiationStrategy.java
1 |
|
populateBean注入Bean属性
- AbstractAutowireCapableBeanFactory.java
1 | protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { |
initializeBean处理回调
- AbstractAutowireCapableBeanFactory.java
1 | protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { |
基于AnnotationConfigApplicationContext执行流程
1 | // 测试入口代码 |
说明
id 和 name
- 每个 Bean 在 Spring 容器中都有一个唯一的名字(beanName)和 0 个或多个别名(aliases)。获取Bean
beanFactory.getBean("beanName or alias");
1 | <!-- 配置的结果就是:beanName 为 messageService,别名有 3 个,分别为 m1、m2、m3 --> |
BeanDefinition 接口定义说明
- BeanFactory 是 Bean 容器,那么 Bean 又是什么呢?
- 这里的 BeanDefinition 就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中
- 所以,如果有人问你 Bean 是什么的时候,你要知道 Bean 在代码层面上可以简单认为是 BeanDefinition 的实例
- BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等
- BeanDefinition
1 | public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { |
BeanFactoryPostProcessor和BeanPostProcessor
- BeanFactoryPostProcessor
- 在spring的bean定义文件加载之后,Bean创建之前,添加处理逻辑,如修改bean的定义属性
- 也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉
- 可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序
- 在spring的bean定义文件加载之后,Bean创建之前,添加处理逻辑,如修改bean的定义属性
- BeanPostProcessor
- 在spring容器实例化bean之后,在执行bean的初始化方法前后,添加处理逻辑
工厂模式生成 Bean
- 请读者注意
factory-bean
和FactoryBean
的区别。这节说的是前者,是说静态工厂或实例工厂,而后者是 Spring 中的特殊接口,代表一类特殊的 Bean - 设计模式里,工厂方法模式分静态工厂和实例工厂
- 静态工厂
1 | <bean id="clientService" |
1 | public class ClientService { |
- 实例工厂
1 | <bean id="serviceLocator" class="examples.DefaultServiceLocator"> |
1 | public class DefaultServiceLocator { |
FactoryBean
- FactoryBean参考 spring.md#使用Spring提供的FactoryBean(工厂Bean))
ConversionService
- 像前端传过来的字符串、整数要转换为后端的 String、Integer 很容易,但是如果 controller 方法需要的是一个枚举值,或者是 Date 这些非基础类型(含基础类型包装类)值的时候,我们就可以考虑采用 ConversionService 来进行转换
- xml
1 | <bean id="conversionService" |
- java
1 | public class StringToDateConverter implements Converter<String, Date> { |
Bean 继承
1 | <!-- parent bean 设置了 abstract="true" 所以它不会被实例化,child bean 继承了 parent bean 的两个属性,但是对 name 属性进行了覆写 --> |
方法注入
- 一般来说,我们的应用中大多数的 Bean 都是 singleton 的。singleton 依赖 singleton,或者 prototype 依赖 prototype 都很好解决,直接设置属性依赖就可以了
- 但是,如果是 singleton 依赖 prototype 呢?这个时候不能用属性依赖,因为如果用属性依赖的话,我们每次其实拿到的还是第一次初始化时候的 bean
- 一种常用的解决方案就是不要用属性依赖,每次获取依赖的 bean 的时候从 BeanFactory 中取
- 另一种解决方案就是这里要介绍的通过使用 Lookup method
执行顺序
- @PostConstruct
- ApplicationContextAware#setApplicationContext
参考文章