目錄
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的初始化流程,既然開了這個坑,以後分析。如果有啥不明白的,歡迎點贊留言,咱們可以探討一番。