AbstractApplicationContext.refresh
方法中的finishBeanFactoryInitialization
流程会初始化容器中非延迟的单例Bean。
bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可以总结为以下七个阶段:
- 处理名称,检查缓存
- 处理父子容器
- 处理 dependsOn
- 选择 scope 策略
- 创建 bean
- 类型转换处理
- 销毁 bean
1. 处理名称,检查缓存
这一步会处理别名,将别名解析为实际名称
对 FactoryBean 也会特殊处理,如果以 & 开头表示要获取 FactoryBean 本身,否则表示要获取其产品
这里针对单例对象会检查一级、二级、三级缓存
singletonFactories
三级缓存,存放单例工厂对象earlySingletonObjects
二级缓存,存放单例工厂的产品对象
- 如果发生循环依赖,产品是代理;无循环依赖,产品是原始对象
singletonObjects
一级缓存,存放单例成品对象
2. 处理父子容器
如果当前容器根据名字找不到这个 bean,此时若父容器存在,则执行父容器的 getBean 流程
父子容器的 bean 名称可以重复
思考:如何构建父子容器的情况?怎么区分父子容器
3. 处理 dependsOn
如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean,这一步会提前创建这些 dependsOn 的 bean
所谓非显式依赖,就是指两个 bean 之间不存在直接依赖关系,但需要控制它们的创建先后顺序
4. 选择 scope 策略
对于 singleton scope,首先到单例池去获取 bean,如果有则直接返回,没有再进入创建流程
对于 prototype scope,每次都会进入创建流程
对于自定义 scope,例如 request,首先到 request 域获取 bean,如果有则直接返回,没有再进入创建流程
static class Bean1 {
@PostConstruct
public void init() {
LoggerUtils.get().debug("{} - init", this);
}
@PreDestroy
public void destroy() {
LoggerUtils.get().debug("{} - destroy", this);
}
}
单例 bean 从 refresh 被创建, 到 close 被销毁, BeanFactory 会记录哪些 bean 要调用销毁方法
private static void testSingletonScope() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class);
//为了解析@PostConstruct、@PreDestroy注解
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.refresh(); // getBean
context.close();
}
多例 bean 从首次 getBean 被创建, 到调用 BeanFactory 的 destroyBean 被销毁. 容器启动和关闭不会调用Bean的初始化
private static void testPrototypeScope() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class, bd -> bd.setScope("prototype"));
context.registerBean(CommonAnnotationBeanPostProcessor.class);
LoggerUtils.get().debug("context - refresh");
context.refresh();
//getBean时才调用初始化方法
Bean1 bean = context.getBean(Bean1.class);
//没谁记录该 bean 要调用销毁方法, 需要我们自行调用
context.getDefaultListableBeanFactory().destroyBean(bean);
context.close();
LoggerUtils.get().debug("context - close");
}
request bean 从首次 getBean 被创建, 到 request 结束前被销毁
private static void testRequestScope() {
GenericApplicationContext context = new GenericApplicationContext();
context.getDefaultListableBeanFactory().registerScope("request", new RequestScope());
context.registerBean("bean1", Bean1.class, bd -> bd.setScope("request"));
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.refresh();
for (int i = 0; i < 2; i++) {
new Thread(() -> {
MockHttpServletRequest request = new MockHttpServletRequest();
// 每个 webRequest 对象会记录哪些 bean 要调用销毁方法
ServletWebRequest webRequest = new ServletWebRequest(request);
RequestContextHolder.setRequestAttributes(webRequest);
Bean1 bean = context.getBean(Bean1.class);
LoggerUtils.get().debug("{}", bean);
LoggerUtils.get().debug("{}", request.getAttribute("bean1"));
// request 请求结束前调用这些销毁方法
webRequest.requestCompleted();
}).start();
}
}
5. 创建 bean
虽然有不同的作用域,但是都会走到第5步创建Bean的流程。整体分为4个阶段
- 创建阶段
- 依赖注入阶段
- 初始化阶段
- 注册和销毁Bean阶段
每个阶段都会有BeanPostProcessor对Bean的功能做扩展和增强
5.1 创建 bean 实例
要点 | 总结 |
---|---|
有自定义 TargetSource 的情况 | 由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回 |
Supplier 方式创建 bean 实例 | 为 Spring 5.0 新增功能,方便编程方式创建 bean 实例 |
FactoryMethod 方式 创建 bean 实例 | ① 分成静态工厂与实例工厂; ② 工厂方法若有参数,需要对工厂方法参数进行解析,利用 resolveDependency; ③ 如果有多个工厂方法候选者,还要进一步按权重筛选 |
AutowiredAnnotationBeanPostProcessor | ① 优先选择带 @Autowired 注解的构造; ② 若没有@Autowired 但是有唯一的带参构造,也会选择带参构造 |
mbd.getPreferredConstructors | 选择所有公共构造,这些构造之间按权重筛选 |
采用默认构造 | 如果上面的后处理器和 BeanDefiniation 都没找到构造,采用默认构造,即使是私有的也会暴力反射创建 |
5.2 依赖注入
要点 | 总结 |
---|---|
AutowiredAnnotationBeanPostProcessor | 识别 @Autowired 及 @Value 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
CommonAnnotationBeanPostProcessor | 识别 @Resource 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
resolveDependency | 用来查找要装配的值,可以识别: ① Optional; ② ObjectFactory 及 ObjectProvider; ③ @Lazy 注解; ④ @Value 注解(${ }, #{ }, 类型转换); ⑤ 集合类型(Collection,Map,数组等); ⑥ 泛型和 @Qualifier(用来区分类型歧义); ⑦ primary 及名字匹配(用来区分类型歧义) |
AUTOWIRE_BY_NAME | 根据成员名字找 bean 对象,修改 mbd 的 propertyValues,不会考虑简单类型(String 、Integer等)的成员 |
AUTOWIRE_BY_TYPE | 根据成员类型执行 resolveDependency 找到依赖注入的值,修改 mbd 的 propertyValues |
applyPropertyValues | 根据 mbd 的 propertyValues 进行依赖注入(即xml中 <property name ref|value/> ) |
实验哪种注入优先级高
- 优先级最高的:精确指定注入 bean 的名称
- 优先级次之的:通过 AUTOWIRE_BY_NAME 匹配
- 优先级最低的:@Autowired 匹配
static class Bean1 {
MyInterface bean;
// 优先级最低的:@Autowired 匹配
@Autowired @Qualifier("bean4")
public void setBean3(MyInterface bean) {
System.out.println(bean);
this.bean = bean;
}
}
interface MyInterface {
}
static class Bean2 implements MyInterface {
}
static class Bean3 implements MyInterface {
}
static class Bean4 implements MyInterface {
}
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
context.registerBean("bean1", Bean1.class, bd -> {
// 优先级最高的:精确指定注入 bean 的名称 <property name="bean3" ref="bean2"/>
bd.getPropertyValues().add("bean3", new RuntimeBeanReference("bean2"));
// 优先级次之的:通过 AUTOWIRE_BY_NAME 匹配
((RootBeanDefinition) bd).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
});
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
context.refresh();
}
5.3 初始化
要点 | 总结 |
---|---|
内置 Aware 接口的装配 | 包括 BeanNameAware,BeanFactoryAware 等 |
扩展 Aware 接口的装配 | 由 ApplicationContextAwareProcessor 解析,执行时机在 postProcessBeforeInitialization |
@PostConstruct | 由 CommonAnnotationBeanPostProcessor 解析,执行时机在 postProcessBeforeInitialization |
InitializingBean | 通过接口回调执行初始化 |
initMethod | 根据 BeanDefinition 得到的初始化方法执行初始化,即 <bean init-method> 或 @Bean(initMethod) |
创建 aop 代理 | 由 AnnotationAwareAspectJAutoProxyCreator 创建,执行时机在 postProcessAfterInitialization |
实验初始化方法的优先级:输出 4 2 1 3
- 先执行Aware接口
- 执行注解初始化:@PostConstruct
- 执行接口初始化:afterPropertiesSet接口回调
- 执行自定义初始化:配置的initMethod
public class TestInitialization {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(CommonAnnotationBeanPostProcessor.class);
// 相当于配置了XML标签 <bean init-method="initMethod">
context.registerBean("bean1", Bean1.class, bd -> bd.setInitMethodName("initMethod"));
context.refresh();
}
static class Bean1 implements InitializingBean, BeanFactoryAware {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(1);
}
@PostConstruct
public void init() {
System.out.println(2);
}
public void initMethod() {
System.out.println(3);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(4);
}
}
}
5.4 注册可销毁 bean
在这一步判断并登记可销毁 bean
- 判断依据
- 如果实现了 DisposableBean 或 AutoCloseable 接口,则为可销毁 bean
- 如果自定义了 destroyMethod,则为可销毁 bean
- 如果采用 @Bean 没有指定 destroyMethod,则采用自动推断方式获取销毁方法名(提供了 close,shutdown方法)
- 如果有 @PreDestroy 标注的方法
- 存储位置
- singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中
- 自定义 scope( request、session、application) 的可销毁 bean 会存储于对应的域对象当中
- prototype scope 不会存储,需要自己找到此对象销毁
- 存储时都会封装为
DisposableBeanAdapter
类型对销毁方法的调用进行适配 (适配器模式
)
6. 类型转换处理
如果 getBean 的 requiredType 参数与实际得到的对象类型不同,会尝试进行类型转换
在这个阶段Bean已经被创建并返回
7. 销毁 bean
- 销毁时机
- singleton bean 的销毁在 ApplicationContext.close 时,此时会找到所有 DisposableBean 的名字,逐一销毁
- 自定义 scope bean 的销毁在作用域对象生命周期结束时
- prototype bean 的销毁可以通过自己手动调用 AutowireCapableBeanFactory.destroyBean 方法执行销毁
- 同一 bean 中不同形式销毁方法的调用次序
- 优先后处理器销毁,即 @PreDestroy
- 其次 DisposableBean 接口销毁
- 最后 destroyMethod 销毁(包括自定义名称,推断名称,AutoCloseable 接口 多选一)