Spring 是 JavaWeb 技术中的核心框架,Spring 所延伸出的家族是 Java 帝国的中流砥柱,与 Java 的发展紧密相连。Spring 容器于对象的管理,即 Bean 的管理是 Spring 的极其重要的基础设施。本文将以理论、图解与代码结合的方式,循序渐进,试图讲清 Spring 对象管理的设计思路与 Java 帝国中原子公民"波澜壮阔"的一生。
在阅读本文之前,请确保您有 JavaEE 基础,对 Spring 的应用有部分了解。本文中的所有代码演示都基于 JDK 1.8 Spring 5.3.23 SpringBoot 2.6.13。
为了优化排版,在解析源码时,spring 代表 org.springframework。
例如:spring.beans.factory 代表 org.springframework.beans.factory。
容器
Spring 容器负责创建、管理和销毁应用中的对象,开发者只需要配置对象的依赖关系和相关属性,不需要手动创建对象或处理依赖。
从 Spring 开发者的角度来看:
作为容器,Spring 需要持久 管理使用者所依赖的对象,这些对象称作Bean。尤其是在 MVC 架构下,Mapper Service Controller都只需要单例存在,不需要每次创建新的对象。
从 Spring 使用者的角度来看:
作为容器,Spring 需要通过 Bean 的名字来获取 Bean 的Object 对象,以此作为容器提供服务。
综上所述,HashMap 是持久管理、通过名字获取对象的不二选择。
实际上,Spring 也是这么做的。
在 [spring].beans.factory.support.DefaultSingletonBeanRegistry 中,singletonObjects 即为上述所提到的 HashMap。
java
public class DefaultSingletonBeanRegistry
extends SimpleAliasRegistry
implements SingletonBeanRegistry {
// ....
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// ....
}
作为简单的容器,我们可以通过 HashMap 长期引用 Object,以此来保证其不会被 GC 回收。
通过构建 String -> Object 映射,可以快速查询目标对象。
自此,Spring 的容器已经有了雏形。
Bean 的产生
从 Spring 开发者的角度来看。
Spring 需要管理 Bean 从创建到死亡的全过程,Bean 的死亡只需要删除 HashMap 中的映射关系,该 Bean 随后就会被 GC 标记回收。为了方便称呼,下文将记录 String -> Object 映射关系的 HashMap 叫做单例池(singletonObjects)。
Bean 的创建
在常规开发中,通常使用 new 关键字创建对象。
例如:
java
new String(); // 调用无参构造方法创建对象
new String("ErickRen"); // 调用有参构造方法创建对象
在 Spring 进行对象管理时,很明显无法使用 new 关键字进行对象创建。
Spring 采用反射进行对象创建,有关反射的概念、使用和原理,本文暂且按下不表。
通过反射调用构造方法,创建 Bean 的实例对象 (instance),将实例对象与 Bean 名字建立映射,就完成了容器创建对象的流程。
以上,可以得到流程图:

Bean 注册信息
在使用者视角中,Spring 有两种方法定义 Bean:从 XML 文件定义 ,使用注解定义。
两种定义方法效果一致,由此可以猜测:两者的底层逻辑可能有相通指出之处,XML 和 注解 只是上层定义的一个包装。
事实也确实如此,Spring 通过引入BeanDefinition来包装 Bean 的定义信息。并将 BeanDefinition 利用 HashMap 储存,即[spring].beans.factory.support.DefaultListableBeanFactory中的beanDefinitionMap,在实例化时统一读取,统一创建。
从 XML 和 注解 扫描而来的定义信息统一封装进 BeanDefinition 中,再由容器统一读取,统一创建 Bean。
BeanDefinition 中几乎包含了所有 Bean 的信息,例如:
- Bean 的类型
- 是否为单例
- 是否懒加载
- 属性填充信息
- 依赖其他 Bean 信息
- ....
BeanDefinition 是 Bean 创建的最高准则,是整个 Spring 管理对象最重要的参考。
XML文件定义
在 XML 文件中构造的 Bean,一般由 XML 解析器 ,通过将 XML 文件重新反序列化为树状文件,以此来读取并解析 Bean。
本文在此对 XML 的反序列化不作详细解释。
注解定义
一般通过扫描类注解来检查某个类是否有某个注解。
注解扫描有两种常用方法:反射 与 ASM。
反射
现有类 Demo.java:
java
package me.erickren.source.demos;
import org.springframework.stereotype.Component;
/**
* DateTime: 2024/03/11 - 21:06
* Author: ErickRen
*/
@Component
public class Demo {
}
通过反射方式可以获取某个类上的注解:
java
public static void main(String[] args){
Class<Demo> klass = Demo.class;
Component annotation = klass.getAnnotation(Component.class);
System.out.println(annotation);
}
得到结果:
text
@org.springframework.stereotype.Component(value=)
递归获取注解问题
在使用 Spring 时,有许多子注解,例如:@Controller @Service。
本质上 @Controller 是 @Component 的一个子注解。
java
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
如果使用上文提到的klass.getAnnotation(Controller.class)获取注解,无法读取到父注解 @Component。
在框架开发中,针对 Controller 等子注解判断再复用 Component 注册流程是可行的。
Spring 采取的方案是再次扫描子注解,检查其中是否有某个父注解。
以下是一个示例:
java
public static void main(String[] args) {
// 获取 Class
Class<Demo> klass = Demo.class;
// 获取对象上的注解
Annotation[] annotations = klass.getAnnotations();
// 获取父注解
for (Annotation annotation : annotations) {
Annotation[] an = annotation.annotationType().getAnnotations();
for (Annotation target : an) {
System.out.println(target);
}
}
}
从以上来看,反射方法确实优雅而易于实现。但反射存在问题,当 Bean 设置为懒加载时,需要将 Bean 加载到内存中才能获取注解。该情况与懒加载的语义冲突,所以通过反射处理不是最优方案。
ASM
ASM 是一种分析和操作 Java 字节码(.class文件)的框架。它可以直接以二进制的形式用于修改现有类或动态生成类。相比反射,ASM 获取注解更加高效,因为其直接操作字节码,不需要将类加载到内存中。
ASM 名字的来源于 C 语言中 __asm__ 关键字,后者可以在 C 语言中内联汇编程序。
本文在此不详细说明 ASM 的具体实现。
现在,Bean 的创建流程图为:

自动生成 Bean 的名称
在类上标注 @Component,Spring 将会管理该 Bean。
前文提到,Spring 维护了 String -> Object 的映射关系,所以任何单例 Bean 都需要有一个名字。在一般开发中,使用者并不关心 Bean 的名字,这部分工作也可以由 Spring 进行。
自动生成 Bean 名字由[spring].beans.factory.support.BeanNameGenerator定义,在一般注解开发中,通常由其实现类[spring].context.annotation.AnnotationBeanNameGenerator实现。在其buildDefaultBeanName方法中,需要传入一个 BeanDefinition,并调用了Introspector.decapitalize()最终生成默认 Bean 名字。
java
protected String buildDefaultBeanName(BeanDefinition definition) {
// 获取 Bean 类全限定名
//例如:me.erickren.source.UserService
String beanClassName = definition.getBeanClassName();
// 断言是否为 null
Assert.state(beanClassName != null, "No bean class name set");
// 获取类名称 UserService
String shortClassName = ClassUtils.getShortName(beanClassName);
// 生成默认 Bean 名称
return Introspector.decapitalize(shortClassName);
}
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
// 如果第1个和第2个字符都是大写,则直接返回
// 这是为了处理缩写,例如 URL,不应该改写为 uRL,不符合直觉。
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
// 如果只有第1个字符为大写,则将第1个字符转为小写
// 例如 UserService -> userService
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
BeanDefinition 的统一注册与管理
BeanDefinition 全都由 BeanDefinitionRegistry 接口注册。该接口主要有两个实现包含 beanDefinitionMap,一个是 [spring].beans.factory.support.SimpleBeanDefinitionRegistry,另一个是同包下的DefaultListableBeanFactory。在一般开发中,都会使用 DefaultListableBeanFactory 作为 BeanRegistry。
BeanRegistry 中提供了一些常规方法注册、获取和使用 BeanDefinition,这赋予开发者极大的灵活性。
甚至在使用中,还可以通过一些非常手段通过容器获取 BeanRegistry 直接注册 Bean。
请注意,以下代码仅供博客演示,请勿在生产环境使用该方式。
java
package me.erickren.source;
import me.erickren.source.service.UserService;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Hello {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Hello.class, args);
ConfigurableListableBeanFactory beanFactory = run.getBeanFactory();
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(UserService.class);
factory.registerBeanDefinition("myBean", rootBeanDefinition);
Object myBean = run.getBean("myBean");
System.out.println(myBean);
}
}
text
me.erickren.source.service.UserService@5c089b2f
Bean 的生命流程图:

属性填充
对于 Spring 而言,创建对象只是基本任务,Spring 为人称道更多的是因为其会自动地为对象填充属性。
这里的属性可能是常规属性,也可能是另一个 Bean。
填充属性
上文提到使用反射创建对象,可以方便地为 Bean 填充基础数据。
在填充属性时,属性大多是以<String, Object>为一对存在,通过将封装PropertyValue为 PropertyValues,在 BeanDefinition 中携带该信息,在创建 Bean 时利用反射 进行填充。在通常情况下,Spring 会使用 PropertyValues 的实现类MutablePropertyValues。它使用一个 List 保存 PropertyValue。
java
public abstract class AbstractBeanDefinition
extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// ...
@Nullable
private MutablePropertyValues propertyValues;
// ...
}
在创建 Bean 的核心方法AbstractAutowireCapableBeanFactory#doCreateBean中,调用this.populateBean()方法,为 Bean 填充信息。populateBean方法中,通过获取 BeanDefinition 携带的 PropertyValues 为 Bean 填充属性。
java
// [spring].beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
{
// ...
PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
// ...
}
填充 Bean
在上文提到,Bean 的普通属性会封装一份 PropertyValues 由 BeanDefinition 携带,而 Bean 相关的依赖也由一个数据结构定义,同样由 BeanDefinition 持有,即:BeanReference。
BeanReference 有三个实现类,其中RuntimeBeanReference最常使用。
站在开发者的角度来看,欲注入的 Bean 实际上是特殊的属性,所以可以通过 PropertyValue 封装 BeanReference。这样就实现了属性注入信息的统一封装。
在 BeanDefinitionValueResolver#resolveValueIfNecessary中,通过instanceof关键字,将 PropertyValue 封装的 BeanReference 读取、强制转换并执行注入。
java
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// 检查 value 是否为 BeanReference
if (value instanceof RuntimeBeanReference) {
// 是则强制转换
RuntimeBeanReference ref = (RuntimeBeanReference)value;
return this.resolveReference(argName, ref);
} else if (value instanceof RuntimeBeanNameReference) {
// RuntimeBeanNameReference 是 BeanReference 的另一个实现类
// 前者只通过 Bean 名称进行引用,而后者包含了前者,并封装了 Bean 类型
String refName = ((RuntimeBeanNameReference)value).getBeanName();
refName = String.valueOf(this.doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);
} else {
return refName;
}
}
// ...
}
到现在,Bean 的生命流程如下:

AOP 增强
AOP(Aspect Oriented Programming) 全称面向切面编程,通过预编译和运行期间动态代理来实现程序功能的一种技术。
AOP 是 Spring 的另一个核心基础设施,一般使用动态代理技术实现。
在 Spring 运行期间通过动态代理技术动态生成对象,代理对象方法执行时进行增强功能的介入。
请注意,本文不会介绍 AOP 在 Spring 中的应用,只会从表面原理对其进行简单解析。
AOP 的术语解释
为了方便解释,给定一个场景。
现给定一个类 UserService.java
java
package me.erickren.source.service;
import org.springframework.stereotype.Service;
/**
* DateTime: 2024/03/13 - 20:03
* Author: ErickRen
*/
@Service
public class UserService {
public void login() {
System.out.println("用户正在登录。。。");
}
public void logout() {
System.out.println("用户退出。。。");
}
}
其中定义方法login和logout,都只进行简单打印。
再给定一类 Aspect.java
java
package me.erickren.source.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* DateTime: 2024/03/13 - 20:06
* Author: ErickRen
*/
@Aspect
@Component
@Slf4j
public class Aspect {
@Before("execution(* me.erickren.source.service.UserService.*.*(..))")
public void before(JoinPoint joinPoint) {
log.info("前置通知执行");
}
@After("execution(* me.erickren.source.service.UserService.*.*(..))")
public void after(JoinPoint joinPoint) {
System.out.println("后置通知执行");
}
}
此时,UserService 的两个方法均已加强。
现解释术语:
- Join Point(连接点):具体被拦截的对象,Spring 只支持方法拦截,所以被拦截的是方法。即上述场景的
UserService#login和UserService#logout。 - Point Cut(切点):当需要批量连接点时,通常使用切点表达式 来匹配多个连接点,多个连接点组成的集合即称为切点 。即上述场景的
execution(* me.erickren.source.service.UserService.*.*(..))表达式所匹配到的(UserService#login,UserService#logout)集合。 - Advice(通知/增强):AOP 增强的具体实现,分为
前置、后置、异常、环绕和最终五种,即上述场景的Aspect#before和Aspect#after。 - Aspect(切面):由 切点 和 通知 组成的对象集合。上述场景的
UserService和Aspect都是切面。 - Target(目标):承载连接点的对象,即上述场景的
UserService类。 - Weaving(织入):是一个操作,具体指将切面应用到目标生成代理类的过程。这个过程通常发生在编译期(静态代理),运行期(动态代理)。
- Proxy(代理):通过各种手段生成的代理对象 ,其本质上是一个对象,不同于
UserService和Aspect,是自动生成的对象。这个对象有着和UserService类似的方法,但其中的方法都经过增强。
实现动态代理的两种技术
本文主要讲解 Bean 生命全流程,所以动态代理的实现技术暂且提起顶层设计。
JDK 动态代理
在 Spring 中,对于实现接口的类,会使用java.lang.reflect.Proxy类来创建代理对象。代理对象会在运行时实现代理接口,覆盖其中的方法,在方法调用前后执行切面逻辑。
CGLIB 动态代理
对于未实现接口的类,会使用 CGLIB 库生成代理对象。CGLIB 通过字节码技术创建目标类的子类,在子类中重写目标方法并在方法前后插入切面逻辑。
对于 Spring 来说,动态代理技术最后生成的代理对象才是运行需要的对象。即容器中最终存储的是代理对象。
此时,Bean 的生命流程为:

上文中的 AOP 为什么会在属性填充之前,会在下文中有详细解释。
上下文与 Bean 工厂
从上文来看,容器的基本功能已经实现,但这个容器包含了 BeanDefinition 的创建,Bean 的扫描,还需要管理各种对 Bean 的加强类等,未来还可能会添加的容器相关功能,整个项目的结构已经变得非常复杂,难以维护,所以 Spring 将容器与 Bean 的创建剥离,维护了一套层级结构,即ApplicationContext与BeanFactory。
在本质上,ApplicationContext 是 BeanFactory 的顶层实现:

BeanFactory 主要负责 Bean 的创建,而 ApplicationContext 集成了更多功能,例如:容器生命周期管理,Bean 的扫描,与其他框架的融合。
该举是为了将整个框架分为底层服务与上层应用,便于管理与拓展。
分层思想是计算机科学中常见的开发思想,其将复杂系统分为多层,极大系统拓展性与简洁性。在计算机科学中著名的分层系统有:计算机网络OSI七层模型,计算机网络TCP/IP四层模型,WEB开发MVC三层模型。
Bean 行为的拓展
通过上述流程,Bean 已经基本成形,现需要为 Bean 提供更多的灵活性。
通过长期实践,两个点位最为适宜:Bean 初始化后 与Bean 销毁前 。分别称为 init-method和destroy-method。
这种在固定点位被自动调用的方法,叫做钩子方法(Hook Method)。
在 Spring 中,有四种方法配置这两种方法。
- @Bean 注解填写参数
- @PostConstruct 和 @PreDestroy 注解
- InitializingBean 和 DisposableBean
- XML 配置
篇幅所限,本文不在此细说使用方式。
执行顺序分析
给定场景:
UserService.java
java
package me.erickren.source.service;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* DateTime: 2024/03/15 - 17:42
* Author: ErickRen
*/
public class UserService implements InitializingBean, DisposableBean {
public UserService() {
System.out.println("构造函数执行");
}
public void init_bean () {
System.out.println("@Bean 上定义的 Init 方法");
}
public void destroy_bean () {
System.out.println("@Bean 上定义的 Destroy 方法");
}
@PostConstruct
public void init_post() {
System.out.println("@PostConstruct 上定义的 Init 方法");
}
@PreDestroy
public void destroy_post() {
System.out.println("@PreDestroy 上定义的 Destroy 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 重写的 afterPropertiesSet 方法");
}
@Override
public void destroy() {
System.out.println("DisposableBean 重写的 destroy 方法");
}
}
BeanConfig.java:
java
package me.erickren.source.config;
import me.erickren.source.service.UserService;
import org.springframework.context.annotation.Bean;
/**
* DateTime: 2024/03/15 - 17:41
* Author: ErickRen
*/
public class BeanConfig {
@Bean(initMethod = "init_bean", destroyMethod = "destroy_bean")
public UserService userService() {
return new UserService();
}
}
main 函数:
java
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(BeanConfig.class);
context.getBean("userService");
context.close();
}
通过检测,可以得到顺序为:
- 构造函数
- @PostConstruct 上定义的 Init 方法
- InitializingBean 重写的 afterPropertiesSet 方法
- @Bean 上定义的 Init 方法
- @PreDestroy 上定义的 Destroy 方法
- DisposableBean 重写的 destroy 方法
- @Bean 上定义的 Destroy 方法
由此可知,@PostConstruct 与 @PreDestroy 是最先执行的,随后是 InitializingBean 和 DisposableBean 重写的两个方法,最后是 Bean 定义。
原理解析
从名称上来看,这几种方法锁针对的细分位置也不一样。
例如:InitializingBean 中的方法叫做 afterPropertiesSet,这表明这个方法是在填充属性后调用的。
从原理上看,@PostConstruct 和 @PreDestroy 最终生成了InitDestroyAnnotationBeanPostProcessor,而重写 afterPropertiesSet 方法 和 @Bean 定义的 Init 方法实际上都术语 InitMethod 的范畴。
通过断点调试,这三种方法的顺序由AbstractAutowireCapableBeanFactory#initializeBean控制。
java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用初始化前 PostProcessor
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
// 调用初始化方法
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用初始化后 PostProcessor
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
因为初始化前 PostProcessor 最先调用,所以封装为 PostProcessor 的 @PostConstruct 最先调用。之后是其他两种方法,重写 afterPropertiesSet 和 @Bean 定义本质都到了 invokeInitMethods中。
java
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
// 处理是否实现 InitializingBean
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 + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(() -> {
((InitializingBean)bean).afterPropertiesSet();
return null;
}, this.getAccessControlContext());
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
// 调用重写的 afterPropertiesSet 方法
((InitializingBean)bean).afterPropertiesSet();
}
}
// 处理自定义的 初始化方法
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
// 调用自定义的初始化方法 即 @Bean 定义的方法 与 XML 定义等价
this.invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
由此,我们可以得到新的流程:

前面提到的是 Bean 的初始化方法,当容器关闭(调用context.close())时,容器会进行关闭,并进行 Bean 的销毁流程。
java
public void close() {
synchronized(this.startupShutdownMonitor) {
this.doClose();
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
} catch (IllegalStateException var4) {
}
}
}
}
// 上述代码的 doClose() 方法
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Closing " + this);
}
if (!NativeDetector.inNativeImage()) {
LiveBeansView.unregisterApplicationContext(this);
}
try {
this.publishEvent((ApplicationEvent)(new ContextClosedEvent(this)));
} catch (Throwable var3) {
this.logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", var3);
}
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
} catch (Throwable var2) {
this.logger.warn("Exception thrown from LifecycleProcessor on context close", var2);
}
}
// 销毁 Bean
this.destroyBeans();
// 关闭 BeanFactory 这个下文会详细讲解
this.closeBeanFactory();
this.onClose();
// 关闭监听器 这个下文也会讲到
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// 设置活动标志符为 false 标志容器已关闭
this.active.set(false);
}
}
在核心方法 DisposableBeanAdapter#destroy中,与上述初始化方法一样,通过代码顺序确定了三种销毁方法的执行顺序,分别为:processor.postProcessBeforeDestruction(this.bean, this.beanName)、((DisposableBean)this.bean).destroy()和 this.invokeCustomDestroyMethod(this.destroyMethod)。篇幅所限,本文在此不再赘述。
注意:多例 Bean 在本质上不由容器管理生命周期,所以只执行初始化方法,不执行销毁方法。
流程图:

PostProcessor
PostProcessor 本质上是 Hook 处理器 ,下文可能会简称为处理器。其在特定位置被调用执行,干预 Bean 的生命流程。
上文提到,@PostConstruct 和 @PreDestroy 本质上都是 InitDestroyAnnotationBeanPostProcessor,PostProcessor 是 Spring 中非常重要的拓展机制,主要分为两类:
- BeanFactoryPostProcessor:主要作用于 BeanFactory。
- BeanPostProcessor:主要作用于 Bean。
BeanFactoryPostProcessor
BeanFactoryPostProcessor是对BeanFactory进行操作的后置 Hook 处理器。
在 BeanFactory 中,暴露出接口可以对 BeanDefinition 进行操作。BeanFactory 中包含 BeanDefinition。
因此,Spring 提供了有一个更细粒度 的后置处理器接口BeanDefinitionRegistryPostProcessor,参数为BeanDefinitionRegistry,主要对 BeanDefinition 进行操作。
使用
BeanFactoryPostProcess 一般通过作为 Bean 注册到 Spring 容器中,在执行时通过:
java
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
获取所有 processor,并执行。
或者通过直接向容器中插入 processor 的形式使用 BeanFactoryPostProcess。
java
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
context.addBeanFactoryPostProcessor(processor);
从上述代码可以看出,BeanFactoryPostProcessor 由 ApplicationContext 管理和维护,因为其本身操作 BeanFactory,所以不应由 BeanFactory 管理和维护。
调用
这两个处理器主要在AnnotationConfigApplicationContext#refresh中调用执行:
refresh:
java
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// ...
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 执行 BeanFactoryPostProcessor 后置处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// ...
// 注册监听器
this.registerListeners();
// ...
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
// 如果遇到异常,则销毁 Bean
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
执行顺序问题
排序接口
BeanFactoryPostProcessor 有特定的执行顺序,在[spring].context.support.PostProcessorRegistrationDelegate中,定义了方法invokeBeanFactoryPostProcessors,其中决定了执行顺序。
java
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// ...
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
// 先执行实现了 PriorityOrdered 的处理器
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// ...
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
// 再执行实现了 Ordered 的处理器
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// ...
for(int var26 = 0; var26 < var10; ++var26) {
String ppName = var19[var26];
// 最后再执行剩余的处理器
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
// ...
}
由上述源码分析,Spring 会优先执行实现了PriorityOrderedD的处理器,再执行Ordered的处理器,最后执行普通的处理器。
注册方式
上文提到,BeanFactoryPostProcessor 是容器的概念,所以 ApplicationContext 持有并维护处理器。
BeanFactoryPostProcessor 的调用链为:refresh() -> invokeBeanFactoryPostProcessors() -> invokeBeanFactoryPostProcessors() ,其中在invokeBeanFactoryPostProcessors中会向下一级调用传入List<BeanFactoryPostProcessor>类型的参数,由getBeanFactoryPostProcessors()获取,该 List 由AbstractApplicationContext维护。
本质上,context.addBeanFactoryPostProcessor(processor)就向该 List 新增了一个处理器。
在invokeBeanFactoryPostProcessors中,传入的 List 会被首先调用,本文因篇幅所限,不再详细展示代码。
有兴趣的读者可以参阅[spring].context.support.PostProcessorRegistrationDelegate自行分析。
因此,手动注册的处理器会先于 Spring 自动扫描的处理器执行。
实现类型
依旧是在invokeBeanFactoryPostProcessors方法中,Spring 会显示先匹配BeanDefinitionRegistryPostProcessor,再匹配BeanFactoryPostProcessor。
在此不再赘述。
至此,得到 Bean 生命周期的流程图:

BeanPostProcessor
BeanPostProcessor 是对Bean的处理器,其提供了两个点位的处理器:初始化前、初始化后。
java
public interface BeanPostProcessor {
@Nullable
// 初始化前处理器
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
// 初始化后处理器
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
接口的默认方法为不对 Bean 进行任何处理。
BeanPostProcessor 是 Spring 中极其重要的 Hook 处理器,AOP 的实现高度依赖于 BeanPostProcessor。
使用
BeanPostProcessor 与 BeanFactoryPostProcessor 一样,可以注册为 Bean 被 Spring 扫描后执行,也可以向容器中手动注册,不过注册位置与后者有所不同:
java
context.getBeanFactory().addBeanPostProcessor(processor);
从上述代码可以看出,BeanPostProcessor 由 BeanFactory 管理和维护。
ApplicationContext 继承了 BeanFactory,同时使用变量维护 BeanFactory。
执行点位
BeanPostProcessor 是修改 Bean 的处理器,从理论上说需要在创建 Bean 时调用。
Spring 中,BeanPostProcessor 基本由AbstractAutowireCapableBeanFactory进行调用,调用链如下:
doCreateBean() -> initializeBean():
initializeBean 方法:
java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 处理 Aware 下文会详细提到 如果没有概念请忽略
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
// 执行初始化前处理器
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
// 执行初始化方法
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行初始化后处理器
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
AOP 的切入
上文 AOP 增强部分提到,AOP 发生在属性注入之后,这是因为 AOP 实际上依赖了 BeanPostProcessor 的后置处理器。
在[spring].aop.framework.autoproxy包中有 BeanPostProcessor 的实现类AbstractAutoProxyCreator,其在重写 postProcessAfterInitialization方法中调用wrapIfNecessary,生成代理对象。
java
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 调用 wrapIfNecessary
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// ...
Object[] specificInterceptors =
this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy =
this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
所以,在执行属性填充后,才会创建代理对象。也因此,BeanPostProcessor 是 Spring 框架尤其重要的拓展接口。
由此可得,Bean 的流程图:

InstantiationAwareBeanPostProcessor
在 BeanPostProcessor 之上,有一个更细粒度 的接口InstantiationAwareBeanPostProcessor。
其主要定义了三个方法:
- postProcessBeforeInstantiation,返回值为 Object 为 Bean 对象。
- postProcessAfterInstantiation,返回值为 boolean,如果为 false,则postProcessProperties 不会执行。
- postProcessProperties,返回值为 PropertyValues。
注意:BeanPostProcessor 维护方法 postProcessBeforeInitialization 和 postProcessAfterInitialization。
而 InstantiationAwareBeanPostProcessor 维护的是 postProcessBeforeInstantiation 和 postProcessAfterInstantiation 。两者是不同的,Initialization 和 Instantiation。
Instantiation 译作:实例化,特指创建 Bean 对象。
Initialization 译作:初始化,特指进行 Bean 属性填充等必要步骤。
执行顺序为:Instantiation -> properties -> Initialization
从流程图来理解,即为这样:

运行原理
在AbstractAutowireCapableBeanFactory的 createBean 中,其会先执行 BeforeInstantiation,之后再执行 doCreateBean 创建 Bean 实例。
java
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// ...
Object beanInstance;
try {
// 执行 BeforeInstantiation 方法
beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
// 如果 beanInstance 不为空,则已经有对象了,所以直接返回,不进行后续步骤。
if (beanInstance != null) {
return beanInstance;
}
}
// ...
try {
// 调用 doCreateBean
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// ...
}
因为 AfterInstantiation 在初始化后,属性赋值前执行,Spring 将其放在了populateBean中执行:
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ...
while(var4.hasNext()) {
InstantiationAwareBeanPostProcessor bp = (InstantiationAwareBeanPostProcessor)var4.next();
// 当返回为 false 则直接返回
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
// ...
}
拓展
感知
Spring 依赖注入的最大特点是所有的 Bean 对 Spring 容器的存在是没有意识的 ,这是 Spring 为了隔离业务代码和框架代码 所做的努力。在 Spring 的思想中,解耦并不只是业务代码间的解耦,还包括业务代码与框架间的解耦 。在没有感知(Aware)的情况下,Bean 作为业务方无法感知到容器的存在。但在实际项目中,又不可避免地要使用到 Spring 容器本身的功能。Aware 的目的是让 Bean 获得容器服务。
Aware 接口
java
package org.springframework.beans.factory;
public interface Aware {
}
Aware 接口是一个标记接口,其下有极其多实现。Aware 的子接口表示需要使用的 Spring 资源。
例如:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,ResourceLoaderAware。
Aware的实现
在 Bean 创建过程中会实现一部分 Aware,主要在AbstractAutowireCapableBeanFactory#invokeAwareMethods,该方法在同类下initializeBean方法中调用:
java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
// 执行 Aware 方法
this.invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
invokeInitMethods:
java
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
// BeanName Aware 实现
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
// BeanClassLoader Aware 实现
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
// BeanFactory Aware 实现
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
}
}
Spring 在初始化 Bean 的过程中,判断 Bean 实现的 Aware 子接口的类型,调用相关的 set 方法将 Spring 内部对象注入到 Bean 中。
在 Spring 内部只执行了少部分 Aware,实际上,其他的 Aware 都依靠 BeanPostProcessor 进行注入。
例如:在[spring].context.support.ApplicationContextAwareProcessor 中,实现了BeanPostProcessor中的postProcessBeforeInitialization方法,对感知进行扫描与执行。
ApplicationContextAwareProcessor 中实现的 postProcessBeforeInitialization:
java
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 检查 Bean 是否实现了本 Processor 负责的感知接口
if (
!(bean instanceof EnvironmentAware) &&
!(bean instanceof EmbeddedValueResolverAware) &&
!(bean instanceof ResourceLoaderAware) &&
!(bean instanceof ApplicationEventPublisherAware) &&
!(bean instanceof MessageSourceAware) &&
!(bean instanceof ApplicationContextAware) &&
!(bean instanceof ApplicationStartupAware)) {
return bean;
} else {
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareInterfaces(bean);
return null;
}, acc);
} else {
// 执行感知扫描并设置
this.invokeAwareInterfaces(bean);
}
return bean;
}
}
invokeAwareInterfaces 方法:
java
private void invokeAwareInterfaces(Object bean) {
// 匹配并执行
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware) {
((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}