前言:
Spring 自从诞生以来就一直都是 Java 开发框架中的佼佼者,Spring 也是在各大面试中经常被提及的一个点,所以掌握 Spring 是无法避免的一道坎。而在 Spring 中最重要的就是 IOC 容器,IOC 管理着大量的 Bean。那么这些 Bean 仅仅是被 Spring 实例化出来管理那么简单吗?肯定不是的,在实例化 Bean 的过程中,Spring 提供了大量的扩展点供开发者去定制自己的 Bean,那么我们应该如何去扩展这些 Bean 就是本篇文章的重点。
后置处理器
后置处理器 —— BeanPostProcessor ,这是 Spring 为扩展 Bean 提供的接口。在 Spring 中,不管是内部提供的,还是开发者提供的后置处理器都是该接口的一个实现类。
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。
其中
postProcessBeforeInitialization() 方法是在初始化 Bean 之前调用的,这里的初始化并不是指实例化,而是指这个 Bean 中定义的初始化回调方法,比如:InitializingBean 接口中的 afterPropertiesSet() 方法、@PostConstruct 修饰的方法。postProcessBeforeInitialization() 方法实在这些初始化回调方法执行之前执行。
而
postProcessAfterInitialization() 方法则是在初始化 Bean 之后调用。但是该方法在 FactoryBean 中也许会被执行两次,一次是因为 FactoryBean 本身执行的,另一个是因为 FactoryBean 创建的 Bean 执行的。后置处理器可以自行决定是否要为这两个 Bean 都执行该方法。
注册后置处理器
后置处理器在 Spring 中也是以 Bean 的形式存在的,所以后置处理器与我们放入 Spring 中的普通 Bean 并没有什么区别,都会被放入到 IOC 容器中进行管理。
那么 Spring 是在什么时候注册这些后置处理器的呢?我们自己又要怎么注册一个自定义的后置处理器呢?
首先来看第一个问题。Spring 是在什么时候注册了后置处理器?
Spring 在多个地方都有注册一些 BeanPostProcessor。第一个地方是在 ApplicationContext 的构造函数中:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 在构造函数中,注册了 6 个 BeanDefinition:
// 1.ConfigurationClassPostProcessor
// 2.AutowiredAnnotationBeanPostProcessor
// 3.CommonAnnotationBeanPostProcessor 支持 JSP-250 才会注册
// 4.PersistenceAnnotationBeanPostProcessor 支持 Jpa 才会注册
// 5.EventListenerProcessor
// 6.EventListenerFactory
this();
register(componentClasses);
refresh();
}
复制代码
在注释中有写出这里注册了 6 个 BeanDefinition,但是只有 2 - 4 才是真正的实现了 BeanPostProcessor 接口的后置处理器。注意这里仅仅是注册了 BeanDefinition,并不是真正实例化了这些后置处理器,这些后置处理器的实例化将会在后面进行。
真正注册这 3 个后置处理器的方法是:
registerAnnotationConfigProcessors()。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册 AutowiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 只有符合 JSR-250 规范才会注册 CommonAnnotationBeanPostProcessor
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 只有检测到 JPA 的情况下才会注册 PersistenceAnnotationBeanPostProcessor
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 EventListenerMethodProcessor
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
return beanDefs;
}
复制代码
第二、三个地方是在著名的 Refresh() 方法中,分别都已经进行了相关的注释。这里就不再贴出真正注册的那些语句了。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册了三个 BeanPostProcessor:
// ApplicationListenerDetector
// ApplicationContextAwareProcessor
// LoadTimeWeaverAwareProcessor 满足指定条件才会注册
prepareBeanFactory(beanFactory);
try {
// 注册了 1 个 BeanPostProcessor:
// ImportAwareBeanPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 注册了 1 个 BeanPostProcessor:
// ApplicationListenerDetector
// 实例化 BeanPostProcessor:
// AutowiredAnnotationBeanPostProcessor
// CommonAnnotationBeanPostProcessor
// ApplicationListenerDetector
// ......
// 注册的这些后置处理器必须是已经在上面的步骤中被转换为了 BeanDefinition
// 否则将无法被成功注册,注册成功的后置处理器将会在实例化 Bean 的时候使用
registerBeanPostProcessors(beanFactory);
// 实例化非懒加载的单例对象
finishBeanFactoryInitialization(beanFactory);
}
catch (BeansException ex) {
}
}
}
复制代码
我们通过上面的代码可以知道注册的都是 BeanPostProcessor 的 BeanDefinition,这只是一个承载 Bean 属性的一个类,但是并不是我们真正需要的那个 Bean。所以,我们还需要通过这些 BeanDefinition 来实例化我们真正的后置处理器对象。而这个操作就是在
registerBeanPostProcessors() 这个方法中进行的。该方法通过调用 getBean() 方法来实例化后置处理器,然后将它放到容器中。
小结
Spring 内部自身总共注册了 7 个后置处理器,这是 Spring
image.png上面的 7 个后置处理器都是最终注册进容器的,但是它们本身并不仅仅是实现了 BeanPostProcessor,它们本身还会实现很多的其他 BeanPostProcessor 的子接口。
比如:
AutowiredAnnotationBeanPostProcessor,它的 UML 图如下
[图片上传失败...(image-515450-1649422794920)]
通过 UML 图可以知道
AutowiredAnnotationBeanProcessor 实现了多个后置处理器接口,这些接口都是很重要的。
自定义后置处理器
自定义后置处理器非常的简单,我们之前说过,后置处理器跟我们普通的 Bean 都是被 IOC 容器管理的,所以我们只要让 Spring 能够扫描到我们的后置处理器即可。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行自定义后置处理器");
return bean;
}
}
复制代码
Spring 扫描到这个类之后,就会把该类当作一个后置处理器注册到我们的容器中。
如何扩展 Bean
我们要扩展 Bean,就要知道 Bean 的生命周期,而生命周期跟后置处理器是紧紧联系在一起的,所以我们要知道 Spring 在什么时候执行了哪些后置处理器,这些后置处理器的作用是什么?当我们了解了这些之后,我们就知道该如何去扩展 Bean 了。
Spring 总共有 9 个地方用到了后置处理器,这些后指出处理器都是在实例化 Bean 的过程中执行的。接下来我们就把这 9 处地方都找出来。
第一处
AbstractAutowireCapableBeanFactory::createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
// 代码片段 1
try {
// 第一个扩展点,可以在里面返回一个代理 bean
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
复制代码
// 代码片段 2
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
复制代码
主要是
resolveBeforeInstantiation() 方法里面会执行 InstantiationAwareBeanPostProcessor 这个后置处理器的 postProcessBeforeInstantiation() 方法,默认返回 null。
该方法的主要作用是返回一个 Bean 的实例。我们通过上面的代码片段 2 可知,如果这里返回一个 Bean,那么就会直接执行
InstantiationAwareBeanPostProcessor 这个后置处理器的 postProcessAfterInstantiation() 方法,默认返回传入的 Bean。当执行完整个 resolveBeforeInstantiation() 方法后,我们来看代码片段 1,它判断如果有返回值,就直接返回这个 Bean,这表示Bean 的创建过程将会停止。
因此,这个实例化 Bean 的生命周期到这里就结束了(不包括使用、销毁的生命周期),总共执行
InstantiationAwareBeanPostProcessor 里面的两个方法。
这个后置处理器的主要作用就是自己实例化 Bean,而不需要 Spring 帮我们进行实例化。也可以利用这个后置处理器返回 Bean 的代理。
总共有三个内部类实现了该后置处理器:
- ImportAwareBeanPostProcessor,未重写方法,返回默认值
- CommonAnnotationBeanPostProcessor ,未重写方法,返回默认值
- AutowiredAnnotationBeanPostProcessor,未重写方法,返回默认值
所以,默认情况下,是不会存在类被此后置处理器实例化返回一个 Bean。
第二处
AbstractAutowireCapableBeanFactory::determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName)
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}
复制代码
这里执行了第二个后置处理器
SmartInstantiationAwareBeanPostProcessor ,该后置处理器里面有一个方法 determineCandidateConstructors() ,此方法用于在实例化 bean 之前,决定实例化的 bean 使用的构造方法。默认返回 null,表示使用无参构造函数。
实现该接口的类只有一个:
- AutowiredAnnotationBeanPostProcessor,重写了该方法,用于选择合适的构造函数。
第三处
AbstractAutowireCapableBeanFactory::applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
复制代码
这里执行的是第三个后置处理器
MergedBeanDefinitionPostProcessor,该后置处理器的 postProcessMergedBeanDefinition() 方法是非常重要的,它在实例化 Bean 之后执行,主要是处理 Bean 中被指定注解修饰的字段、方法,如:@Autowired、@Value等等
它会获取到被上述注解修饰的字段、方法,然后将需要注入的对象封装并缓存起来,等到后面进行依赖注入的时候再从缓存中取出,并进行依赖注入。
实现了该接口的类有三个:
- CommonAnnotationBeanPostProcessor ,获取被 @WebServiceRef、@EJB、@Resource 修饰的对象,并缓存起来
- AutowiredAnnotationBeanPostProcessor ,获取被 @Autowired、@Value、@Inject 修饰的对象,并缓存起来
- ApplicationListenerDetector,如果 bean 的类型是 ApplicationListener,则将此 beanName 放入到 singletonNames 的 map 中
第四处
AbstractAutowireCapableBeanFactory::getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
复制代码
这里执行的后置处理器是
SmartInstantiationAwareBeanPostProcessor,该后置处理器的 getEarlyBeanReference 主要是用于解决依赖循环,只要的目的是为了延迟代理对象的创建,因为在解决依赖循环的过程中,会使用到三级缓存,而该方法会将要创建的 Bean 封装成一个 ObjectFactory 对象,存放到二级缓存中,当出现依赖循环时,就会从二级缓存中拿出该 ObjectFactory 对象,通过该对象去创建 Bean,这个 Bean 有可能是原始对象,也可能是代理对象。具体的过程可以看我的另外一篇文章 Spring 解决循环依赖必须要三级缓存吗?。
实现该接口的并重写了 getEarlyBeanReference 方法的类:
- AbstractAdvisorAutoProxyCreator 这是一个抽象类,所有的 AOP 都与它相关。
至此,Spring 已经完成了对 Bean 的实例化,现在还剩下两个步骤,一个是属性的填充,也就是依赖注入;另一个是初始化 Bean,也就是执行 Bean 中定义的初始化函数和接口方法。
第五处
AbstractAutowireCapableBeanFactory::populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
....
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
....
复制代码
这里执行的是
InstantiationAwareBeanPostProcessor,该后置处理器在第一处中也出现过,第一处中主要是执行 postProcessBeforeInstantiation() 方法,是在 Bean 实例化之前执行。而这里主要是执行 postProcessAfterInstantiation() 方法,实在 Bean 实例化之后,属性填充之前执行。它的返回值表示是否要跳过字段注入。
它的主要作用是可以让开发者自定义字段的注入,也就是字段的注入由开发者手动来完全,而不是 Spring 来帮我们自动注入。如果我们通过手动注入字段的话,那么后面的 Spring 自动注入将会不再执行。
该方法默认返回为 true,表示属性应该自动注入到 Bean 中;如果返回为 false,则表示跳过属性自动注入。
实现了该接口并重写
postProcessAfterInstantiation() 的类:
- CommonAnnotationBeanPostProcessor 但是它重写之后的返回值也为 true,不知道为什么要重写。
第六处
AbstractAutowireCapableBeanFactory::populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
....
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
....
复制代码
第六处依然是在 populateBean 方法中,依然也是
InstantiationAwareBeanPostProcessor 后置处理器,但是这次执行的方法是 postProcessProperties ,该方法的作用就是将 Bean 依赖的属性注入进来。
而 Bean 依赖了哪些属性已经在第三处的
MergedBeanDefinitionPostProcessor 后置处理器中获取并缓存起来,postProcessProperties() 方法只需要从缓存中获取到它的依赖了哪些属性,然后在容器中拿到这些属性的对象,注入到 Bean 中就可以了。
该后置处理器还有一个也是用于依赖注入的方法 postProcessPropertyValues(),但是该方法已经废弃。
第七、八处
AbstractAutowireCapableBeanFactory::initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 执行各种 Aware 接口的方法:BeanNameAware等
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 第七处后置处理器,执行 @PostConstruct
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行初始化方法,如:InitializingBean 接口中的 afterPropertiesSet 方法,init-method
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()) {
// 第八处后置处理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
复制代码
第七处的后置处理器是 BeanPostProcessor 接口的
postProcessBeforeInitialization() 方法,该方法是在初始化 Bean 之前调用,我们可以在这里方法里面去增强我们的对象,比如返回一个代理对象等。
BeanPostProcessor 接口是所有后置处理器的父接口,重写了该方法的类:
- ApplicationContextAwareProcessor,如果 bean 实现了如下接口,则会执行接口中的回调方法: EnvironmentAware EmbeddedValueResolverAware ResourceLoaderAware ApplicationEventPublisherAware MessageSourceAware ApplicationContextAware
- ImportAwareBeanPostProcessor,如果 bean 实现了 ImportAware,则会设置相关信息
- BeanPostProcessorChecker,直接返回 bean
- CommonAnnotationBeanPostProcessor,执行 @PostConstruct 注解的方法
第八处的后置处理器是 BeanPostProcessor 接口的
postProcessAfterInitialization() 方法,该方法在初始化 Bean 之后调用。Spring 默认为 Bean 创建代理也是在这个方法中(不存在依赖循环情况下,如果存在依赖循环则会通过第四处中创建的 ObjectFactory 提前为 Bean 创建代理)。
BeanPostProcessor 接口是所有后置处理器的父接口,重写了该方法的类:
- BeanPostProcessorChecker,打印日志,返回 bean
- ApplicationListenerDetector,如果 bean 实现 ApplicationListener,则将此 bean 添加进应用监听器中
第九处
后置处理器是
DestructionAwareBeanPostProcessor,该后置处理器主要执行 @PreDestroy 注解修饰的方法。
实现了该接口的类有:
- CommonAnnotationBeanPostProcessor 的父类 InitDestroyAnnotationBeanPostProcessor ,执行 @PreDestroy 注解修饰的方法。
总结
下面是 Spring 中 Bean 的生命周期,只有我们熟悉了生命周期,那么我们就可以根据自身业务在生命周期中进行扩展。
示例:Spring 实现 AOP 就是通过添加一个后置处理器来完成的。Spring 在一开始会注册一个后置处理器
AnnotationAwareAspectJAutoProxyCreator,该后置处理器会在第八处对需要进行代理的对象完成代理,并且返回代理对象。
[图片上传失败...(image-30b461-1649423004326)]
网友评论