9. Bean 生命周期 Lifecycle (重点)
什么是 Bean 的生命周期?
就是 Bean 从出生到死亡的全过程
// 补充: 这一章是重中之重, 也是难点, 补充流程图等
9.1 Bean 元信息配置阶段
BeanDefinition 配置的方式:
- 面向资源
- xml 配置
- properties 配置
- 面向注解 @Bean
- 面向 api
配置 bean 的几种方式在前面章节已经非常熟悉了,这里只介绍 properties 配置 bean 的方式
- 在 properties 文件中配置 bean 的元信息
# user.properties
user.(class)=org.geekbang.dependency.injection.type.Docter
user.id=11
user.name=黑百合
user.city=HANGZHOU
- 使用 PropertiesBeanDefinitionReader 解析加载 bean
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader beanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
String location = "docter.properties";
// 创建资源
Resource resource = new ClassPathResource(location);
// 加载 properties 中的bean配置
int count = beanDefinitionReader.loadBeanDefinitions(resource);
System.out.println("已加载BeanDefinition数量: " + count);
Docter docter = beanFactory.getBean(Docter.class);
System.out.println(docter);
}
输出结果:
已加载BeanDefinition数量: 1
Docter{id=11, name='黑百合', city=HANGZHOU, resource=null}
9.2 Bean 元信息解析
Bean 的元信息就是 BeanDefinition,
- 面向资源 BeanDefinition 解析,核心是 BeanDefinitionReader 接口,其有 2 个实现类
- xml 配置解析,XmlBeanDefinitionReader 解析得到 GenericBeanDefinition
- properties 配置解析,PropertiesBeanDefinitionReader
- 面向注解 BeanDefinition 解析,核心是 AnnotatedBeanDefinitionReader 类
AnnotatedBeanDefinitionReader 与 BeanDefinitionReader 接口没有继承关系,因为前者不需要加载资源loadBeanDefinitions()
加载 xml 配置的 bean 包含两个阶段:
- 解析 xml
- 将 bean 配置解析为 BeanDefinition
- 注册 BeanDefinition
XmlBeanDefinitionReader.java
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 1.解析xml
Document doc = doLoadDocument(inputSource, resource);
// 2.将doc解析为BeanDefinition,
// 3.然后注册BeanDefinition
// 见下方代码块
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
// bean的配置格式有问题
}
catch (SAXParseException ex) {
// xml 解析有问题
}
catch (IOException ex) {
// xml 找不到
}
}
解析<bean>标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 2. 将xml中bean配置解析为BeanDefinition, 保存到BeanDefinitionHolder中
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 解析<bean>中嵌套的自定义标签
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 3. 见代码块2,注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
- 注解类型配置的 bean 示例
public class AnnotatedBeanDefintionParsingDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 用来解析注解类型配置的bean
AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);
int countBefore = beanFactory.getBeanDefinitionCount();
// 解析bean, 注册bean, 见代码块1
beanDefinitionReader.register(AnnotatedBeanDefintionParsingDemo.class);
int countAfter = beanFactory.getBeanDefinitionCount();
System.out.println("加载的bean数量: " + (countAfter - countBefore));
}
}
与下面的代码作用类似,因为 AnnotationConfigApplicationContext 中有两个字段 AnnotatedBeanDefinitionReader 和 DefaultListableBeanFactory,前者负责注册 bean,后者负责容器管理。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
加载注解配置的 bean 包含两个阶段:
- 解析 bean 得到 BeanDefinition
- 注册 BeanDefinition 到容器
源码分析,注解类型配置的 bean,会解析 bean 配置元信息得到 BeanDefinition,封装为 BeanDefinitionHolder,最后注册到容器
// 代码块1
AnnotatedBeanDefinitionReader.java
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
// 1.解析bean配置得到BeanDefinition
// 生成BeanDefinition, 设置beanClass
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 处理@Conditional,若条件不满足,则跳过该bean
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 设置回调, 这里为null
abd.setInstanceSupplier(supplier);
// 解析并设置scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 若未设置bean名称, 自动生成
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 解析@Lazy, @Primary, @Value, @DependsOn, @Description, 保存到BeanDefinition
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 使用spring api注册bean时,可以在方法参数中手动设置 Lazy,Primary等, 这里跳过
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 跳过
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
// 封装BeanDefinition到BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 设置代理模式,若是类则Cglib,若是接口则动态代理,或者不使用代理
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 2.注册BeanDefinition到容器, 见下一小节代码块2
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
9.3 Bean 注册
- Bean 注册接口 BeanDefinitionRegistry#registerBeanDefinition
- Bean 注册实现 DefaultListableBeanFactory#registerBeanDefinition
// 代码块2
BeanDefinitionReaderUtils.java
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 见代码块3, 注册BeanDefinition到容器
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 注册bean的别名到容器, 保存到aliasMap属性中
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
BeanDefinitionRegistry 接口规范了 BeanDefinition 的注册,删除,查找等操作,源码如下所示:
public interface BeanDefinitionRegistry extends AliasRegistry {
// 注册BeanDefinition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
// 删除BeanDefinition
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 通过bean名称查找BeanDefinition
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 通过bean名称判断容器中是否已经存在该bean
boolean containsBeanDefinition(String beanName);
// 获取所有BeanDefinition的名称
String[] getBeanDefinitionNames();
// 获取容器中BeanDefinition的数量
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
DefaultListableBeanFactory 实现了 BeanDefinitionRegistry 接口,也实现了注册 BeanDefinition 的方法 registerBeanDefinition。
注册 BeanDefinition 到容器,都要经过该方法,无论是 xml,注解,api注册,还是 Spring 内建BeanDefinition等
// 代码块3
DefaultListableBeanFactory.java,
// 保存BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 保存bean名称, 有序
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 实现了BeanDefinitionRegistry接口registerBeanDefinition方法
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 校验bean
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 查找bean名称是否已被占用
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 默认允许同名bean覆盖, Springboot2.1中修改不允许
if (!isAllowBeanDefinitionOverriding()) {
// 不允许同名bean覆盖, 抛出异常
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}else {
// 打印相关日志
}
// bean名称已被占用, 会使用当前bean进行覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// bean的创建是否已经开始
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
// 将BeanDefinition注册到容器,即保存到beanDefinitionMap
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
// 添加bean的名称
updatedDefinitions.add(beanName);
// beanDefinitionNames是ArrayList,保证bean初始化的顺序与声明顺序相同
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
} else {
// 将BeanDefinition注册到容器,即保存到beanDefinitionMap
this.beanDefinitionMap.put(beanName, beanDefinition);
// 将bean名称保存到beanDefinitionNames
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
9.4 BeanDefinition 合并
一个 bean 的 BeanDefinition 不仅包括自身的,还包括父 bean 的 BeanDefinition,所以需要将父 bean 的元信息合并进来,故注册子 BeanDefinition 之前要依赖查找父 BeanDefinition
- 在当前容器 BeanFactory 中查找
- 去父容器 BeanFactory 层次性查找
- 合并接口 ConfigurableBeanFactory#getMergedBeanDefinition
- 具体实现 AbstractBeanFactory#getMergedBeanDefinition(java.lang.String),DefaultListableBeanFactory 继承了该类,调用这些方法时,本质还是他在调用。
- 配置父子 bean
在 xml 配置 bean 时可以使用parent属性指定父 bean
<bean id="user" class="org.geekbang.ioc.overview.lookup.domain.User">
<property name="id" value="1"/>
<property name="name" value="tracccer"/>
</bean>
<bean class="org.geekbang.ioc.overview.lookup.domain.SuperUser" parent="user" primary="true">
<property name="address" value="杭州"/>
</bean>
在注解配置 bean 时,java 代码中的继承 extend 也相当于指定了父 bean
- GenericBeanDefinition 表示 Bean 的元信息,但是不包括 Bean parent 中的元信息。上面的两个 Bean user, superUser,开始都会被解析为 GenericBeanDefinition,只不过后者设置了 parent
public class GenericBeanDefinition extends AbstractBeanDefinition {
private String parentName;
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
}
RootBeanDefinition 表示一个 Bean 完整的元信息,包括 parent bean 中的信息。
user 在经过 MergedBeanDefinition 操作后,直接将 GenericBeanDefinition 修改为 RootBeanDefinition
superUser 在经过 MergedBeanDefinition 操作后,会将其与 parent 中的元信息 BeanDefinition 合并,然后得到 RootBeanDefinition
public class RootBeanDefinition extends AbstractBeanDefinition {
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
}
- 获取 bean 的完整 BeanDefinition,即合并后的元信息 MergedBeanDefinition
// 代码块4
AbstractBeanFactory.java
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
String beanName = transformedBeanName(name);
// 当前容器不存在beanName, 且存在父容器
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// 递归调用getMergedBeanDefinition, 去父容器查找
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
}
// 从本地容器查找, 见代码块5
return getMergedLocalBeanDefinition(beanName);
}
去缓存中查找 bean 的合并后元信息 mergedBeanDefinition,如果找不到,则去本地容器获取 bean 合并后的元信息。
// 代码块5
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// 从本地容器缓存中查找bean
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
// 找到了目标BeanDefinition返回
return mbd;
}
// 见代码块6,
// 根据bean名称,bean的普通元信息GenericBeanDefinition获取完整元信息
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
// 去容器查找bean的普通元信息
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
根据 bean 的名称beanName和 bean 的普通元信息GenericBeanDefinition,获取合并后的完整元信息RootBeanDefinition,源码如下所示,
- 如果是获取 user 的完整元信息,这里的操作很简单,就是将其普通的元信息 GenericBeanDefinition 封装为 RootBeanDefinition 返回。
- 如果是获取 superUser 的完整元信息,会获取 parent bean,然后将二者的 BeanDefinition 合并为 RootBeanDefinition 并返回
// 代码块6
// beanName bean名称
// bd bean的普通元信息,包含parent属性
// containingBd 表示嵌套bean, 这里为null
// return mbd, 合并后的完整元信息
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// 如果不是嵌套bean, 从缓存中再次检查bean是否存在
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 当前容器缓存中未找到bean
if (mbd == null || mbd.stale) {
previous = mbd;
// 1.bean没有parent, user会进入这里
if (bd.getParentName() == null) {
// 如果是RootBeanDefinition,没有parent,不需要merge
if (bd instanceof RootBeanDefinition) {
// 复制一份RootBeanDefinition返回
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
// 将GenericBeanDefinition封装为RootBeanDefinition返回
mbd = new RootBeanDefinition(bd);
}
} else {
// 2.bean有parent, SuperUser会进入这里
// 见代码块7
}
// 如果scope为空, 默认设置为SINGLETON
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// 跳过
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// 非嵌套bean为null, 会进入
// 将user缓存到mergedBeanDefinitions,供superUser获取父bean时查找
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
这里是上一个方法的截取,主要是处理 bean 存在 parent 的情况,会去缓存 mergedBeanDefinitions 中查找 parent,然后将 parent 元信息与当前 bean 的元信息合并为 RootBeanDefinition 并返回。
// 代码块7
else {
// 2.bean有parent, SuperUser会进入这里
BeanDefinition pbd; // 保存parent BeanDefinition
try {
// 获取parent bean名称, 这里为user
String parentBeanName = transformedBeanName(bd.getParentName());
// bean的parent与自己同名
if (!beanName.equals(parentBeanName)) {
// 获取parent BeanDefinition, 这里是user
// 调用代码块4,然后调用代码块5,会从缓存中找到user
pbd = getMergedBeanDefinition(parentBeanName);
} else {
// bean的parent与自己同名,说明父bean可能在父容器中
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
// 存在父容器, 去父容器合并BeanDefinition
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
} else {
// 不存在父容器,说明找不到parent bean,打印日志
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
} catch (NoSuchBeanDefinitionException ex) {
// 找不到parent bean
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 使用parent BeanDefinition构造一个RootBeanDefinition
mbd = new RootBeanDefinition(pbd);
// 使用子BeanDefinition覆盖父BeanDefinition中相关属性
// (合并)这里bd是superUser,mbd是user,将二者信息合并
mbd.overrideFrom(bd);
}
下面是一个 xml 配置的嵌套 bean,Shop 类有一个属性 User,将 user 直接声明在字段中,称为嵌套 bean,嵌套的 bean 仅仅作为 setter 注入的参数,无法被容器访问。
<bean id="shop" class="com.geek.Shop">
<property name="user">
<bean class="org.geekbang.ioc.domain.User" />
</property>
</bean>
与上面的配置几乎等价。
<bean id="user" class="org.geekbang.ioc.domain.User" />
<bean id="shop" class="com.geek.Shop">
<property name="user" ref="user" />
</bean>
9.5 Bean Class 加载
- ClassLoader 类加载
- Java Security 安全控制
- ConfigurableBeanFactory 临时 ClassLoader (不重要)
// 代码块8
AbstractBeanFactory.java
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
// 跳过
if (!ObjectUtils.isEmpty(typesToMatch)) {}
// 得到bean的class
String className = mbd.getBeanClassName();
if (className != null) {
Object evaluated = evaluateBeanDefinitionString(className, mbd);
// 跳过
if (!className.equals(evaluated)) {}
// 跳过
if (freshResolve) {}
}
// 代码块9, 加载bean的class
return mbd.resolveBeanClass(beanClassLoader);
}
// 代码块9
AbstractBeanDefinition.java
public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
String className = getBeanClassName();
if (className == null) {
return null;
}
// 加载bean的class文件, 底层是Class.forName()
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
this.beanClass = resolvedClass;
return resolvedClass;
}
// 这一节没看太懂
9.6 Bean 实例化前
- 接口 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
- 自定义实例化前的回调方法,实现 InstantiationAwareBeanPostProcessor 接口,重写 postProcessBeforeInstantiation 方法
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* 当 user 在实例化时, 手动创建一个user对象并返回
* 返回为null表示使用spring容器实例化bean
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("user".equals(beanName)) {
System.out.println(beanName + " bean 实例化前回调...");
User user = new User();
user.setName("widowmaker");
return user;
}
return null;
}
}
- 注册,会将这个 BeanPostProcessor 注册保存到容器的
beanPostProcessors属性中
public static void main(String[] args) {
// 创建容器并加载xml中的BeanDefinition
DefaultListableBeanFactory beanFactory = getBeanFactory();
// 1. 注册自定义的BeanPostProcessor, 保存到容器的beanPostProcessors属性
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 2. 依赖查找, 会进行实例化
User user = beanFactory.getBean("user", User.class);
// 3. 期望输出widowmaker, 因为在实例化前我们将bean替换了
System.out.println(user);
}
输出结果
user bean 实例化前回调...
User{id=null, name='widowmaker'}
- 源码分析,这是在 bean 实例化前,回调所有实现了 InstantiationAwareBeanPostProcessor 接口的回调方法
// 代码块10
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
// 从容器的beanPostProcessors属性获取所有
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 处理InstantiationAwareBeanPostProcessor接口实现类
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 回调postProcessBeforeInstantiation方法
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
// 如果不为空, 会将result作为bean返回
if (result != null) {
return result;
}
}
}
// 返回null表示使用spring容器对bean进行实例化
return null;
}
- 创建 bean 分为 3 个步骤,
- 加载 bean class
- 回调实例化前的处理程序 Postprocessor
- 实例化 bean
// 代码块11
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// 1.加载类, 见代码块8
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 若mbd中没有设置bean的class, 这里进行设置
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
mbdToUse.prepareMethodOverrides();
// 2.代码块10,处理bean实例化前的操作
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
// 3.bean 实例化, 见代码块
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
9.7 Bean 实例化
实例化方式
- 默认构造器创建,实例化策略:InstantiationStrategy
- 构造器依赖注入,
- AbstractAutowireCapableBeanFactory#createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// lambda方式注册的bean, 进行实例化
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 跳过,若bean存在工厂方法factory-method
if (mbd.getFactoryMethodName() != null) {
// 通过工厂方法factory-method实例化bean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 重复创建相同类型的bean
boolean resolved = false;
boolean autowireNecessary = false;
// 跳过
if (args == null) {}
if (resolved) {}
// 没有实现SmartInstantiationAwareBeanPostProcessor返回null
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 判断自动绑定的模式autowiring=constructor
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 注入构造器参数实例化
return autowireConstructor(beanName, mbd, ctors, args);
}
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 注入构造器参数实例化
return autowireConstructor(beanName, mbd, ctors, null);
}
// (重点)使用默认构造器实例化bean
return instantiateBean(beanName, mbd);
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 不存在方法覆盖
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
// 获取bean的class
final Class<?> clazz = bd.getBeanClass();
// 接口无法实例化,抛出异常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
// 跳过,安全处理
if (System.getSecurityManager() != null) {}
else {
// 获取class的构造方法
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 通过反射调用构造方法创建bean
// 将构造方法Accessible修改为true,然后constructor.newInstance()创建实例
return BeanUtils.instantiateClass(constructorToUse);
}else {
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
protected <T> T doGetBean(final String name, final Class<T> requiredType,
final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
// ....
// 获取bean的完整元信息
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 跳过, 获取并处理bean的 dependsOn
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {}
// 如果bean是单例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
// 见代码块 ,创建bean, 包含两步操作
// 1.加载bean的class 2.实例化bean
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 跳过,如果bean是Prototype
else if (mbd.isPrototype()) {}
// ...
}
// debug 构造器注入, 自动绑定构造器注入
9.8 Bean 实例化后
- 接口 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
- 属性赋值 populate 判断
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
// 返回true表示bean的属性应该被设置, false应该被跳过
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
}
使用案例
实现 接口 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法,在 bean 实例化后对 bean 进行后置处理,这里我们将名称为 user 的bean 的返回值设置为 false,表示不需要为user 设置属性,故 xml 中配置的 bean 属性不会生效。
- 实现接口,重写方法
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* bean 实例化后调用
* 返回false表示不要为bean设置属性
* 返回true表示要为bean设置属性
* 注释掉该方法, user bean 属性有值
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
// user bean 不要为属性赋值
if ("user".equals(beanName)) {
return false;
}
return true;
}
}
- 注册自定义的 BeanPostProcessor 到容器
public static void main(String[] args) {
// 创建容器并加载xml中的BeanDefinition
DefaultListableBeanFactory beanFactory = getBeanFactory();
// 1. 注册自定义的BeanPostProcessor, 保存到容器的beanPostProcessors属性
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 2. 依赖查找, 会实例化bean
User user = beanFactory.getBean("user", User.class);
SuperUser superUser = beanFactory.getBean(SuperUser.class);
// 3. 期望输出bean的属性为null, 因为在实例化后我们返回了false表示不为属性赋值
// 如果没有自定义的后置beanPostProcessors, 期待输出xml中配置的 tracccer
System.out.println(user);
}
- 输出结果,若注释掉重写的方法,会输出 User{id=1, name='tracccer'}
User{id=null, name='null'}
9.9 Bean 属性赋值前
- Bean 属性值元信息 PropertyValues
- Bean 属性赋值前回调接口
- Spring1.2-5.0 InstantiationAwareBeanPostProcessor#postProcessPropertySource
- Spring5.1以后 InstantiationAwareBeanPostProcessor#postProcessProperties
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
}
使用案例
实现 接口 InstantiationAwareBeanPostProcessor 的 postProcessProperties 方法,在 bean 属性赋值前对 bean 进行后置处理,这里我们将名称为 user 的bean 的 name 属性值设置Sigma并返回,这一步替换掉了 Spring 对于 bean 属性赋值的处理。
- 实现接口,重写方法
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* 为bean的属性设置值
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
MutablePropertyValues propertyValues = new MutablePropertyValues();
// 作用等价于 <property name="name" value="Sigma"/>
propertyValues.addPropertyValue("name", "Sigma");
return propertyValues;
}
return null;
}
}
- 注册自定义的 BeanPostProcessor 到容器
public static void main(String[] args) {
// 创建容器并加载xml中的BeanDefinition
DefaultListableBeanFactory beanFactory = getBeanFactory();
// 1. 注册自定义的BeanPostProcessor, 保存到容器的beanPostProcessors属性
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 2. 依赖查找, 会实例化bean
User user = beanFactory.getBean("user", User.class);
// 3. 期望输出bean的属性为Sigma, 因为在BeanPostProcessor中设置了
System.out.println(user);
}
- 输出结果,是我们定义的属性值,xml 中对 bean 的属性赋值没有生效,即替换了 Spring 对bean 的赋值,若注释掉重写的方法,会输出 User{id=1, name='tracccer'}
User{id=null, name='Sigma'}
9.10 Aware 接口回调
这块的注入参考 6.8 章节 接口回调方法注入
AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
// 回调BeanNameAware实现类
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// 回调BeanClassLoaderAware实现类
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
// 回调BeanFactoryAware实现类
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
9.11 Bean 初始化前
- 回调方法 BeanPostProcessor#postProcessBeforeInitialization,方法字面意思就是初始化前的处理程序
- AOP 功能就是在这一阶段实现的,AbstractAutoProxyCreator#postProcessBeforeInstantiation
源码如下所示:
public interface BeanPostProcessor {
/**
* 在bean初始化之前回调
*/
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
使用案例
实现接口 BeanPostProcessor 的 postProcessBeforeInitialization 方法,在 bean 初始化前对 bean 进行后置处理,这里我们将名称为 user 的bean 的 name 属性值设置Torbjorn并返回。
- 实现接口,重写方法,由于 InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor,所以这里继承 InstantiationAwareBeanPostProcessor 也是可以的。
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* bean初始化前回调该方法
* 为user bean重新设置属性并返回
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
User user = (User) bean;
user.setName("Torbjorn");
return user;
}
return bean;
}
}
- 注册自定义的 BeanPostProcessor 到容器
public static void main(String[] args) {
// 创建容器并加载xml中的BeanDefinition
DefaultListableBeanFactory beanFactory = getBeanFactory();
// 1. 注册自定义的BeanPostProcessor, 保存到容器的beanPostProcessors属性
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 2. 依赖查找, 会实例化bean
User user = beanFactory.getBean("user", User.class);
// 3. 期望输出bean的属性为Torbjorn, 因为在BeanPostProcessor中设置了
// 默认输出xml中配置的tracccer
System.out.println(user);
}
输出结果:是我们定义的属性值,xml 中对 bean 的属性赋值没有生效,即替换了 Spring 对bean 的赋值,若注释掉重写的方法,会输出 User{id=1, name='tracccer'}
User{id=1, name='Torbjorn'}
源码分析
bean 在初始化前会回调自定义的 BeanPostProcessor#postProcessBeforeInitialization 方法
AbstractAutowireCapableBeanFactory.java
// 代码块 11-1,初始化bean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
// 安全部分,跳过
} else {
// 回调自定义的Aware方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化前,见代码块11-2
// 回调自定义的BeanPostProcessor#postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 初始化, 见代码块12-2
// 回调自定义的InitializingBean#afterPropertiesSet方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 初始化后, 见代码块13-1
// 回调自定义的BeanPostProcessor#postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
AbstractAutowireCapableBeanFactory.java
// 代码块 11-2
// bean初始化前回调BeanPostProcessors#postProcessBeforeInitialization 方法
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 获取所有BeanPostProcessor,
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 回调其postProcessBeforeInitialization()方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
// 回调返回null,则将当前bean返回
return result;
}
// 将回调的返回结果作为bean返回
result = current;
}
return result;
}
9.12 Bean 初始化
Bean 的初始化就是指调用 Bean 的初始化方法,会依次回调下列方法:
- @PostConstruct 标记方法
- 实现 InitialzingBean 接口的 afterPropertiesSet() 方法
- 自定义初始化方法,都是将初始化方法名保存到 BeanDefinition 元信息的属性 initMethodName 中
- xml 配置:
<bean init-method="xxx" /> - Java 注解:
@Bean(initMethod="xxx") - Java API:
AbstractBeanDefinition#setInitMethodName(String)
- xml 配置:
详细使用参考 4.6 初始化 Bean 章节
1.@PostConstruct 的回调流程
- 首先构建一个 bean,使用 @PostConstruct 标记初始化方法
public class Teacher {
// @PostConstruct 标记初始化方法
@PostConstruct
public void init() {
System.out.println("@PostConstruct设置初始化方法: Teacher 初始化中...");
}
}
- 参考 6.17 章节,@PostConstruct 注解由
CommonAnnotationBeanPostProcessor进行处理,而且该类实现了 BeanPostProcessor#postProcessBeforeInitialization 方法,即和上一节中我们自定义的初始化前调用的 BeanPostProcessor 作用一致,源码如下所示
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
// 可以处理的注解
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
}
// 该方法会在bean初始化前被回调,具体参考代码块11-2
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 底层是利用反射调用@PostConstruct标记的方法
metadata.invokeInitMethods(bean, beanName);
}
catch (Throwable ex) {}
return bean;
}
}
这其实也解答了一个疑问,就是 BeanPostProcessor#postProcessBeforeInitialization 有什么具体应用案例,在 Bean 初始化前处理@PostConstruct 注解就是之一。以后我们有特殊 Bean 需要在初始化前执行一些操作,就可以重写该方法来实现,比如标记了某个自定义注解的 bean 在初始化前需要打印日志等。
2. 其他初始化方法的回调过程
- 首先构建一个 bean,重写 InitialzingBean#afterPropertiesSet 方法
public class Teacher implements InitializingBean {
// 实现InitializingBean#afterPropertiesSet方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实现InitializingBean接口设置初始化方法: Teacher 初始化中...");
}
// 使用@Bean(initMethod="")标记该方法在初始化后调用
public void initTeacher() {
System.out.println("initMethod设置初始化方法: Teacher 初始化中...");
}
}
- 使用注解配置 bean,并设置初始化方法,然后创建容器并启动,容器会扫描到类中配置的 bean,初始化 bean 时会回调指定的初始化方法
public static void main(String[] args) {
// 1.创建注解配置的应用上下文
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanDestroyDemo.class);
System.out.println("=========Spring应用上下文开始启动=========");
// 2. 启动应用上下文
applicationContext.refresh();
System.out.println("=========Spring应用上下文已启动=========");
}
// 指定初始化方法, 与xml方式作用一直
@Bean(initMethod = "initTeacher")
public Teacher createTeacher() {
return new Teacher();
}
输出结果:说明 bean 初始化时回调了两个初始化方法
=========Spring应用上下文开始启动=========
实现InitializingBean接口设置初始化方法: Teacher 初始化中...
initMethod设置初始化方法: Teacher 初始化中...
=========Spring应用上下文已启动=========
- 参考上一节代码块 11-1,bean 在初始化时会回调初始化方法
- 回调重写的 InitialzingBean#afterPropertiesSet 方法
- 回调 Bean 使用
initMethod指定的初始化方法
AbstractAutowireCapableBeanFactory.java
// 代码块12-2
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 判断bean是否实现了InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
// 1. 回调重写的afterPropertiesSet()方法
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (System.getSecurityManager() != null) {
// 省略安全部分...
}else {
// 重点:回调重写的afterPropertiesSet()方法
((InitializingBean) bean).afterPropertiesSet();
}
}
// 2. 回调bean配置中指定的初始化方法
// 3. 回调通过 Java Api 的方式指定初始化方法,见4.6.2
if (mbd != null && bean.getClass() != NullBean.class) {
// 通过BeanDefinition获得bean配置的初始化方法,包括注解和xml配置
String initMethodName = mbd.getInitMethodName();
// 1.初始化方法名不能为空
// 2.若当前bean实现了InitializingBean,则配置的初始化方法名不能为afterPropertiesSet
// 3.安全部分,跳过即可
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 通过反射回调指定的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
通过源码分析,不难得出三种初始化方法的调用顺序是:
@PostConstruct → InitializingBean接口 → initMethod,@PostConstruct 本质是 BeanPostProcessor 进行处理,在初始化前就进行了回调,后两者会在初始化时依次回调。
所谓的初始化时,就是 bean 在创建好之后,需要进行一些初始化操作,即会调用 bean 设置的初始化方法。
9.13 Bean 初始化后
-
回调方法 BeanPostProcessor#postProcessAfterInitialization,在Bean初始化后回调,与初始化前的 postProcessBeforeInitialization() 相对应
public interface BeanPostProcessor {
// 在bean初始化前调用
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 在bean初始化后调用
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
使用案例
实现接口 BeanPostProcessor 的 postProcessBeforeInitialization 方法,在 bean 初始化后 对 bean 进行后置处理,这里我们将名称为 user 的bean 的 name 属性值设置Symmetra并返回。
- 实现接口,重写方法,由于 InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor,所以这里继承 InstantiationAwareBeanPostProcessor 都是可以的。
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* bean初始化后回调该方法
* 为user bean重新设置属性并返回
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
User user = (User) bean;
user.setName("Symmetra");
return user;
}
return bean;
}
}
- 注册自定义的 BeanPostProcessor 到容器
public static void main(String[] args) {
// 创建容器并加载xml中的BeanDefinition
DefaultListableBeanFactory beanFactory = getBeanFactory();
// 1. 注册自定义的BeanPostProcessor, 保存到容器的beanPostProcessors属性
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 2. 依赖查找, 会实例化bean
User user = beanFactory.getBean("user", User.class);
// 3. 期望输出bean的属性为Torbjorn, 因为在BeanPostProcessor中设置了
// 默认输出xml中配置的tracccer
System.out.println(user);
}
输出结果:是我们定义的属性值,xml 中对 bean 的属性赋值没有生效,即替换了 Spring 对bean 的赋值,若注释掉重写的方法,会输出 User{id=1, name='tracccer'}
User{id=1, name='Symmetra'}
源码分析
bean 在初始化后会回调自定义的 BeanPostProcessor#postProcessAfterInitialization 方法
AbstractAutowireCapableBeanFactory.java
// 初始化bean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 回调自定义的Aware方法
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化前,见代码块11-2
// 回调自定义的BeanPostProcessor#postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 初始化, 见代码块12-2
// 回调自定义的InitializingBean#afterPropertiesSet方法
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null || !mbd.isSynthetic()) {
// 初始化后, 见代码块13-1
// 回调自定义的BeanPostProcessor#postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这部分源码与初始化前回调 BeanPostProcessor,不能说一模一样,只能说完全一致。
AbstractAutowireCapableBeanFactory.java
// bean初始化后回调BeanPostProcessor#postProcessAfterInitialization 方法
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 获取所有的BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 回调其postProcessAfterInitialization()方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
// 回调返回null,则将当前bean返回
return result;
}
// 将回调的返回结果作为bean返回
result = current;
}
return result;
}
// 补充: 通过这几个章节,可以发现 AutowireCapableBeanFactory 也是 Spring 中非常重要的一个容器,补充一下其的主要功能。定义了以下功能:创建bean,初始化bean,销毁bean,注入bean,处理依赖,应用BeanPostProcessor
9.14 Bean 初始化完成
该方法可以在 Bean 在初始化完成以后,还能对 Bean 进行修改
- 回调方法 SmartInitializingSingleton#afterSingletonsInstantiated,Spring 4.1支持
public interface SmartInitializingSingleton {
// 在bean初始化完成后回调
void afterSingletonsInstantiated();
}
使用案例
实现接口 SmartInitializingSingleton 的 afterSingletonsInstantiated 方法,在 bean 初始化完成后 对 bean 进行后置处理,这里我们将名称为 user 的bean 的 name 属性值设置Symmetra并返回。
- 构建一个 bean,重写 SmartInitializingSingleton#afterSingletonsInstantiated 方法
public class Teacher2 implements SmartInitializingSingleton {
private String name;
@Override
public void afterSingletonsInstantiated() {
this.name = "Winston";
System.out.println("实现SmartInitializingSingleton接口设置初始化完成时回调方法: Teacher 初始化完成...");
}
}
- 注册 bean 到容器并启动
public static void main(String[] args) {
// 1.创建并启动 ApplicationContext 容器, 使用注解配置
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationLifeCycleDemo4.class);
// 容器启动, 对bean实例化初始化完成后, 回调afterSingletonsInstantiated方法
applicationContext.refresh();
Teacher2 teacher = applicationContext.getBean(Teacher2.class);
System.out.println(teacher);
}
@Bean
public Teacher2 createTeacher() {
return new Teacher2();
}
输出结果,自定义回调方法中修改的属性值生效
实现SmartInitializingSingleton接口设置初始化完成时回调方法: Teacher 初始化完成...
Teacher2{name='Winston'}
源码分析
容器在启动refresh时,会对所有非懒加载的 bean 进行实例化和初始化,在这两项工作完成后,会回调 SmartInitializingSingleton#afterSingletonsInstantiated 方法,源码如下所示:
DefaultListableBeanFactory.java
@Override
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
// 完成bean的实例化与初始化, 初始化前,初始化,初始化后的回调均在此处调用
}
// 遍历所有bean
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
// 若当前bean实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
// 安全处理,跳过
} else {
// (重点)回调SmartInitializingSingleton#afterSingletonsInstantiated 方法
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
应用案例
在监听器 17.16.2 章节,@EventListener 标记监听回调方法,监听器注册到容器的时机就是 bean 初始化完成时,实现方式就是实现了 SmartInitializingSingleton#afterSingletonsInstantiated 方法。
9.15 Bean 销毁前
- 回调方法 DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
- 所有 Bean 在销毁前都会回调该方法
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
// 在bean销毁前调用
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
}
使用案例
实现接口 DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction 方法,在 bean 销毁前对 bean 进行处理,这里我们打印一行日志后销毁 Bean。
- 重写 DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction 方法
// 代码块15-2
static class LifecycleDestructionPostProcessor implements DestructionAwareBeanPostProcessor {
// 如何被调用见代码块15-1
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (bean instanceof User) {
User user = (User) bean;
System.out.println( user.getName() + "被放走了 ......");
}
}
}
- 注册自定义 BeanPostProcessor 到容器,在容器关闭时会回调自定义的 BeanPostProcessor
public static void main(String[] args) {
// 1.创建并启动 ApplicationContext 容器, 使用注解配置
AnnotationConfigApplicationContext applicationContext = getApplicationContext();
// 2.注册自定义BeanPostProcessor,在bean销毁前调用
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
beanFactory.addBeanPostProcessor(new LifecycleDestructionPostProcessor());
// 3. 启动容器
applicationContext.refresh();
// 4. 关闭容器, 开始销毁bean, 此时会回调自定义BeanPostProcessor
applicationContext.close();
}
输出结果
tracccer被放走了 ......
tracccer被放走了 ......
源码分析
-
Bean 销毁的源码如下所示,会回调销毁方法,这里只关心第一种情况
- 回调DestructionAwareBeanPostProcessor#postProcessBeforeDestruction方法
- 回调实现接口DisposableBean 的 destroy() 方法
- 回调 bean 配置的销毁方法,包括 xml 和注解配置的
bean 在销毁前会回调自定义的 DestructionAwareBeanPostProcessor#postProcessBeforeDestruction 方法,与 9.11 章节Bean 初始化前的源码非常类似
DisposableBeanAdapter.java 适配器模式?
// 代码块15-1, 销毁方法
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
// 遍历所有DestructionAwareBeanPostProcessor
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
// 直接调用其postProcessBeforeDestruction()方法
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
try {
if (System.getSecurityManager() != null) {
// 安全处理,跳过
} else {
// 回调重写的DisposableBean#destroy方法
((DisposableBean) this.bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
}
}
if (this.destroyMethod != null) {
// 回调bean配置的销毁前方法
invokeCustomDestroyMethod(this.destroyMethod);
} else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
9.16 Bean 销毁
-
Bean 在销毁前,会依次回调下列方法:
- @PreDestroy 标记方法
- 实现 DisposableBean 接口的 destroy() 方法
- 自定义销毁方法
- xml 配置:
<bean destroy="xxx" /> - java 注解:
@Bean(destroy="xxx") - java api:
AbstractBeanDefinition#setInitMethodName(String)
- xml 配置:
详细使用参考 4.8 销毁 Bean 章节
主要用来优雅下线,删除缓存等。
1.@PreDestroy 的回调流程
- 首先构建一个 bean,使用 @PreDestroy 标记初始化方法
public class Teacher {
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy设置销毁方法: Teacher 销毁中...");
}
}
- 参考 6.17 章节,@PreDestroy 注解由
CommonAnnotationBeanPostProcessor进行处理,而且该类实现了 DestructionAwareBeanPostProcessor#postProcessBeforeDestruction方法,即和上一节中我们自定义的销毁前调用的 DestructionAwareBeanPostProcessor 作用一致,源码如下所示
// 代码块16-1
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
// 可以处理的注解, @PreDestroy
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
}
// 该方法会在bean销毁前被回调
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 底层是利用反射调用@PreDestroy 标记的方法
metadata.invokeDestroyMethods(bean, beanName);
} catch (Throwable ex) {
}
}
与 9.12.1 章节 @PostConstruct 的处理流程相对应
2. 其他销毁方法的回调过程
- 首先构建一个 bean,重写 DisposableBean#destroy 方法
public class Teacher implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("实现DisposableBean接口设置销毁方法: Teacher 销毁中...");
}
// 使用@Bean(destroyMethod="")标记该方法在销毁前调用
public void destroyTeacher() {
System.out.println("destroyMethod设置销毁方法: Teacher 销毁中...");
}
}
- 使用注解配置 bean,并设置初始化方法,然后创建容器并启动,容器会扫描到类中配置的 bean,初始化 bean 时会回调指定的初始化方法
public static void main(String[] args) {
// 1.创建并启动 ApplicationContext 容器, 使用注解配置
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanDestoryLifeCycleDemo2.class);
// 2. 启动容器
applicationContext.refresh();
// 3. 关闭容器, 开始销毁bean, 这里会回调销毁方法
System.out.println("=======Spring应用上下文开始关闭=======");
applicationContext.close();
}
@Bean(destroyMethod = "destroyTeacher")
public Teacher createTeacher() {
return new Teacher();
}
输出结果:说明 bean 销毁前回调了两个销毁方法
=======Spring应用上下文开始关闭=======
实现DisposableBean接口设置销毁方法: Teacher 销毁中...
destroyMethod设置销毁方法: Teacher 销毁中...
-
Bean 销毁的源码如下所示,会回调 5 种方式设置的销毁方法
-
回调自定义重写的DestructionAwareBeanPostProcessor#postProcessBeforeDestruction 方法
-
回调@PreDestroy 标记的销毁方法
-
回调实现接口DisposableBean 的 destroy() 方法
-
回调 bean 配置的销毁方法,包括 xml 和注解配置的
-
回调使用 api 为 bean 配置的销毁方法
比较巧妙的一点是,DisposableBeanAdapter 也是实现了接口 DisposableBean 的 destroy() 方法,所以 5 种设置回调销毁方法的方式,其本质底层都是使用 DisposableBean#destroy 实现的。
-
DisposableBeanAdapter.java 适配器模式?
// 代码块15-1, 销毁方法,重写了DisposableBean#destroy
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
// 遍历所有DestructionAwareBeanPostProcessor
// 包括自定义的实现和CommonAnnotationBeanPostProcessor
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
// 1.回调自定义的postProcessBeforeDestruction()方法
// 2.回调CommonAnnotationBeanPostProcessor的方法
// 见代码块16-1, 15-2
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
// 如果当前bean实现了DisposableBean接口
if (this.invokeDisposableBean) {
if (System.getSecurityManager() != null) {
// 安全处理,跳过
} else {
// 3.回调重写的DisposableBean#destroy方法
((DisposableBean) this.bean).destroy();
}
}
// 如果bean配置了destroyMethod
if (this.destroyMethod != null) {
// 4.回调bean配置的销毁方法,底层是通过反射实现的
invokeCustomDestroyMethod(this.destroyMethod);
} else if (this.destroyMethodName != null) {
// bean未配置destroyMethod, 但通过api设置了回调方法名称
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
// 5.回调java api配置的销毁方法
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
- 销毁 Bean 的时机:
- 在应用上下文关闭的时候
applicationContext.close(),最终会调用 DefaultListableBeanFactory 的destroyBean()方法销毁 Bean - 直接调用 DefaultListableBeanFactory 的
destroyBean()方法销毁指定的 Bean
- 在应用上下文关闭的时候
DefaultListableBeanFactory.java
protected void destroyBean(String beanName, DisposableBean bean) {
Set<String> dependencies;
synchronized (this.dependentBeanMap) {
// 将当前bean移除
dependencies = this.dependentBeanMap.remove(beanName);
}
if (dependencies != null) {
for (String dependentBeanName : dependencies) {
destroySingleton(dependentBeanName);
}
}
if (bean != null) {
try {
// 调用DisposableBean#destroy, 回调销毁方法
bean.destroy();
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
}
}
}
Set<String> containedBeans;
synchronized (this.containedBeanMap) {
// 将当前bean移除
containedBeans = this.containedBeanMap.remove(beanName);
}
if (containedBeans != null) {
for (String containedBeanName : containedBeans) {
destroySingleton(containedBeanName);
}
}
synchronized (this.dependentBeanMap) {
for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Set<String>> entry = it.next();
Set<String> dependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
}
// 将当前bean移除
this.dependenciesForBeanMap.remove(beanName);
}
destroyBean 会回调用 Bean 的销毁方法,destroySingletons 方法会清除 Spring BeanFactory 缓存的 Bean 对象
DefaultListableBeanFactory.java
public void destroySingleton(String beanName) {
// 删除单例bean对象, 见下面方法
removeSingleton(beanName);
// 回调bean的销毁方法
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);
}
protected void removeSingleton(String beanName) {
synchronized (this.singletonObjects) {
this.singletonObjects.remove(beanName);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.remove(beanName);
}
}
为什么调用了beanFactory.destroyBean("userHolder", userHolder) 销毁方法,不会从容器中移除呢。
答:destroyBean 操作仅是触发 Bean 销毁生命周期,因为 Bean 有可能再次被初始化,比如显示地调用 AbstractAutowireCapableBeanFactory#initializeBean(Object, String) 方法
9.17 Bean 垃圾回收
参考 4.8 章节
9.18 Bean 的生命周期总结
简单来说,Spring 框架中 Bean 经过 4 个节点:实例化 -> 属性赋值 -> 初始化 -> 销毁
-
实例化:new xxx(),读取到 bean 后使用 BeanDefinition 保存bean的信息,实例化有两个时机:
1. 当客户端向容器申请一个 bean 时
2. 当容器初始化一个 bean 时发现还需要依赖另一个 bean。
-
设置对象属性,即依赖注入,Spring 通过 BeanDefinition 找到对象依赖的其他对象,并将这些对象复制到当前对象的相应属性
-
处理 Aware 接口,Spring 会检测对象如果实现了 xxxAware 接口,会调用相应的方法。BeanNameAware,BeanFactoryWawre
-
BeanPostProcessor 前置处理,调用 BeanPostProcessor 的
postProcessBeforeInitialization()方法,会在每个 bean 实例化之前都调用 -
处理 InitializingBean 接口,Spring 会检测bean如果实现了该接口,就会调用
afterPropertiesSet()方法,定制初始化逻辑,在 bean 创建前调用 -
处理 init-method,
<bean init-method="xxx">如果 Spring 发现 Bean 配置了该属性,就会调用他的配置方法,执行初始化逻辑,与@PostConstruct类似 -
BeanPostProcessor 后置处理,调用 BeanPostProcessor 的
postProcessAfterInitialization()方法,会在每个 bean 实例化之后都调用到了这一步,bean 就可以正常被使用了
-
DestructionAwareBeanPostProcessor 处理程序,调用其
postProcessBeforeDestruction方法,会在每个 Bean 销毁前调用 -
处理
@PreDestroy注解,该注解配置了 Bean 销毁前的回调方法,Spring 内部实现了CommonAnnotationBeanPostProcessor,来回调该注解指定的销毁方法 -
处理 DisposableBean 接口,Spring 会检测bean如果实现了该接口,就会在对象销毁前调用
destory()方法。与 InitializingBean 接口相对应 -
处理 destory-method,
<bean destory-method="xxx">配置了销毁方法,如果 Spring 发现 Bean 配置了该属性,就会回调他指定的方法,执行销毁逻辑
看到一个有意思的评论,Spring的bean处理过程要留这么多扩展回调接口,四处漏风。
从设计模式的角度来看,这种编程方式符合对扩展开放,对修改关闭的原则,这样后面需要对 Bean 实例化初始化阶段进行任何修改,都不需要修改现有代码,缺点是使得 Bean 的处理过程变得较为复杂。
小知识:Spring 中 Processor 通常是处理已存在的对象,而 Resolver 通常是由 A 物变为 B 物,doXX() 则是实际执行业务逻辑的方法
9.19 面试题
-
BeanPostProcessor 使用场景有哪些?
答:BeanPostProcessor 提供 Spring Bean 初始化前和初始化后的生命周期回调,分别对应 postProcessBeforeInitialization 和 postProcessAfterInitialization,允许对 Bean 进行扩展修改,甚至是替换。
加分项:其中,ApplicationContext 相关的 Aware 回调也是基于 BeanPostProcessor 实现,即 ApplicationContextAwareProcessor。(回顾AbstractApplicationContext#prepareBeanFactory)
加分项:处理 @PostConstruct 注解的 CommonAnnotationBeanPostProcessor 类也是重写了 postProcessBeforeInitialization 方法,用来回调 @PostConstruct 标记的初始化方法。
扩展:BeanPostProcessor 接口还有 3 个经典子接口,MergedBeanDefinitionPostProcessor 负责BeanDefinition 的合并,InstantiationAwareBeanPostProcessor 会在 Bean 实例化前后被回调,DestructionAwareBeanPostProcessor 会在 Bean 销毁前被回调
-
BeanFactoryPostProcessor 与 BeanPostProcessor 的区别
答:BeanFactoryPostProcessor 是 Spring BeanFactory (实际为ConfigurableListableBeanFactory)的后置处理器,用于扩展 BeanFactory,或通过 BeanFactory 进行依赖查找和依赖注入。
加分项:BeanFactoryPostProcessor 必须由 ApplicationContext 执行,BeanFactory 无法与其直接交互。而 BeanPostProcessor 则直接与 BeanFactory 关联,属于 N 对 1 的关系
// 其实根本没学懂 BeanFactoryPostProcessor ,再回顾下前面章节吧
-
BeanFactory 是怎样处理 Bean 声明周期的?
答:参考 9.18 章节
1.注册bean Definition registerBeanDefinition() 2.bean Definition的合并阶段 getMergedLocalBeanDefinition(),比如user和superUser 最后都变为root bean Definition 3.创建bean createBean() 4.将bean类型从string变为class类型 resolveBeanClass() 5.bean实例化前工作resolveBeforeInstantiation(),比如可以返回自定义的bean对象让spring不在实例化bean对象 6.开始实例化bean doCreateBean() 7.实例化bean createBeanInstance() 8.bean实例化后 postProcessAfterInstantiation()返回false即bean不在对属性处理 9.属性赋值前对属性处理postProcessProperties() 10.属性赋值applyPropertyValues() 11.bean初始化阶段initializeBean() 12.初始化前aware接口回调(非ApplicationContextAware),比如beanFactoryAware 13.初始化前回调applyBeanPostProcessorsBeforeInitialization(),比如@PostConstructor 14.初始化invokeInitMethods(),比如实现InitializingBean接口的afterPropertiesSet()方法回调 15.初始化后的回调applyBeanPostProcessorsAfterInitialization() 16.bean重新的填充覆盖来更新bean preInstantiateSingletons() 17.bean销毁前postProcessBeforeDestruction() 18.bean销毁,比如@PreDestroy
// 这一章是重中之重,参考其他教程搞懂实例化部分,还有常用的生命周期回调方法的具体应用
// ! 重看Aware回调章节,实例化章节,初始化销毁部分还是简单呐^_^
// 再回顾下BeanDefinition 合并的章节, 看下MergedBeanDefinitionPostProcessor 的作用
// ConfigurableBeanFactory 的功能有注册 BeanPostProcessor,销毁bean