Spring源碼原理篇(一)

Spring源碼原理篇--容器初始化&Bean後置處理器

本篇主要是講解IOC容器初始化過程當中大致進行了哪一些工做,以及Bean後置處理器的工做原理和BeanPostProcessor在底層的使用。

環境準備

  • 編譯器IDEA
  • maven依賴spring-context version:4.3.12.RELEASE
  • maven依賴junit version:4.11

BeanPostProcessor工做原理

實現BeanPostProcessor接口的組件,而且在兩個方法體內打上斷點:spring

public class BeanPostProcessorDefinition implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization -->"+s+" = "+o);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessorAfterInitialization -->"+s+"="+o);
        return o;
    }
}

調試後查看方法調用棧以下(如圖1):
圖片描述app

在方法調用棧中的initializeBean(初始化Bean)方法中,有下面一段相似的僞代碼:maven

initializeBean(param){
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
...
invokeInitMethods(beanName, wrappedBean, mbd);
...
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

這段僞代碼的大體意思就是先執行bean初始化以前的方法,而後執行bean初始化方法,最後執行初始化後的方法。
applyBeanPostProcessorsBeforeInitialization也是屬於方法調用棧的一環,進去有相似一段僞代碼:ide

applyBeanPostProcessorsBeforeInitialization(param)
            throws BeansException {
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

這段代碼經過遍歷獲得全部的BeanPostProcessor,而後挨個執行重寫的postProcessBeforeInitialization方法,假若有一個方法返回的bean爲null,那麼循環就會跳出,意味着下面的postProcessBeforeInitialization方法不會被執行。在初始化方法後執行的applyBeanPostProcessorsAfterInitialization同理也是同樣的。
大體總結後置處理器處理Bean初始化的過程(如圖2):
圖片描述工具

容器初始化流程

談到spring的IOC容器都離不開兩個接口BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,他們均可以表明spring容器。
圖1打斷點所示的方法調用棧能夠用來分析容器初始化所進行的工做(以AnnotationConfigApplicationContext獲取容器爲例):源碼分析

  • init:註冊配置類,調用refresh()刷新容器
  • refresh過程:post

    • registerBeanPostProcessors(Param)註冊Bean後置處理器用來攔截Bean的建立ui

      • 獲取已經定義了須要建立對象的BeanPostProcessor
      • BeanPostProcessor分別區分實現PriorityOrdered、Ordered的
      • 優先註冊實現PriorityOrdered接口的BeanPostProcessor
      • 再給容器中註冊實現Ordered接口的BeanPostProcessor
      • 最後註冊沒實現優先級接口的BeanPostProcessor(常規的後置處理器)
      • 註冊BeanPostProcessor,實際上spring就會建立對象保存在容器中;
        如下是建立Bean的流程:
        一、doCreateBean(Param)方法內建立Bean實例
        二、populateBean(Param)給bean實例屬性賦值
        三、initializeBean(Param):初始化Bean
        四、invokeAwareMethods():處理Bean實現Aware接口的方法回調
        五、後置處理器處理的流程:圖2的流程this

        • beanFactory.addBeanPostProcessor:將建立完成的BeanPostProcessor放在容器中

==========上面流程則完成對BeanPostProcessor的註冊和建立spa

  • refresh過程接上:

    • finishBeanFactoryInitialization(Param)完成對BeanFactory初始化的工做,剩下建立單實例的bean
    • 單實例Bean被建立的方法調用棧:getBean->doGetBean()->getSingleton()-createBean-doCreateBean而後就是上面重複的建立Bean的流程。這一部分Bean建立源碼細節暫時先緩一緩,待到spring aspectJ源碼分析再回過頭來分析從getBean到doCreateBean進行了哪一些操做。

BeanPostProcessor在spring底層的使用

在spring中,Aware接口的Bean在被初始以後,能夠取得一些相對應的資源,也就是說,自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx)的話,自定義組件就須要實現xxxxAware接口;在建立對象的時候,會調用接口規定的方法注入相關組件,把Spring底層一些組件注入到自定義的Bean中;
ApplicationContextAware
能夠在Spring初始化實例 Bean的時候,能夠經過這個接口將當前的Spring上下文傳入,即得到spring 容器,實際開發中,經常封裝成一個工具類(方便獲取容器獲取bean):

//將組件註冊添加到容器中後能夠直接看成工具類
public class SpringContextTool implements ApplicationContextAware {

    private static ApplicationContext context = null;

    public static Object getBean(String beanName) {
        return context.getBean(beanName);
    }

    public static <T> T getBean(Class<T> clazz){
        return context.getBean(clazz);
    }

    public static ApplicationContext getContext() {
        return context;
    }

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        context = applicationContext;//打個斷點
    }
}

原理:在重寫方法打個斷點,查看方法調用棧
容器看出,在bean初始化方法執行以前,先執行後置處理器的postProcessBeforeInitialization方法,程序跳進ApplicationContextAwareProcessor這個類中(此類實現了BeanPostProcessor接口),執行重寫的postProcessBeforeInitialization方法,在跳到invokeAwareInterfaces方法中,判斷了當前初始化bean時候繼承了對應的Aware,若是是則調用對應的set方法,傳入對應的資源。

同理還有**EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware**也是注入spring底層組件
再舉個EmbeddedValueResolverAware的例子,能夠實現這個aware接口來完成Spring獲取properties文件屬性值:

public class PropertiesUtil implements EmbeddedValueResolverAware {

    private static StringValueResolver resolver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
    }
    public static String getPropertiesValue(String key) {
        StringBuilder name = new StringBuilder("${").append(key).append("}");
        return resolver.resolveStringValue(name.toString());
    }
}

須要獲取properties文件的屬性值時能夠採用:propertiesUtil.getPropertiesValue("xxxxxxx")或者@value("xxxx")來達到獲取屬性值。
打個斷點後發現它的原理和ApplicationContextAware是同樣的。都是判斷了當前初始化bean時候繼承了對應的Aware,若是是則調用對應的set方法,傳入對應的資源。源碼以下:

private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

ServletContextAware、ServletConfigAware等幾個原理也是差很少相似的。
同理還有BeanValidationPostProcessor也實現了BeanPostProcessor接口,可用於數據校驗,還有InitDestroyAnnotationBeanPostProcessor也實現了此接口,主要是用於處理JSR250那幾個註解的,AutowiredAnnotationBeanPostProcessor也實現了該接口,用於處理@autowired註解裝載bean。總之,Bean的賦值、注入其餘組件,@autowired,@Async,生命週期等都是使用BeanPostProcessor來完成的。這一些使用和原理在下一章再分析並補上流程圖。
圖片描述

相關文章
相關標籤/搜索