前言
最近通过阅读 小傅哥 的手撕Spring系列文章,跟着源码敲了一遍。 此文通过Bean生命周期对简化版Spring的执行流程进行总结。
源码仓库 :https://gitee.com/ithuameng/small-spring
Bean 生命周期
Xml 配置文件与 Refresh 方法
- 准备 xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context">>
<!--目标对象-->
<bean id="userService" class="com.ithuameng.springframework.test.bean.UserService3"/>
<!--注册 BeanPostProcessor-->
<bean class="com.ithuameng.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<!--自定义环绕拦截-->
<bean id="beforeAdvice" class="com.ithuameng.springframework.test.advice.UserServiceBeforeAdvice"/>
<!--方法拦截器-->
<bean id="methodInterceptor"
class="com.ithuameng.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<property name="advice" ref="beforeAdvice"/>
</bean>
<!--pointcutAdvisor 切面配置-->
<bean id="pointcutAdvisor" class="com.ithuameng.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression" value="execution(* com.ithuameng.springframework.test.bean.IUserService.*(..))"/>
<property name="advice" ref="methodInterceptor"/>
</bean>
<context:component-scan base-package="com.ithuameng.springframework.test.bean"/>
</beans>
可以 自定义Bean,配置AOP代理,也可以 使用注解 @Component,通过 component-scan 来扫描。
- 测试方法使用 ClassPathXmlApplicationContext 加载 xml配置文件:
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(CLASSPATH_URL_PREFIX + "spring.xml");
// 注册虚拟机钩子
applicationContext.registerShutdownHook();
}
- 通过 ClassPathXmlApplicationContext 构造方法执行
Spring 核心方法 refresh:
@Override
public void refresh() throws BeansException {
// 1.创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2.获取 BeanFactory()
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 3.添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 4.在 Bean 实例化之前,执行 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory);
// 6. 初始化事件发布者
initApplicationEventMulticaster();
// 7. 注册事件监听器
registerListeners();
// 8.设置类型转换器、提前实例化单例 Bean对象
finishBeanFactoryInitialization(beanFactory);
// 9. 发布容器刷新完成事件
finishRefresh();
}
注:下文将通过这个 refresh 方法来解析各方面的执行流程。
BeanDefinition
一个 BeanDefinition 描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。主要目的是允许修改属性值和其他 Bean 元数据。
BeanDefinition 一些属性信息:
public class BeanDefinition {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
private Class beanClass;
private PropertyValues propertyValues; // Bean属性值
private String initMethodName; // Bean初始化方法
private String destroyMethodName; // Bean销毁方法
private String scope = SCOPE_SINGLETON; // Bean作用域
private boolean singleton = true;
private boolean prototype = false;
}
通过 refresh 方法第一行代码 refreshBeanFactory() 来加载 xml 中定义的 Bean 信息。
@Component 注解扫描
xml 使用了如下的组件扫描配置:
<context:component-scan base-package="com.ithuameng.springframework.test.bean"/>
Java 代码判断是否使用了 component-scan:
// 解析 context:component-scan 标签,扫描包中的类并提取相关信息,用于组装 BeanDefinition
Element componentScan = root.element("component-scan");
if (null != componentScan) {
String scanPath = componentScan.attributeValue("base-package");
if (StrUtil.isEmpty(scanPath)) {
throw new BeansException("The value of base-package attribute can not be empty or null");
}
scanPackage(scanPath);
}
通过Java代码对 xml 中配置的包路径进行扫描,判断是否有使用了 @Component 注解的类,若有则将其定义为 BeanDefinition 注册进 beanDefinitionMap 中:
public void doScan(String... basePackages) {
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : candidates) {
// 解析 Bean的作用域 singleton、prototype
String beanScope = resolveBeanScope(beanDefinition);
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
// 注册 Bean信息
registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);
}
}
// 注册处理注解的 BeanPostProcessor (@Autowired、@Value)
registry.registerBeanDefinition("internalAutowiredAnnotationProcessor",
new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
}
findCandidateComponents 方法如下:
/**
* 这里先要提供一个可以通过配置路径 basePackage=com.ithuameng.springframework.test.bean
* 通过这个方法就可以扫描到所有 @Component 注解的 Bean 对象了
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation(basePackage, Component.class);
for (Class<?> clazz : classes) {
candidates.add(new BeanDefinition(clazz));
}
return candidates;
}
解析 xml 自定义
xml 配置文件中,可以自定义各种各样的 Bean,使用 Java进行解析处理,将其注册到 beanDefinitionMap 中:
List<Element> beanList = root.elements("bean");
for (Element bean : beanList) {
String id = bean.attributeValue("id");
String name = bean.attributeValue("name");
String className = bean.attributeValue("class");
String initMethod = bean.attributeValue("init-method");
String destroyMethodName = bean.attributeValue("destroy-method");
String beanScope = bean.attributeValue("scope");
// 获取 Class,方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义 Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestroyMethodName(destroyMethodName);
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
// 读取属性并填充
List<Element> propertyList = bean.elements("property");
for (Element property : propertyList) {
// 解析标签:property
String attrName = property.attributeValue("name");
String attrValue = property.attributeValue("value");
String attrRef = property.attributeValue("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
// 判断 bean是否已经定义
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
BeanFactoryPostProcessor
Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean之前读取bean的定义(配置元数据),通过beanFactory可以获取bean的定义信息,并 可以修改bean的定义信息。
refresh方法中第四行代码执行 BeanFactoryPostProcessor 对 BeanDefinition 进行修改:
// 4.在 Bean 实例化之前,执行 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
方法中使用 BeanFactory 获取所有实现 BeanFactoryPostProcessor 接口的 Bean,执行其中的 postProcessBeanFactory 方法:
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
可以通知自定义 BeanFactoryPostProcessor 接口的实现类,进行对某个 BeanDefinition 进行修改,例如下面的实现类,对 userService 这个 Bean定义信息进行修改:
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
PropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.addPropertyValue(new PropertyValue("company", "改为:字节跳动"));
}
}
将其定义在 xml 配置文件中,交由 Spring IOC 管理:
<bean class="com.ithuameng.springframework.test.common.MyBeanFactoryPostProcessor"/>
BeanPostProcessor
BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。BeanPostProcessor的源码如下:
/**
* Spring 提供的扩展机制
* 在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象
* 这部分与后面要实现的 AOP 有着密切的关系
*
* @author ithuameng
* @date 2022-7-19
*/
public interface BeanPostProcessor {
/**
* 在 Bean 对象执行初始化方法之前,执行此方法
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* 在 Bean 对象执行初始化方法之后,执行此方法
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
其中 postProcessBeforeInitialization 方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization 方法会在每个bean对象的初始化方法调用之后被回调。
BeanPostProcessor 与 AOP 的实现有着密切的关系。
Bean实例化
Bean 实例化是整个 Bean生命周期中最为重要的地方,也是整个 IOC 与 AOP 体现所在。
创建 Bean 实例
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
提供了两种实例化 Bean 的方法,使用了策略模式进行算法选择:
// 默认使用 JDK 实例化 Bean对象
private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();
Bean 三级缓存
循环依赖问题
- 循环依赖主要分为这三种,自身依赖于自身、互相循环依赖、多组循环依赖。
- 无论循环依赖的数量有多少,循环依赖的本质是一样的。就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。
三级缓存就为了解决 Bean之间相互注入收发的循环依赖问题,一级缓存存放的是完整的 Bean 实例,二级缓存存放的是代理之后的 Bean 实例,三级缓存存放的是代理对象方法。
实例一个 Bean 首先需要向缓存中获取,如果缓存中已经有这个 Bean 则直接返回,没有则需要创建 Bean:
@Override
public Object getSingleton(String beanName) {
// 一级缓存
Object singletonObject = singletonObjects.get(beanName);
if (null == singletonObject) {
// 二级缓存
singletonObject = earlySingletonObjects.get(beanName);
if (null == singletonObject) {
// 三级缓存
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 把三级缓存中的代理对象中的真实对象获取出来,放入二级缓存中
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
上面使用策略算法实例化 Bean之后,将没有完全实例化的 Bean存放到第三级缓存中:
// 创建 Bean实例
bean = createBeanInstance(beanDefinition, beanName, args);
// 处理循环依赖,将实例化后的 Bean 对象提前放入缓存中暴露出来
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
}
从三级缓存中获取数据的时候,会使用 AOP 对实例的 Bean 对象进行代理,如果 AOP 没有进行配置,则会返回之前实例的 Bean 保存到 第二级缓存中,将第三级缓存中的数据删除。
Bean 填充属性
之前在介绍解析 xml 配置文件时,已经将 Bean的属性信息解析配置到 PropertyValue 中,不过还有一种是使用了注解的方式进行属性内容注入,例如 @Value,@Autowired 这两个注解,这个时候我们就需要手动的对使用了注解的属性进行解析:
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
// 1.处理注解 @Value
Class<?> clazz = bean.getClass();
clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
Value valueAnnotation = field.getAnnotation(Value.class);
if (null != valueAnnotation) {
String value = valueAnnotation.value();
value = beanFactory.resolveEmbeddedValue(value);
BeanUtil.setFieldValue(bean, field.getName(), value);
}
}
// 2. 处理注解 @Autowired
for (Field field : declaredFields) {
Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
if (null != autowiredAnnotation) {
Class<?> fieldType = field.getType();
String dependentBeanName = null;
Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);
Object dependentBean = null;
if (null != qualifierAnnotation) {
dependentBeanName = qualifierAnnotation.value();
dependentBean = beanFactory.getBean(dependentBeanName, fieldType);
} else {
dependentBean = beanFactory.getBean(fieldType);
}
BeanUtil.setFieldValue(bean, field.getName(), dependentBean);
}
}
return pvs;
}
解析完之后存放到 PropertyValues 中,就可以给 Bean 进行属性填充了:
// 属性填充
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
// Bean引用对象 获取容器中的 Bean
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 类型转换
else {
Class<?> sourceType = value.getClass();
Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
ConversionService conversionService = getConversionService();
if (conversionService != null) {
if (conversionService.canConvert(sourceType, targetType)) {
value = conversionService.convert(value, targetType);
}
}
}
// 反射设置属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
Aware 感知
Aware 感知指的是 Bean 实现某些接口,可以获取应用程序上下文中的一些对象信息,比如 BeanFactory、ClassLoader 等。
例如定义一个 BeanFactoryAware 的接口,标识需要获取 BeanFactory 对象信息:
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
spring 中的 AutowiredAnnotationBeanPostProcessor 类实现这个接口:
/**
* 扫描自定义注解
*
* @author ithuameng
* @date 2022-8-1
*/
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
执行 Bean的初始化方法时获取这些感知对象:
// spring容器 Aware感知
if (bean instanceof Aware) {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
}
这样就可以使用这些感知对象了。
Bean 对象的初始化方法
Bean 初始化方法来源于实现了 InitializingBean 接口或者是在 xml 中配置了 init-method 信息,调用 invokeInitMethods 执行 Bean的初始化方法:
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 1.Bean 实现了 InitializingBean接口
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2.配置信息 init-method
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
在执行这个初始化方法之前,将会执行 BeanPostProcessor Before 处理:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (null == current) {
return result;
}
result = current;
}
return result;
}
在执行这个初始化方法之后,将会执行 BeanPostProcessor After 处理:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (null == current) {
return result;
}
result = current;
}
return result;
}
Bean 对象的销毁方法
Bean 销毁方法来源于实现了 DisposableBean 接口或者是在 xml 中配置了 destroy-method 信息。我们需要在应用上下文中注册虚拟机钩子:
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
当程序关闭时,执行程序上下文中的 close 事件,调用 Bean 的 destory方法:
@Override
public void destroy() throws Exception {
// 1.bean实现接口 DisposableBean
if (bean instanceof DisposableBean) {
((DisposableBean) bean).destroy();
}
// 2.配置信息 destroy-method {判断是为了避免二次执行销毁}
if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
Method initMethod = bean.getClass().getMethod(destroyMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
总结
这个简化版 spring 还实现了容器事件和事件监听器,类型转换器等功能,具体的实现不一一演示。
此文用于记录 spring 中 Bean 的生命周期是如何进行的,用于巩固已学知识。
学海无涯,作者:浪子花梦,写于:2022 / 9 / 2