Spring实例化的基本流程
将xml中的bean标签封装到一个BeanDefinition对象中,然后将BeanDefinition对象存储到一个BeanDefinitionMap<String,BeanDefinition>集合中去,通过对BeanDefinitionMap进行遍历,使用反射创建bean示例对象存储到singletonObjects<String,Object>的map集合中,调用getBean(beanName)方法取出bean示例。
Spring后处理器
介入到bean的实例化过程中,实现动态注册BeanDefinition、动态修改BeanDifinition、动态修改BeanDefinition,Spring有两种后处理器:
(1)BeanFactoryPostProcessor:在BeanDefinition填充之后,bean实例化之前执行。
(2)BeanPostProcessor:在bean实例化之后,添加到singletonObjects之前执行。
BeanFactoryPostProcessor
BeanFactoryPostProcessor实现:写一个processor类实现接口,重写方法,将类配置到xml。
bean中的配置:
<!-- 后处理器 -->
<bean class="com.demo.processor.MyBeanFactoryPostProcessor"></bean>
案例:
(1)修改已经注册bean标签的beanName:通过beanFactory获取指定的beanDefinition进行更改
BeanDefinition userDaoBeanDefinition = beanFactory.getBeanDefinition("userDao");
userDaoBeanDefinition.setBeanClassName("com.demo.service.impl.UserServiceImpl");
(2)添加xml没有配置的bean信息:
new BeanDefinition的实现类对象,并填入参数,再注册到beanFactory
//类型强制转换(使用其中的方法)
BeanDefinition beanDefinition = new RootBeanDefinition("com.demo.dao.impl.PersonDaoImpl");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition);//注册
另外介绍一个实现类BeanDefinitionRegistryPostProcessor,他有两个方法,一个原来的postProcessBeanFactory,一个提供注册功能的postProcessBeanDefinitionRegistry
使用它实现注册
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition("com.demo.dao.impl.PersonDaoImpl");beanDefinitionRegistry.registerBeanDefinition("personDao",beanDefinition);//注册
}
各个后处理器以及方法的执行顺序
MyBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry
MyBeanDefinitionRegistryPostProcessor的postProcessBeanFactory
MyBeanFactoryPostProcessor的postProcessBeanFactory
案例:自定义注解扫描自动注入
案例:使用自定义注解,实现将加注解的类自动注册到beanDefinitionMap中。
自定义注解,类型是加到类上的,在运行时生效,可以指定一个String属性。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {String value();
}
注解使用:
@MyComponent("other")
public class OtherBean {
}
使用写好的工具类进行包扫描,最终返回包含指定注解的<beanName,反射对象>的map集合
最后实现后处理器并加到xml中,后处理器对获取到的map反射集合进行创建beanDefinition并注册。
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {//扫描使用注解的类,获取反射对象,构造beanDefinition并注册Map<String, Class> classMap = BaseClassScanUtils.scanMyComponentAnnotation("com.demo");//注解中的name、反射classMap.forEach((beanName,clazz)->{RootBeanDefinition beanDefinition = new RootBeanDefinition(clazz.getName());beanDefinitionRegistry.registerBeanDefinition(beanName,beanDefinition);});
}
BeanPostProcessor
Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。
两个方法postProcessBeforeInitialization和postProcessAfterInitialization
生命周期的执行顺序:实例化、后处理器BeforeInitialization、属性赋值、init初始化方法、后处理器AfterInitialization
同样后处理器也需要配置
<bean class="com.demo.processor.TimeLogPostProcessor"></bean>
案例:对每一个实例化bean的方法都增强记录日志
实现:
(1)对方法进行增强主要就是代理设计模式和包装设计模式;
(2)由于Bean方法不确定,所以使用动态代理在运行期间执行增强操作:
(3)在Bean实例创建完毕后,进入到单例池之前,使用Proxy代替真是的目标Bean
后处理器的实现代码
public class TimeLogPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//通过动态代理对实例的方法进行增强Object instance = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println(method.getName() + "方法startTime=" + LocalDateTime.now());Object result = method.invoke(bean, args);System.out.println(method.getName() + "方法endTime=" + LocalDateTime.now());return result;});return instance;}
}
结果:
构造函数执行了
afterPropertiesSet方法执行了
自定义初始化方法执行了
say方法startTime=2025-02-04T15:24:42.115
say方法endTime=2025-02-04T15:24:42.119
实例化总体流程的总结
Spring Bean生命周期
Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:
(1)Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
(2)Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充。执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的;
(3)Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。
由于Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段
(1)Spring Bean的初始化过程涉及如下几个过程
(2)Bean实例的属性填充
(3)Aware接口属性注入
(4)BeanPostProcessor的before()方法回调
(5)InitializingBean接囗的初始化方法回调
(5)自定义初始化方法init回调
(6)BeanPostProcessor的after()方法回调
Bean实例属性填充
Spring在进行属性注入时,会分为如下几种情况:
(1)注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去
(2)注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
(3)注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案。
循环依赖
循环依赖问题图解:
Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:
//最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
//单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
循环依赖源码流程剖析