目录
1、Spring初始化bean
在我们的项目中会使用@Controller、@Service等注解方式或标签配置文件的形式向Spring容器注入各种bean,其本质是Spring框架扫描我们添加了@Controller、@Service等注解的类或解析标签的class属性利用java反射机制创建bean对象的过程。本篇主要从Spring源码级别,讨论Spring在创建bean对象后,Spring是如何调用各种初始化方法来初始化这个bean对象的。
2、BeanFactory的初始化Bean
2.1 BeanFactory接口和ApplicationContext接口
BeanFactory是Spring框架中最基本的一个接口,注意体会这个最字和接口。即这个接口是定义了一个bean容器的最基本功能方法,比如获取bean实例getBean()、获取bean实例的类型getType(),那么它的具体实现类有DefaultListableBeanFactory。
ApplicationContext是Spring框架中功能更加全面的,也是在我们的项目中经常能看到它的身影的一个接口。它继承了BeanFactory接口,是Spring更高一级的容器,它在BeanFactory的基础上提供了更多的功能,比如国际化、消息发送、AOP等,那么它的实现类有ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、
AnnotationConfigApplicationContext。
假如把我们的bean比作是一滴一滴的水,一个bean就是一滴水,那么BeanFactory就好比是一个能够盛水的水壶,能做到的只是简单的盛水,而ApplicationContext就是一个电水壶不仅能盛水,还能加热,水开了还能提示。比如我们的DefaultListableBeanFactory就是一个普通的玻璃水壶,而ClassPathXmlApplicationContext就是一个电水壶。
2.2 BeanFactory的初始化Bean
那么,BeanFactory的实现类AbstractAutowireCapableBeanFactory是如何初始化bean的呢?具体的初始化步骤如下图。
Spring容器就是按照这个步骤,一步一步的顺序进行bean的初始化代码执行,最终初始化完成交给给我们使用的。网上很多的博客都是每一个步骤简单解释了一下,然后就不了了之,只能让我去死记硬背这个流程,现在咱们看看spring源码是如何实现这个流程。如果让咱们自己写代码实现这个流程呢?
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
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 {
//1、对实现了BeanNameAware、BeanClassLoaderAware、
// BeanFactoryAware的bean进行处理
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//2、调用 bean后置处理器 的初始化前置方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//3、先调用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()) {
//4、调用 bean后置处理器 的初始化前置方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
//最后返回包装后的bean
return wrappedBean;
}
以上就是spring的BeanFactory初始化bean的源码,总共分为4步,源码中这4步的执行顺序决定了流程图的执行步骤,这次知道流程图是咋来的了吧。具体对应如下关系如下:
- invokeAwareMethods方法,对应流程图的(1)(2)(3)步,如果bean实现了BeanNameAware、BeanClassLoaderAware、 BeanFactoryAware的接口,则调用bean实现的相对应的set方法。
- applyBeanPostProcessorsBeforeInitialization方法,对应流程图的(4)步,将调用spring容器里的所有的实现了BeanPostProcessor接口的bean的
postProcessBeforeInitialization()方法。 - invokeInitMethods方法,如果bean实现了InitializingBean接口,则先调用bean实现的afterPropertiesSet()方法,对应(5)步;否则直接执行init-method属性指定的方法,对应第(6)步。
- applyBeanPostProcessorsAfterInitialization方法,对应流程图的第(7)步,将调用spring容器里的所有的实现了BeanPostProcessor接口的bean的
postProcessAfterInitialization()方法。
下面我依次分析这四个方法,并且将点出来其中的与spring相关的知识点。
2.3 Spring的Aware接口
Aware中文意思:知道、意识到。那么xxxAware接口就是知道XXX,比如BeanNameAware,如果我们的bean实现了BeanNameAware接口,就是让我们的bean通过重写的setBeanName方法知道beanName是什么,即Spring将beanName为参数调用bean重写的setBeanName方法,这样我们的bean便知道了beanName。同理我们项目中常用的ApplicationContextAware、BeanFactoryAware都有对应的set方法,让我们的bean知道applicationContext、beanFactory。有了这样的理解,咱们再看看invokeAwareMethods方法的源码。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
此段代码,只是依次判断bean是否实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口并调用对应的set方法。
2.4 BeanPostProcessor所有bean的后置处理器
BeanPostProcessor是一个接口,翻译成中文就是Bean后置处理器,什么作用呢?见名知意,用于扩展bean创建后的处理逻辑。这个接口只有两个方法分别是:
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 AAA实现了BeanPostProcessor接口,那么AAA的
postProcessBeforeInitialization见名知意,方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization同样见名知意,方法会在每个bean对象的初始化方法调用之后被回调。Spring的命名是多么的优雅!!!重点注意下每一个bean对象。
那么有咱们分析的AbstractAutowireCapableBeanFactory#initializeBean方法的源码决定了这两个方法的调用顺序,而applyBeanPostProcessorsBeforeInitialization方法就是真正的调用AAA实现的postProcessBeforeInitialization方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
2.4 InitializingBean接口和init-method属性
直接上源码,看看如果我们的bean实现了InitializingBean接口,或者定义了init-method属性,Spring会如何处理。
org.springframework.beans.factory.InitializingBean
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//1、判断bean是否实现了InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//执行afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
}
//判断是否指定init-method属性
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 执行用户通过init-method方法指定的自定义初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
如果我们的bean实现了InitializingBean接口,那么将先执行afterPropertiesSet方法,这个方法没有任何入参,只是单纯的执行初始化逻辑。之后会判断我们的bean有没有指定init-method属性,如果制定了将通过invokeCustomInitMethod方法来执行自定义的方法。
invokeCustomInitMethod方法的逻辑就是利用java反射机制来执行init-method指定的方法,这里偷个懒不做详细分析,Spring源码博大进深,请原谅一个辛苦码字的小伙子。
2.5 BeanPostProcessor的bean初始化后置方法
同2.3节相呼应,执行实现了BeanPostProcessor接口的bean的初始化后置方法
postProcessAfterInitialization方法,具体的源码如下
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
这里单独指出一点,BeanPostProcessor还具备一个包装、加工bean的功能,为什么这么说呢?BeanPostProcessor的两个方法postProcessBeforeInitialization、
postProcessAfterInitialization入参都是bean和beanName,并且返回值都是必须是bean,那么咱们就可以在BeanPostProcessor的实现类里,通过这两个方法操作bean,对bean进行一定的处理后返回。由源码
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
看这个变量名的中文含义:被包装的Bean,从这个变量的命名也能看出Spring设计BeanPostProcessor时想提供的包装的含义。
3、 总结
- 本文主要分析了实现了BeanFactory的接口,未实现ApplicationContext接口的简单容器的bean 初始化步骤,源码的执行顺序决定了下面的初始化bean初始化步骤,概括起来如下图:
- 针对Aware系列接口,如BeanNameAware、ApplicationContextAware、BeanFactoryAware的作用,我们的bean通过实现此类接口,通过上面分析的源码,Spring在初始化bean的时候来调用set方法进行赋值。
- BeanPostProcessor的字面意思是bean的后置处理器,所以这个接口的作用于所有bean的初始化流程,可以用于对每一个bean在初始化的时候做统一的处理。
- 最后,spring将先调用InitializingBean的afterPropertiesSet()方法,后调用用户自定义的初始化方法init-method属性指定的方法。
写在最后:写到这里,我相信已经能够完全理解Spring的BeanFactory是如何去初始化咱们的bean了,美中不足的是没有分析ApplicationContext的初始化流程,既然开了这个坑,以后分析。如果有啥不明白的,欢迎点赞留言,咱们可以探讨一番。