Spring Bean 元信息配置阶段
BeanDefinition 配置
• 面向资源
- XML 配置
- Properties 资源配置
public class BeanMetadataConfigurationDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 实例化基于 Properties 资源 BeanDefinitionReader
PropertiesBeanDefinitionReader beanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
String location = "META-INF/user.properties";
// 基于 ClassPath 加载 properties 资源
Resource resource = new ClassPathResource(location);
// 指定字符编码 UTF-8
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
// 通过 Bean Id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
}
• 面向注解
• 面向 API
Spring Bean 元信息解析阶段
• 面向资源 BeanDefinition 解析
- BeanDefinitionReader
- XML 解析器 - BeanDefinitionParser
• 面向注解 BeanDefinition 解析
- AnnotatedBeanDefinitionReader
/**
* 注解 BeanDefinition 解析示例
*/
public class AnnotatedBeanDefinitionParsingDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 基于 Java 注解的 AnnotatedBeanDefinitionReader 的实现
AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);
int beanDefinitionCountBefore = beanFactory.getBeanDefinitionCount();
// 注册当前类(非 @Component class)
beanDefinitionReader.register(AnnotatedBeanDefinitionParsingDemo.class);
int beanDefinitionCountAfter = beanFactory.getBeanDefinitionCount();
int beanDefinitionCount = beanDefinitionCountAfter - beanDefinitionCountBefore;
System.out.println("已加载 BeanDefinition 数量:" + beanDefinitionCount);
// 普通的 Class 作为 Component 注册到 Spring IoC 容器后,通常 Bean 名称为 annotatedBeanDefinitionParsingDemo
// Bean 名称生成来自于 BeanNameGenerator,注解实现 AnnotationBeanNameGenerator
AnnotatedBeanDefinitionParsingDemo demo = beanFactory.getBean("annotatedBeanDefinitionParsingDemo",
AnnotatedBeanDefinitionParsingDemo.class);
System.out.println(demo);
}
}
Spring Bean 注册阶段
• BeanDefinition 注册接口: BeanDefinitionRegistry
Spring BeanDefinition 合并阶段
• BeanDefinition 合并
- 父子 BeanDefinition 合并
- 当前 BeanFactory 查找
- 层次性 BeanFactory 查找
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- Root BeanDefinition 不需要合并,不存在 parent -->
<!-- 普通 beanDefinition GenericBeanDefinition -->
<!-- 经过合并后 GenericBeanDefinition 变成 RootBeanDefinition -->
<bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="小马哥"/>
<property name="city" value="HANGZHOU"/>
<property name="workCities" value="BEIJING,HANGZHOU"/>
<property name="lifeCities">
<list>
<value>BEIJING</value>
<value>SHANGHAI</value>
</list>
</property>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
<!-- 普通 beanDefinition GenericBeanDefinition -->
<!-- 合并后 GenericBeanDefinition 变成 RootBeanDefinition,并且覆盖 parent 相关配置-->
<!-- primary = true , 增加了一个 address 属性 -->
<bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="杭州"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
/**
* BeanDefinition 合并示例
*/
public class MergedBeanDefinitionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 基于 XML 资源 BeanDefinitionReader 实现
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String location = "META-INF/dependency-lookup-context.xml";
// 基于 ClassPath 加载 XML 资源
Resource resource = new ClassPathResource(location);
// 指定字符编码 UTF-8
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
// 通过 Bean Id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
User superUser = beanFactory.getBean("superUser", User.class);
System.out.println(superUser);
}
}
Spring Bean Class 加载阶段
• ClassLoader 类加载
• Java Security 安全控制
• ConfigurableBeanFactory 临时 ClassLoader
Spring Bean 实例化阶段
实例化方式
• 传统实例化方式
- 实例化策略 - InstantiationStrategy
• 构造器依赖注入
Spring Bean 实例化前阶段
非主流生命周期 - Bean 实例化前阶段
• InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
Spring Bean 实例化后阶段
Bean 属性赋值(Populate)判断
• InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
/**
* Bean 实例化生命周期示例
*/
public class BeanInstantiationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
System.out.println("--------------------------------");
executeApplicationContext();
}
private static void executeBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 方法一:添加 BeanPostProcessor 实现 MyInstantiationAwareBeanPostProcessor
// beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 方法二:将 MyInstantiationAwareBeanPostProcessor 作为 Bean 注册
// 基于 XML 资源 BeanDefinitionReader 实现
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"META-INF/dependency-lookup-context.xml", "META-INF/bean-constructor-dependency-injection.xml"};
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(locations);
System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
// 通过 Bean Id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
User superUser = beanFactory.getBean("superUser", User.class);
System.out.println(superUser);
// 构造器注入按照类型注入,resolveDependency
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
private static void executeApplicationContext() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
String[] locations = {"META-INF/dependency-lookup-context.xml", "META-INF/bean-constructor-dependency-injection.xml"};
applicationContext.setConfigLocations(locations);
// 启动应用上下文
applicationContext.refresh();
User user = applicationContext.getBean("user", User.class);
System.out.println(user);
User superUser = applicationContext.getBean("superUser", User.class);
System.out.println(superUser);
// 构造器注入按照类型注入,resolveDependency
UserHolder userHolder = applicationContext.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
// 关闭应用上下文
applicationContext.close();
}
}
Spring Bean 属性赋值前阶段
• Bean 属性值元信息
- PropertyValues
• Bean 属性赋值前回调
- Spring 1.2 - 5.0:InstantiationAwareBeanPostProcessor#postProcessPropertyValues
- Spring 5.1:InstantiationAwareBeanPostProcessor#postProcessProperties
Spring Bean Aware 接口回调阶段
• Spring Aware 接口
• BeanNameAware
• BeanClassLoaderAware
• BeanFactoryAware
• EnvironmentAware
• EmbeddedValueResolverAware
• ResourceLoaderAware
• ApplicationEventPublisherAware
• MessageSourceAware
• ApplicationContextAware
Spring Bean 初始化
Spring Bean 初始化前阶段
• 已完成
- Bean 实例化
- Bean 属性赋值
- Bean Aware 接口回调
• 方法回调
- BeanPostProcessor#postProcessBeforeInitialization
Spring Bean 初始化阶段
Bean 初始化(Initialization)
• @PostConstruct 标注方法
• 实现 InitializingBean 接口的 afterPropertiesSet() 方法
• 自定义初始化方法
Spring Bean 初始化后阶段
方法回调
• BeanPostProcessor#postProcessAfterInitialization
Spring Bean 初始化完成阶段
方法回调
• Spring 4.1 +:SmartInitializingSingleton#afterSingletonsInstantiated
class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals("superUser", beanName) && SuperUser.class.equals(beanClass)) {
// 把配置完成 superUser Bean 覆盖
return new SuperUser();
}
return null; // 保持 Spring IoC 容器的实例化操作
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals("user", beanName) && User.class.equals(bean.getClass())) {
User user = (User) bean;
user.setId(2L);
user.setName("mercyblitz");
// "user" 对象不允许属性赋值(填入)(配置元信息 -> 属性值)
return false;
}
return true;
}
// user 是跳过 Bean 属性赋值(填入)
// superUser 也是完全跳过 Bean 实例化(Bean 属性赋值(填入))
// userHolder
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
// 对 "userHolder" Bean 进行拦截
if (ObjectUtils.nullSafeEquals("userHolder", beanName) && UserHolder.class.equals(bean.getClass())) {
// 假设 <property name="number" value="1" /> 配置的话,那么在 PropertyValues 就包含一个 PropertyValue(number=1)
final MutablePropertyValues propertyValues;
if (pvs instanceof MutablePropertyValues) {
propertyValues = (MutablePropertyValues) pvs;
} else {
propertyValues = new MutablePropertyValues();
}
// 等价于 <property name="number" value="1" />
propertyValues.addPropertyValue("number", "1");
// 原始配置 <property name="description" value="The user holder" />
// 如果存在 "description" 属性配置的话
if (propertyValues.contains("description")) {
// PropertyValue value 是不可变的
// PropertyValue propertyValue = propertyValues.getPropertyValue("description");
propertyValues.removePropertyValue("description");
propertyValues.addPropertyValue("description", "The user holder V2");
}
return propertyValues;
}
return null;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals("userHolder", beanName) && UserHolder.class.equals(bean.getClass())) {
UserHolder userHolder = (UserHolder) bean;
// UserHolder description = "The user holder V2"
userHolder.setDescription("The user holder V3");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals("userHolder", beanName) && UserHolder.class.equals(bean.getClass())) {
UserHolder userHolder = (UserHolder) bean;
// init() = The user holder V6
// UserHolder description = "The user holder V6"
userHolder.setDescription("The user holder V7");
}
return bean;
}
}
/**
* Bean 初始化生命周期示例
*/
public class BeanInitializationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
}
private static void executeBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 添加 BeanPostProcessor 实现 MyInstantiationAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
// 添加 CommonAnnotationBeanPostProcessor 解决 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"META-INF/dependency-lookup-context.xml", "META-INF/bean-constructor-dependency-injection.xml"};
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(locations);
System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
// 显示地执行 preInstantiateSingletons()
// SmartInitializingSingleton 通常在 Spring ApplicationContext 场景使用
// preInstantiateSingletons 将已注册的 BeanDefinition 初始化成 Spring Bean
beanFactory.preInstantiateSingletons();
// 通过 Bean Id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
User superUser = beanFactory.getBean("superUser", User.class);
System.out.println(superUser);
// 构造器注入按照类型注入,resolveDependency
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
}
Spring Bean 销毁
Spring Bean 销毁前阶段
方法回调
• DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
Spring Bean 销毁阶段
• @PreDestroy 标注方法
• 实现 DisposableBean 接口的 destroy() 方法
• 自定义销毁方法
Spring Bean 垃圾收集
Bean 垃圾回收(GC)
• 关闭 Spring 容器(应用上下文)
• 执行 GC
• Spring Bean 覆盖的 finalize() 方法被回调
面试题
BeanPostProcessor 的使用场景有哪些?
答:BeanPostProcessor 提供 Spring Bean 初始化前和初始化后的生命周期回调,分别对应 postProcessBeforeInitialization 以及postProcessAfterInitialization 方法,允许对关心的 Bean 进行扩展,甚至是替换。
加分项:其中,ApplicationContext 相关的 Aware 回调也是基于BeanPostProcessor 实现,即 ApplicationContextAwareProcessor。
BeanFactoryPostProcessor 与BeanPostProcessor 的区别
答:BeanFactoryPostProcessor 是 Spring BeanFactory(实际为ConfigurableListableBeanFactory) 的后置处理器,用于扩展BeanFactory,或通过 BeanFactory 进行依赖查找和依赖注入。
加分项:BeanFactoryPostProcessor 必须有 Spring ApplicationContext 执行,BeanFactory 无法与其直接交互。
而 BeanPostProcessor 则直接与BeanFactory 关联,属于 N 对 1 的关系。
BeanFactory 是怎样处理 Bean 生命周期?
答:
BeanFactory 的默认实现为 DefaultListableBeanFactory,其中 Bean生命周期与方法映射如下:
• BeanDefinition 注册阶段 - registerBeanDefinition
• BeanDefinition 合并阶段 - getMergedBeanDefinition
• Bean 实例化前阶段 - resolveBeforeInstantiation
• Bean 实例化阶段 - createBeanInstance
• Bean 初始化后阶段 - populateBean
• Bean 属性赋值前阶段 - populateBean
• Bean 属性赋值阶段 - populateBean
• Bean Aware 接口回调阶段 - initializeBean
• Bean 初始化前阶段 - initializeBean
• Bean 初始化阶段 - initializeBean
• Bean 初始化后阶段 - initializeBean
• Bean 初始化完成阶段 - preInstantiateSingletons
• Bean 销毁前阶段 - destroyBean
• Bean 销毁阶段 - destroyBean