天天看点

源码解析Spring Bean的生命周期一、生成bean的模型对象BeanDefinition二、创建Bean三、增强bean功能四、单例bean的销毁五、总结六、扩展章节:Bean后置处理器

源码解析Spring Bean的生命周期

  • 一、生成bean的模型对象BeanDefinition
  • 二、创建Bean
    • 2.1 实例化之前:加载类
    • 2.2 实例化之前:可以提前返回bean(很少用到)
    • 2.3 推断构造器并实例化
    • 2.4 BeanDefinition的后置处理(很少用到)
    • 2.5 填充属性(依赖注入)
  • 三、增强bean功能
    • 3.1 扩展点:Aware接口
    • 3.2、扩展点:初始化方法之前
    • 3.3 扩展点:初始化方法
    • 3.4 扩展点:初始化方法之后
  • 四、单例bean的销毁
  • 五、总结
  • 六、扩展章节:Bean后置处理器
    • 6.1 Spring中的Bean后置处理器
      • 6.1.1 典型例子之一:CommonAnnotationBeanPostProcessor
      • 6.1.2 典型例子之二:AnnotationAwareAspectJAutoProxyCreator
    • 6.2 BeanPostProcess的顺序

声明:下文中涉及的Spring源码都是Spring 5.3.7版本

Spring中用的最多的是单例bean,单例bean的创建、使用、销毁都是由Spring容器管理的,对于原型bean,spring只负责创建,在创建结束之后就不会再管了,销毁或释放资源都是要由开发者自己控制,所以我们经常说的"spring bean的生命周期"实际上指的是单例bean的生命周期。对于单例bean和原型bean以外类型的bean,由于使用的场景比较少,这里也不进行讲述。

Spring bean说到底也就是一个java对象,一个java对象的生命周期是什么样子的?首先通过构造器将对象实例化出来,如果构造器实例化的时候没有给属性赋值,在实例化之后还可以通过set方法给属性赋值,这之后就可以使用这个对象,使用完成之后被jvm回收掉。Spring bean也是java对象,所以和java对象一样spring bean的生命周期也离不开实例化 -> 使用 -> 最后销毁的过程,不过Spring作为一个功能全面、强大的框架,可以对bean的生命周期进行更细粒度的控制。除了实例化之外,还可以处理bean的依赖关系(依赖注入);可以对bean进行各种功能增强;也允许用户自定义一些初始化操作;对于单例bean来说,spring会将其保存在容器中,这样暂时使用完的bean不会被垃圾回收,下次使用的时候不需要再创建,而是直接获取。总之,Spring对bean的创建、使用、销毁进行了全面的接管,这也是IoC(控制反转)的具体体现。

详细来说我们可以把bean的生命周期分为如下几个阶段:

  • 1、扫描包并生成bean的建模对象BeanDefinition
  • 2、创建bean(包括bean的实例化和依赖注入)
  • 3、增强bean(通过各种扩展点进行功能增强)
  • 4、使用bean
  • 5、关闭Spring容器的时候销毁bean

按照这样的划分我们来看Spring bean完整的生命周期:

一、生成bean的模型对象BeanDefinition

BeanDefinitio即bean的建模器或者bean的定义器,它保存了一个Bean的所有信息,这些信息包括bean的属性、构造方法参数、显示依赖的Bean的名称(即@DependsOn注解中指定的bean名称)、是否单例、是否延迟加载、初始化和销毁方法等各种信息,Spring最终会根据BeanDefinition来创建对象。那BeanDefinition是什么时候创建的呢?

Spring容器在启动的时候会去扫描指定的包,识别出哪些类需要由spring接管,每扫描到一个类会生成一个MetadataReader对象,在这个对象中通过ASM框架(Java字节码操控框架,可以方便的解析出类中的所有元素:类名、方法、属性等,cglib动态代理底层也使用了ASM框架,其性能要远好于java反射)解析class文件,得到类的元数据信息和注解信息,通过这些信息就可以创建BeanDefinition对象了。这里要注意,扫描过程中获取的这些类本身没有进行类加载,所以这个时候jvm中还没有这些类的Class对象。

思考:
java中类的Class对象已经包含了类的各种信息,为什么还需要有一个专门的BeanDefinition来保存类的信息?

答案:
Class对象确实保存了一个类的所有信息,但是Spring实例化一个bean需要更多信息,比如是否懒加载,bean的scope,bean的依赖等等,这些是Class对象无法提供的,所以Spring专门设计了这样一个类来存储定义一个bean所需要的各种信息。
           

二、创建Bean

获取到bean的BeanDefinition之后就可以根据BeanDefinition创建bean了,Spring容器会按照字典序来创建非懒加载的这些Bean。

如果调试过这个创建的步骤,会发现Spring最终会调用到AbstractAutowireCapableBeanFactory类的createBean()方法,createBean()方法又会调用doCreateBean()方法,doCreateBean()还会调用initializeBean()方法,这三个方法执行结束,一个bean就真正意义的创建完成了,所以这三个方法非常重要,从这三个方法就可以了解创建bean和增强bean功能的整个过程。这里先贴出这三个方法的源码,省略了其中部分对理解生命周期不是特别重要的代码,比如异常处理之类的,然后对生命周期中重要的步骤进行了注释并标号,后面会对这些步骤详细讲解,可以对照来看。

AbstractAutowireCapableBeanFactory中第一个重要的方法——createBean:

// AbstractAutowireCapableBeanFactory中的createBean方法
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {

	RootBeanDefinition mbdToUse = mbd;
    // 1、进行类加载
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	...
    // 2、如果用户实现了InstantiationAwareBeanPostProcessor,则直接返回bean,并结束剩余创建流程(很少用到)
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
	
    // 调用doCreateBean方法,这是上面提到的第二个重要的方法
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	return beanInstance;
}
           

AbstractAutowireCapableBeanFactory中第二个重要的方法——doCreateBean:

// AbstractAutowireCapableBeanFactory中的doCreateBean方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {

	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
	    // 3、推断构造器并实例化bean
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	// Allow post-processors to modify the merged bean definition.
	if (!mbd.postProcessed) {
	    // 4、BeanDefinition的后置处理器,可以更改bean的属性等(很少用到)
		applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		mbd.postProcessed = true;
	}
    ... 
	Object exposedObject = bean;
	
    // 5、处理依赖关系(依赖注入)
	populateBean(beanName, mbd, instanceWrapper);
	// 调用initializeBean方法,这是上面提到的第三个重要的方法
	exposedObject = initializeBean(beanName, exposedObject, mbd);
	
	...
	return exposedObject;
}
           

AbstractAutowireCapableBeanFactory中第三个重要的方法——initializeBean:

// AbstractAutowireCapableBeanFactory中的initializeBean方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	} else {
	    // 6、执行aware接口(第一处扩展点)
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
	    // 7、执行bean后置处理器的前方法(第二处扩展点)
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

    // 8、执行初始化方法(第三处扩展点)
	invokeInitMethods(beanName, wrappedBean, mbd);
	
	if (mbd == null || !mbd.isSynthetic()) {
	    //  9、执行bean后置处理器的后方法(第四处扩展点)
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}
           

上面标号的注释就是创建bean和增强bean的九个步骤,其中第二和第四步很少用到,剩余的七个都很重要,下面具体来看。

2.1 实例化之前:加载类

在前面有提到,扫描类的时候并没有进行类加载,但是实例化一个对象就必须要先进行类加载,所以AbstractAutowireCapableBeanFactory类的createBean()方法中做的第一件事就是进行类加载,对应上面源码中标号为1的注释的位置:

// 1、resolveBeanClass方法进行类加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
           

2.2 实例化之前:可以提前返回bean(很少用到)

Spring允许不按照正常流程来创建一个Bean,开发者可以实现InstantiationAwareBeanPostProcessor接口,并在这个接口的postProcessBeforeInstantiation方法中返回一个Bean对象,如果这个对象不为空,就会结束剩余的创建流程,提前返回这个bean,这个bean如果是单例的话依然会放入到单例池中,只是不会进行依赖注入和功能增强。

// 2、提前返回bean,并结束生命周期
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
	return bean;
}
           

不过这种用法很少会用到,基本可以忽略这种用法。

2.3 推断构造器并实例化

实例化对象当然需要用到构造器,Spring可以推断构造器,选择合适的构造器来进行bean的实例化。

// 3、推断构造器并实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
           

推断构造方法其实没那么复杂:

如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。

如果有多个构造方法,其中一个是无参构造方法,其余的是有参构造方法,这些构造方法都没有@AutoWired注解,也没有在xml文件中进行设置,那么spring会默认选择无参构造方法。

如果有多个构造器,都是有参构造器,这些构造器上没有@AutoWired注解,也没有在xml文件中进行设置,spring启动时会报错。

如果只有一个有参构造器,这个构造器上没有@AutoWired注解,也没有在xml文件中进行设置,spring会看这个有参构造器的参数(可能是其它bean或者常量)是不是都能获取到,如果不能都获取到就会报错,如果都能获取到就会用这个构造器。

其它情况就看用户指定了哪个构造器,指定构造器有两种方式,一是通过@Autowired注解,二是通过xml中的<constructor-arg>标签来指定构造器参数,spring会根据参数来选择构造器,如果能找到一个合适的构造器,spring就会使用用户指定的构造器。但如果用户指定了多个构造器,比如在多个构造器上使用@Autowired注解或者通过xml标签不能推断出一个唯一的构造器,spring也会报错。

可能情况还不止上面这些,但是整体思路就是看spring能否找到一个不存在歧义的构造器(唯一的构造器或用户唯一指定的构造器),如果能找到,那么就使用这个构造器,如果找不到就看用户是否允许spring自动选择构造器,如果不允许就报错,如果允许就看spring自动选择的这个构造的参数是否都能获取到,如果都能获取到就会使用这个构造器,如果不能都获取到就会报错。

2.4 BeanDefinition的后置处理(很少用到)

在BeanDefinition的后置处理中可以修改BeanDefinition,但是此时实例对象已经生成好了,所以想通过修改beanClass来改变bean对象已经没用了,但是这个时候bean只是实例化出来,还没进行依赖注入,所以可以修改PropertyValues:

if (!mbd.postProcessed) {
	try {
	    // 4、BeanDefinition的后置处理器,可以更改bean的属性等
		applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
	}
	catch (Throwable ex) {
	    ...
	}
	mbd.postProcessed = true;
}
           

这种用法也很少会用到,基本可以忽略。

2.5 填充属性(依赖注入)

populateBean()方法进行了属性填充,所谓属性填充其实就是依赖注入,spring会先去容器中寻找依赖的bean,如果找到了就直接注入,如果没有找到就会去创建依赖的bean,所以这个方法是一个递归的入口,等依赖的bean创建完之后,会接着进行当前bean的属性注入。这里就涉及到spring bean循环依赖的问题,这是一个比较复杂的问题,用一个单独的篇章来讲,详见:源码解析Spring循环依赖

// 5、处理依赖关系(依赖注入)
populateBean(beanName, mbd, instanceWrapper);
           

上面创建bean的步骤细分有很多步,但如果粗略划分,其实最重要的只有两步:一是实例化,二是属性填充,这两步也是创建一个java对象的过程。

三、增强bean功能

在属性填充结束之后,从java的角度来说这个bean已经是一个完整的java对象,可以使用了。但是spring框架更进一步,通过各种扩展点来对bean的功能进行增强,这些扩展点都是用户可选的,并不是必须的。

3.1 扩展点:Aware接口

第一处扩展点就是Aware接口,Aware单词有"发现…/对…有兴趣"的含义,从名字就可以看出来aware接口让用户能够从spring容器中获取一些有用的、感兴趣的信息或对象。Aware接口的执行对应上面源码中标号为6的注释的位置:

// 6、执行aware接口(第一处扩展点)
invokeAwareMethods(beanName, bean);
           

Aware接口有很多,这里列举几个常见的:

  • BeanNameAware用于获取实现这个接口的bean的名称;
  • BeanFactoryAware用于获取beanFactory对象,beanFactory对象其实就是spring容器。
  • ApplicationContextAware用于获取aplicationContext对象(应用上下文),aplicationContext实现了beanFactory,所以aplicationContext也是spring容器。

beanFactory和aplicationContext是spring容器不同程度上的抽象,BeanFactory接口定义了容器应该具有的基础行为,只要一个类实现了BeanFactory接口,我们就可以称它为容器。ApplicationContext接口组合了BeanFactory接口和一些其它接口,所以ApplicationContext接口扩展了容器的行为,我们称实现了BeanFactory接口的类为容器,那么实现了ApplicationContext接口的类也是容器,只是这个容器会具有更多的行为,使用起来会更加方便。

一个正在运行的spring应用只会有一个容器,但是jvm中可以同时有beanFactory和aplicationContext对象,这是不矛盾的,这种情况下beanFactory对象是aplicationContext对象的一个属性,相当于aplicationContext对象静态代理了beanFactory对象,这属于实现上的细节。正因为jvm中可以同时有beanFactory和aplicationContext对象,所以我们可以在一个bean上同时实现BeanFactoryAware和ApplicationContextAware接口,虽然这么做没有意义。

@Component
public class BeanC implements BeanFactoryAware, ApplicationContextAware {
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
           

BeanFactoryAware和ApplicationContextAware接口可以让我们获取到spring容器,这其实是实现依赖查找的关键,所谓依赖查找就是事先不进行bean的注入,而是在需要使用的时候从容器中查找,既然要从容器中查找,那必然要先获取容器对象,这两个接口可以让我们获取容器对象。

3.2、扩展点:初始化方法之前

从通用的设计角度来说,一个框架可以允许用户在对象实例化完成之后执行一些操作,这些操作统一放在一个方法中,叫做初始化方法。Spring也一样,当spring将一个bean实例化完成之后,就会执行这个初始化方法。但是在这个初始化方法的前后还可以增加扩展点,做到全方位的可扩展,这就是bean后置处理器(BeanPostProcessor)的前方法和后方法,前方法就是初始化之前执行的方法,后方法是初始化之后执行的方法。

前方法的执行对应上面源码中标号为7的注释的位置:

// 7、执行bean后置处理器的前方法(第二处扩展点)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
           

由于Bean后置处理器是比较重要的一块功能,涉及的内容也很多,所以用一个单独的章节讲解,详细内容请跳转到第六章。

这里面有一个特别要关注的点是@PostConstruct注解,这个注解用于标注一个方法,这个方法会在在bean实例化结束之后执行一些操作,和初始化方法的作用是一样的,但是我们知道**@PostConstruct注解标注的方法会在初始化方法之前执行**,这可以在Spring实现这个注解的方式中找到原因。细心的小伙伴会发现这个注解是javax包中的注解,并不是Spring自己的注解,Spring使用了CommonAnnotationBeanPostProcessor这个bean后置处理器来处理javax包中常用的注解,@PostConstruct注解就是其中之一,而且是在前方法中去执行这个注解标注的方法,这就是为什么@PostConstruct注解标注的方法会在初始化方法之前执行的原因,在第六章有源码解析,可以跳转查看。

与之相对的是@PreDestroy注解,这个注解也是javax包中的注解,也通过CommonAnnotationBeanPostProcessor的前方法来处理,但是和@PostConstruct不一样,@PostConstruct标注的方法会在前方法中直接执行,而@PreDestroy不会直接执行,而是暂时保存起来等到bean销毁之前执行。

3.3 扩展点:初始化方法

Spring允许用户自定义一些操作,这些操作会在bean实例化完成之后执行,这些操作放在一个统一的方法中叫做初始化方法。

初始化方法有多种指定方式,这里列举最为常用的两种,第一种是实现InitializingBean接口,在这个接口的afterPropertiesSet()方法中定义初始化操作;第二种是在xml配置文件中通过init-method标签指定初始化方法,现在用xml配置文件的方式已经比较少了。这两种方式可以共存,会先执行在afterPropertiesSet()方法,然后执行init-method标签指定初始化方法,但是一般不会有人同时混用这两种方式。

初始化方法的执行对应上面源码中标号为8的注释的位置:

// 8、执行初始化方法(第三处扩展点)
invokeInitMethods(beanName, wrappedBean, mbd);
           

3.4 扩展点:初始化方法之后

初始化方法之后的扩展点就是bean后置处理器的后方法,这里典型的应用就是Spring AOP的功能实现,Spring AOP底层用的是动态代理,代理对象就是在Bean后置处理器的后方法中进行生成的,详细内容请跳转到第六章。

后方法的执行对应于上面源码中标号为9的注释的位置:

// 9、执行bean后置处理器的后方法(第四处扩展点)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
           

这一步执行完之后一个bean就真正意义的创建完成,如果是单例bean还会加入到单例池中,之后就可以真正使用了,直到最后在容器关闭的时候被销毁。

四、单例bean的销毁

容器销毁的时候会进行单例bean的销毁。可以想象一下,如果所有单例bean都没有定义销毁方法,那么容器只需要直接清空保存单例bean的缓存就可以了。但如果有一些单例bean定义了销毁方法,就需要找出这些单例bean,执行销毁方法,执行完之后再清空单例bean的缓存。所以先要找出那些定义了销毁方法的bean,然后执行这些销毁方法。有多种方式来定义销毁方法,这里列举最为常用的三种方式

  • a、使用@PreDestroy注解,在这个注解标注的方法中定义销毁操作
  • b、实现DisposableBean接口,在destroy()方法中定义销毁操作
  • c、在xml配置文件中使用destroy-method标签指定销毁方法

Spring使用了适配器模式来统一这些销毁方法的处理方式,这个适配器就是DisposableBeanAdapter,最终会在这个适配器中的destroy方法中来执行具体的销毁方法。

// DisposableBeanAdapter中的destroy方法
@Override
public void destroy() {
	if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
	    // 执行@PreDestroy注解标注的方法
		for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
			processor.postProcessBeforeDestruction(this.bean, this.beanName);
		}
	}

	if (this.invokeDisposableBean) {
		try {
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
					((DisposableBean) this.bean).destroy();
					return null;
				}, this.acc);
			}
			else {
			    // 执行DisposableBean接口的destroy()方法
				((DisposableBean) this.bean).destroy();
			}
		}
		catch (Throwable ex) {
			...
		}
	}

    // 执行xml标签中指定的销毁方法或者其他方式指定的销毁方法
	if (this.destroyMethod != null) {
		invokeCustomDestroyMethod(this.destroyMethod);
	} else if (this.destroyMethodName != null) {
		Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
		if (methodToInvoke != null) {
			invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
		}
	}
}
           

上面提到的三种销毁方法可以同时存在,先执行@PreDestroy标注的方法,然后执行DisposableBean接口的destroy()方法,最后执行xml中destry-method标签指定的销毁方法。当然没有必要同时混用这几中方法。

五、总结

Spring Bean是java对象的一种特例,所以和java对象一样需要实例化和填充属性,但是Spring作为框架还可以在bean实例化并填充属性之后进行各种功能增强。实例化、填充属性、增强功能这是Spring Bean生命周期最为主要的三个阶段,如果简略划分甚至可以把这三个阶段作为Spring Bean的生命周期。当然如果进一步细分就是如下五个阶段:

  • 1、扫描包并生成bean的建模对象BeanDefinition
  • 2、创建bean:这个阶段中spring推断bean的构造器进行实例化并完成依赖注入(实例化+填充属性)
  • 3、增强bean功能:包括Aware接口增强、bean后置处理器前后方法、初始化方法
  • 4、使用bean
  • 5、关闭spring容器的时候销毁bean

最后来看一看Spring Bean生命周期中有一些成对的接口或者注解,比如:

  • @PostConstruct和@PreDestroy
  • InitializingBean接口的afterPropertiesSet()方法和DisposableBean接口的destroy()方法
  • xml配置文件中的init-method和destroy-method标签

这些成对的接口或注解用于定义一些初始化操作和销毁操作,在使用上都是类似的,执行顺序上也是类似的,初始化时先执行@PostConstruct注解标注的方法,然后是afterPropertiesSet()方法,然后是init-method指定的方法;销毁时先执行@PreDestroy注解标注的方法,然后是destroy()方法,然后是destroy-method标签指定的方法。

六、扩展章节:Bean后置处理器

Spring允许一个bean实例化完成之后执行一些操作,这些操作统一放在一个方法中,叫做初始化方法,在这个初始化方法的前后还可以增加功能扩展点,这两个扩展点就是通过bean的后置处理器(BeanPostProcesser接口)来完成的,在初始化方法之前的扩展点对应的是BeanPostProcesser的postProcessBeforeInitialization()方法,为了便于描述可以简单称为bean后置处理器的前方法;初始化方法之后的扩展点对应的是BeanPostProcesser的postProcessAfterInitialization()方法,称为bean后置处理器的后方法。之所以叫做bean的后置处理器,是因为它是在bean实例化完成之后执行的。

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    @Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	
    //bean初始化方法调用后被调用
    @Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}
           

可以看到BeanPostProcesser是一个接口,开发者可以自己实现BeanPostProcesser接口来对bean进行某种功能的增强。但是BeanPostProcesser接口和Aware接口不一样,Aware接口是bean直接继承的,影响的只有实现接口的这一个bean,而BeanPostProcesser接口是需要单独实现的,影响的是所有的用户bean,Spring启动的时候会先注册所有的bean后置处理器,然后创建bean,所以一旦一个BeanPostProcesser注册成功就会在所有bean的创建过程中执行。

比如按如下代码自定义一个Bean后置处理器:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + ": Exec before init");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + ": Exec after init");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
           

那么所有的bean在创建过程中都会打印日志。

6.1 Spring中的Bean后置处理器

BeanPostProcesser是一个接口,我们可以自己实现这个接口,用于在bean初始化方法之前和之后进行功能增强。另一方面,Spring本身也运用这个接口来实现一些功能。典型的例子就是CommonAnnotationBeanPostProcessor和AnnotationAwareAspectJAutoProxyCreator,这两个类都实现了BeanPostProcessor接口,所以都是Bean后置处理器,但是要注意这两个类还实现了其它接口,功能是复杂的,并不是单纯的Bean后置处理器。

6.1.1 典型例子之一:CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor这个类用来处理javax包中扩展的注解,这些注解包括@Resource、@WebServiceRef、@EJB、@PostConstruct、@PreDestroy,这五个注解中最为常用的是@Resource、@PostConstruct、@PreDestroy,但是这5个注解中只有@PostConstruct和@PreDestroy这两个注解用到了Bean后置处理器接口,看源码:

// CommonAnnotationBeanPostProcessor继承了InitDestroyAnnotationBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor中有前方法和后方法的具体实现:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 在bean的class中寻找是否有@PostConstruct和@PreDestroy这两个注解,构造LifecycleMetadata对象
	LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
	try {
	    // 如果有@PostConstruct注解,将直接执行这个注解标注的方法
		metadata.invokeInitMethods(bean, beanName);
	}
	catch (InvocationTargetException ex) {
		...
	} catch (Throwable ex) {
		...
	}
	return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	return bean;
}
           

可以看到CommonAnnotationBeanPostProcessor的前方法中扫描了bean的Class对象,看其中是否有@PostConstruct和@PreDestroy这两个注解,然后构造出LifecycleMetadata对象。如果有@PostConstruct注解,这个注解标注的方法还会在前方法中立刻执行,@PreDestroy则是在bean销毁之前执行。

其它的三个注解则没有通过Bean后置处理器的前后方法进行处理,之前说过CommonAnnotationBeanPostProcessor是复杂的,不仅实现了BeanPostProcessor接口,也实现了其它接口,这几个注解是通过其它接口定义的方法实现的,有兴趣可以去看源码,这里聚焦于Bean后置处理器的功能,所以不进行展开。

我们知道@Resource注解和@Autowired注解对应,都用于进行依赖注入,@Resource通过CommonAnnotationBeanPostProcessor来实现,@Autowired则是通过AutowiredAnnotationBeanPostProcessor来实现的,这个类用来处理@AutoWired、@Values、 java.inject.Inject这三个注解,AutowiredAnnotationBeanPostProcessor同样继承了BeanPostProcessor这个接口,所以也是bean后置处理器,但是看源码就会发现这个Bean后置处理器的前、后方法都是空方法,所以这些注解的功能都是通过其它接口定义的方法来实现的,之所以要把这个类定义为Bean的后置处理器只是为了统一处理:Spring在启动的时候会先扫描所有的Bean后置处理器并注册,这个过程中会把AutowiredAnnotationBeanPostProcessor给注册进去。

@Resource注解和@Autowired注解不使用bean后置处理器来实现的原因也很容易理解,这两个注解是用来进行依赖注入的,spring创建bean的时候是先处理依赖注入(populateBean方法),然后才会执行bean后置处理器的前后方法(initializeBean方法),如果这两个注解使用bean后置处理器来实现和创建bean的流程矛盾了。

6.1.2 典型例子之二:AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator用于实现Spring的AOP功能。我们知道Spring的AOP底层用的是动态代理技术,这意味着在Spring容器中最终保存的应该是增强过后的代理对象,而不是原始的对象,那Spring是怎么做到这一点的呢?其实就是用到了BeanPostProcesser接口,在BeanPostProcesser接口的后方法中判断当前bean是否需要植入切面逻辑,如果需要就生成一个代理对象。这个实现了BeanPostProcesser接口的类是AnnotationAwareAspectJAutoProxyCreator,看源码:

// AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator,在这个类中有后方法的实现
@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 有关循环依赖
			    // 如果检测到aop的设置,则创建代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
           

这里还牵扯到循环依赖相关的事项,这里不进行展开,有单独的篇章讲解,见:源码解析Spring循环依赖

6.2 BeanPostProcess的顺序

从上面的讲解可以看到Spring框架本身已经有了很多bean后置处理器,开发者自己也可以定义很多bean后置处理器,那这些bean后置处理器的执行顺序是什么样的呢?我们来看注册Bean后置处理器的实现逻辑,其实原本的注释已经解释的很详细了:

// 注册方法在PostProcessorRegistrationDelegate这个工具类中
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    // 处理bean后置处理器的主要思路是将bean后置处理器进行分离,将实现了PriorityOrdered接口、Ordered接口的bean后置处理器和剩余的进行分离,分别排序之后再分别向spring容器注册
	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

    // 首先注册实现了PriorityOrdered接口的bean后置处理器,这包括AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor
	// First, register the BeanPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    // 然后注册实现了Ordered接口的bean后置处理器,这包括AnnotationAwareAspectJAutoProxyCreator
	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    // 然后注册剩余的bean后置处理器,包括用户自定义的普通bean后置处理器(没有实现PriorityOrdered接口和Ordered接口),这些后置处理器按加载的顺序放入到list中,加载是按照字典序加载的,所以这里的顺序也是字典序
	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    // 最后重新注册internalPostProcessors中的bean后置处理器,也就是那些实现了MergedBeanDefinitionPostProcessor接口的bean后置处理器,包括AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor,重新注册会将这些bean后置处理器从列表的前面移除,然后放到列表的最后。
	// Finally, re-register all internal BeanPostProcessors.
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
           

上面代码关键步骤我添加了中文注释,处理bean后置处理器的主要思路是将bean后置处理器进行分离,将实现了PriorityOrdered接口、Ordered接口的Bean后置处理器和剩余的进行分离,分别排序之后再分别向spring容器注册,所谓注册就是将这些Bean后置处理器放入到容器中的一个List中去,这里要注意都是是先排序再注册,放入到容器中的list之后不会再进行排序,也就是说先注册的必然在list的前面。

AnnotationAwareAspectJAutoProxyCreator的order是Ordered.LOWEST_PRECEDENCE(值为2147483647),是最低的优先级;CommonAnnotationBeanPostProcessor也是这个值,也是最低的优先级;AutowiredAnnotationBeanPostProcessor是Ordered.LOWEST_PRECEDENCE - 2,比CommonAnnotationBeanPostProcessor略高一点;用户自定义的bean后置处理器一般不会实现PriorityOrdered接口和Ordered接口,则是按照加载的顺序排序,也就是字典序。按照源码执行的流程,容器中bean后置处理器最终的顺序是:

  • 1、AnnotationAwareAspectJAutoProxyCreator(用于AOP生成代理对象)
  • 2、用户自定义的bean后置处理器
  • 3、AutowiredAnnotationBeanPostProcessor
  • 4、CommonAnnotationBeanPostProcessor(处理@PostConstruct等注解)