Spring 4.3 源碼分析之 IOC 組件概述

1. IOC 概述

IOC: Inversion of Control(控制反轉), 這里其實指的是: 將程序中需要使用的 POJOs, 丟入到容器中, 解析成統(tǒng)一的 BeanDefinition(主要基于XML的 GenericBeanDefinition/RootBeanDefinition 與 通過 注解生成的 ScannedGenericBeanDefinition), 而 Bean 依賴的信息都在XML中描述(或通過注解描述), 容器則負責 Bean 的統(tǒng)一生成(本來Bean的創(chuàng)建/銷毀是由我們開發(fā)人員控制的), 因此造成了 Bean 的創(chuàng)建/銷毀由Bean容器控制的反轉現(xiàn)象!(通過下圖理解一下)


container-magic.png

圖中角色:

1. 如上圖 Spring IOC 容器使用了 Configuration Metadata, Configuration Metadata 告知 Spring容器如何去實例化, 配置和裝配對應的對象
2. Configuration Metadata(及 BeanDefinition)現(xiàn)在主要由解析XML.Properties 或通過掃描指定目錄下帶有特定注解的 Bean 生成
2. IOC 主要組件 BeanDefinition 的屬性

先看一下 BeanDefinition 主要屬性

// Bean 的Class 對象
private volatile Object beanClass;

// bean 的作用范圍, 對應 bean 屬性 scope (常見的就是單例/原型)
private String scope = SCOPE_DEFAULT;

// 是否是抽象, 來自 bean 屬性的 abstract(抽象的類是不能直接生成對象)
private boolean abstractFlag = false;

// 是否延遲加載, 對應 bean 屬性 lazy-init (值是否在使用 Bean的時候才正真的創(chuàng)建 Bean)
private boolean lazyInit = false;

// 自動注入模式, 對應 bean 屬性 autowire (這個屬性主要指 XML 描述的 beanDefinition, 在生成bean的對吼階段, 獲取容器中的對象, 自動裝配在 BeanDefinition 對應的 Field 上)
private int autowireMode = AUTOWIRE_NO;

// 依賴檢查, Spring 3.0 后 棄用這個屬性
private int dependencyCheck = DEPENDENCY_CHECK_NONE;

// 用來表示一個 bean 的實例化依靠另一個 bean 先實例化(PS: 這個很少使用了)
private String[] dependsOn;

/**
 *  autowire-candidate 屬性設置為 false, 
 *  這樣容器在查找自動裝配對象時
 *  將不考慮該 bean, 即它不會被考慮作為其他 bean 
 *  自動裝配的候選者, 但是該 bean 
 *  本身還是可以使用自動裝配來注入其他的 bean
 */
private boolean autowireCandidate = true;

// 自動裝配時當出現(xiàn)多個 bean 候選者時, 將作為首候選者 (PS: 使用比較少)
private boolean primary = false;

// 用于記錄 Qualifier, 對應子元素 qualifier(當使用 @Autowired 時, 有多個候選Bean 時, 就通過這個Qualifier 來進行區(qū)分)
private final Map<String, AutowireCandidateQualifier> qualifiers =
        new LinkedHashMap<String, AutowireCandidateQualifier>(0);

// 允許訪問非公開的構造器和方法, 程序設置  (PS: 用得比較少)
private boolean nonPublicAccessAllowed = true;

/**
 * 是否以一種寬松的模式解析構造函數(shù), 默認 true
 * 如果是 false, 則在如下情況
 * interface ITest()
 * class ITestImpl implement ITest();
 * class Main {
 *     Main(ITest i) {}
 *     Main(ITestImpl i) {}
 * }
 * 拋出異常, 因為 Spring 無法準確確定哪個構造函數(shù)
 * 程序設置
 *
 * lenient 寬大, 仁慈
 */
private boolean lenientConstructorResolution = true;

/**
 * 對應 bean 屬性 factory-bean 用法 (PS: 這里涉及 FactoryBean 這個概念, 這個類主要是解決: 創(chuàng)建一個類, 但創(chuàng)建這個類的過程比較長/條件比較多, 這時候就使用同一的抽象工廠模式(FactoryBean對象) 來創(chuàng)建對象)
 * <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean />
 * <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime" />
 */
private String factoryBeanName;

// 對應 bean 屬性 factory-method
private String factoryMethodName;

// 記錄構造函數(shù)注入屬性, 對應 bean 屬性 constructor-arg
private ConstructorArgumentValues constructorArgumentValues;

// 普通屬性集合 (在XML 中定義Bean的信息時, 通常propertyValues里面有很多依賴信息)
private MutablePropertyValues propertyValues;

// 方法重寫的持有者, 記錄 lookup-method, replaced-method 元素(PS: 與此對應有注解Loopup, 但運用的比較少了)
private MethodOverrides methodOverrides = new MethodOverrides();

// 初始化方法, 對應 bean 屬性 init-method (PS: 通過 實現(xiàn)InitializingBean 接口, 可以達到同樣效果)
private String initMethodName;

// 銷毀方法, 對應  bean 屬性 destory-method (PS: 與之對應的是 DisposableBean, 一幫都是在這類方法中完成資源釋放之類的操作)
private String destroyMethodName;

// 是否執(zhí)行 init-method, 程序設置  (默認是 true)
private boolean enforceInitMethod = true;

// 是否執(zhí)行 destory-method, 程序設置 (默認是 true)
private boolean enforceDestroyMethod = true;

// 是否是用戶定義的而不是應用程序本身定義的, 創(chuàng)建 AOP 部分組件時為 true(見 ConfigBeanDefinitionbeanParser.parseAdvice 方法)
private boolean synthetic = false;

/**
 * 定義這個 bean 的應用, APPLICATION: 用戶, INFRASTRUCTURE(infrastructure 基礎設施): 內部使用, 與用戶無關, SUPPORT: 某些復雜配置的一部分程序設置, 一般都是 BeanDefinition.ROLE_APPLICATION;
 */
private int role = BeanDefinition.ROLE_APPLICATION;

// bean 的描述信息
private String description;

// 這個 bean 定義的資源 (其實就是 A.class 這個文件)
private Resource resource;

PS: 屬性好多, 一直其實上面屬性中相對重要的有一下幾個
2.1 class(該實例化的 Bean), name(bean的命名)
2.2 scope(定義Bean的生命周期)
2.3 constructor arguments(Bean構造函數(shù)依賴注入的屬性)
2.4 properties(Bean依賴注入的屬性, 這里的 properties 主要還是指XML或properties里面描述的信息)
2.5 autowiring mode(是否自動裝配, 若是的話, 則容器會在整個容器中尋找所有符合條件的 Field)
2.6 lazy-initialization mode (是否 lazy 生成Bean, 指是否在正真需要使用 Bean時才會創(chuàng)建bean, 但現(xiàn)在運用中一般都是使用 ApplicationContext 的子類, 這個類會在 refresh() 方法里面中調用 finishBeanFactoryInitialization(), 然后再調用 preInstantiateSingletons 來實例化容器中的所有類), 2.7 initialization method (Spring 容器中 bean 的初始化方法, 這個完全可以通過實現(xiàn)接口 InitializingBean 來實現(xiàn))
2.8 destruction method (Spring 容器中 bean 的銷毀方法, 這個也完全可以通過實現(xiàn)接口 DisposableBean 來實現(xiàn))

PS: 這個有個漏掉的點: 在Spring 創(chuàng)建 Bean的過程中, 容器里面的 BeanFactoryPostProcessor 可以對Bean的元數(shù)據(jù)進行一定的修改
3. IOC 主要組件 BeanDefinition 的分類

BeanDefinition 其實是根據(jù) BeanDefinition 的收集策略來進行分類的, 主要分成下面:

1. GenericBeanDefinition:            一個標準的 BeanDefinition, 通過XML 讀取Bean的描述信息組裝的BeanDefinition一般都是GenericBeanDefinition, 后續(xù)的 beanDefinition 都是在這個類的基礎上進行擴展
2. ScanedGenericBeanDefinition:      這個類擴展于 GenericBeanDefinition, 底層是通過 ASM 的ClassReader 來獲取對應注解 Annotation  相關的元數(shù)據(jù)
3. AnnotatedGenericBeanDefinition:   這個 BeanDefinition 與上面的ScanedGenericBeanDefinition 很相似, 都具有 bean上注解的描述信息, AnnotatedGenericBeanDefinition 這個類主要是在使用 AnnotationConfigApplicationContext創(chuàng)建容器時, 通過 AnnotationBeanDefinitionReader 來獲取對應 BeanDefinition 時創(chuàng)建的
4. IOC 主要組件 BeanDefinitionReader 概述

先看一下接口BeanDefinitionReader 的主要方法


// beanDefinition 的讀取者
// 這里有個注意點, BeanDefinition 的讀取器不一定非要實現(xiàn)BeanDefinitionReader接口, 其實這里指的就是 AnnotatedBeanDefinitionReader 與 ClassPathBeanDefinitionScanner
public interface BeanDefinitionReader {

    // 這里的 BeanDefinitionRegistry 其實就是 beanFactory 的注冊接口, BeanDefinition 通過這個接口注入到 BeanFactory 看一下 BeanDefinitionRegistry 的實現(xiàn)類就知道了
    BeanDefinitionRegistry getRegistry();

    // ResourceLoader 代表的是 BeanDefinitionReader 需要讀取的是 描述BeanDefinition的資源文件加載器, 以前 BeanFactory 與 ResourceLoader 是分離開的兩個組件, 后來出現(xiàn)了 ApplicationContext, 將 beanFactory 與 ResourceLoader 結合到一個類中
    ResourceLoader getResourceLoader();

    // 加載類的 ClassLoader
    ClassLoader getBeanClassLoader();

    // bean 的命名生成器
    BeanNameGenerator getBeanNameGenerator();

    // 加載指定目錄Resource下 BeanDefinition 的方法
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

    // 加載多個指定目錄Resource下 BeanDefinition 的方法
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    // 加載指定目錄Resource下 BeanDefinition 的方法
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

    // 加載多個指定目錄Resource下 BeanDefinition 的方法
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

上面方法定義了獲取 BeanDefinition的主要生成策略, 但其中有個重要的點, 就是 BeanDefinition 的讀取器不一定非要實現(xiàn) BeanDefinitionReader 接口, 比如 AnnotatedBeanDefinitionReader(直接注入帶注解的bean) 與 ClassPathBeanDefinitionScanner(掃描指定目錄下面帶注解的Bean)

5. IOC 主要組件 BeanDefinitionReader 分類

BeanDefinitionReader 首先是通過一個抽象類 AbstractBeanDefinitionReader 來定義了加載 beanDefinition 的模板方法(模板模式), 接下來根據(jù)在不同文件(XML/Properties)中定義Bean描述信息來實現(xiàn)不同類別的 BeanDefinitionReader(策略模式)

1. AbstractBeanDefinitionReader:         實現(xiàn) beanDefinitionReader 接口的抽象類, 主要定義了加載類的主邏輯, 后續(xù)的類依據(jù)不同存儲文件不同格式, 有不同的具體實現(xiàn)類 
2. PropertiesBeanDefinitionReader:       讀取 properties 文件的 beanDefinitionReader, 這個類相對簡單, 但是沒有下面的 XMLBeanDefinitionReader 擴展性那么好
3. GroovyBeanDefinitionReader:           這個類是基于 XMLBeanDefinitionReader 實現(xiàn)的 BeanDefinitionReader
4. XmlBeanDefinitionReader:              最常見的 BeanDefinitionReader, 也是相對擴展性最好的 Reader(PS: 它的擴展性主要體現(xiàn)在自定義命名空間, 比如 <mvc...>, <aop...>, <tx...>, 或者dubbo擴展的 <dubbo....>)
5. AnnotatedBeanDefinitionReader:        雖然沒有實現(xiàn) BeanDefinitionReader 接口, 但是它其實還是個 BeanDefinitionReader, 主要是當使用基于注解驅動的 AnnotationConfigApplicationContext 時使用的
6. ClassPathBeanBeanDefinitionScanner:   這個類也沒有實現(xiàn)BeanDefinitionReader , 但是它非常強大, 知道指定一個掃描的目錄, 就會將符合條件的Bean生成 ScanedGenericBeanDefinition 對象, 注入到容器中(PS: 當Spring的XML文件中定義了 <context:component-scan> 也會創(chuàng)建這個類, 并且通過這個類掃描指定目錄項目的類, 并registry 到 BeanFactory 中)

上面額幾種 beanDefinitionReader中, XmlBeanDefinitionReader, AnnotatedBeanDefinitionReader, ClassPathBeanBeanDefinitionScanner 是比較重要的, 也是最常見的, 后續(xù)篇章會專門分析

6. IOC 主要組件 Resource 概述

Resource: Spring 里面對資源進行封裝的統(tǒng)一抽象接口, 里面定義了一些通用的方法, 詳情如下:

// Spring 中資源的統(tǒng)一抽象接口
public interface Resource extends InputStreamSource {

    // 返回的資源是否存在
    boolean exists();

    // 返回的資源是否可讀
    boolean isReadable();

    // 返回這個資源是否有已打開流的處理, 若果是 true, 則此 InputStream 就不能被多次讀取, 而且只能被讀取和關閉以免資源泄露
    boolean isOpen();

    // 轉換 Resource 到 URL
    URL getURL() throws IOException;

    // 轉換 Resource 到File
    File getFile() throws IOException;

    // 返回資源內容的長度
    long contentLength() throws IOException;

    // 資源上次修改時間
    long lastModified() throws IOException;

    // 創(chuàng)建資源相對于這個資源
    Resource createRelative(String relativePath) throws IOException;

    // 對的這個資源的名字
    String getFilename();

    // 返回資源的描述, 用于錯誤處理中打印的信息
    String getDescription();
}

上面是資源抽象的統(tǒng)一接口, 而針對資源獲取的不同方式, 對應的有相應的子類(PS: AbstractResource 是其對應的抽閑子類, 其間定義了一些抽象的方法, 所有的子類都是從這個類派生出來)

7. IOC 主要組件 Resource 類別

在 Spring 中針對獲取資源的不同渠道, 創(chuàng)建了相應的 Resource(主要是依據(jù) 路徑的格式不同, 來創(chuàng)建不同類別的 Resource), 其中有我們進行開發(fā)中常用的一些類, 如下:

1. FileSystemResource: 比如使用容器 FileSystemXmlApplicationContext時, 配置的 XML 資源都會被封裝成FileSystemResource 
2. ServletContextResource: 若是用 XmlWebApplicationContext 系列的 ApplicationContext 容器時, 一般都是生成這個(PS: 這時是以 "/" 開頭)
3. ClassPathResource: 當使用 ClassPathXmlApplicationContext 時, 最終將資源包裝成 ClassPathResource(則對應的資源將通過 ClassLoader 進行加載)(PS: 這時是以 "/" 或"classpath:"開頭, 若不是的話, 則封裝成 URLResource)

PS: 在上面創(chuàng)建 Resource時, 若遇到 Classpath*: 開頭時, 則將通過 PathMatchingResourcePatternResolver 來進行獲取對應資源, 這時又會判斷是否路徑中含有 "*/?" 這種字符串, 則獲取能正則匹配成功的所有文件; 
    補充: classpath*: 代表的是獲取當前ClassLoader對應的 URLClassPath下面的所有包中匹配的資源(包括父 ClassLoader, 詳情見 PathMatchingResourcePatternResolver.getResources(String locationPattern) ); 而 classpath 則是通過Class.getResourceAsStream(String path) 來獲取一個數(shù)據(jù)流, 對滴就一個文件(詳情見 ClassPathResource.getInputStream())
8. IOC 主要組件 ResourceLoader 概述

ResourcceLoader 中定義了獲取Spring中統(tǒng)一資源的方法, 它將根據(jù)路徑的前綴來生成對應的 Resource, 其中最通用的就是下面這幾種:

1. DefaultResourceLoader: 這個類是 AbstractApplicationContext 的超類, 其間定義了獲取 Resourcce的默認方法 getResource(String location); 若路徑以"/"開頭, 則交由子類創(chuàng)建對應的 Resource(根據(jù)不同的子類類別創(chuàng)建不同的 Resource, 如 FileSystemXmlApplicationContext的FileSystemResource, GenericWebApplicationContext 的 ServletContextResource, ClassPathXmlWebApplicationContext的ClassPathResource), 若路徑以 "classpath:" 開頭, 則創(chuàng)建 ClassPathResource, 若不是以上兩種情況, 則直接創(chuàng)建 UrlResource
2. PathMatchingResourcePatternResolver: 這個類是在創(chuàng)建 AbstractApplicationContext 時默認創(chuàng)建的 ResourceResolver, 當遇到的路徑是以 "classpath*: " 開頭是就通過這個類來獲取 ClassLoader的classpath下面的所有 jar 中的符合條件的XML資源(PS: PathMatchingResourcePatternResolver是一個非常重要的類, 而且它獲取資源的方式非常直接借鑒)
9. IOC 主要組件 BeanDefinitionDocumentReader

這個類存在的意義主要是封裝成 XML文件為 Document, 并且根據(jù)每個節(jié)點的命名空間獲取對應的 Namespacehandler 來進行處理解析對應的節(jié)點; 其默認實現(xiàn)就是 DefaultBeanDefinitionDocumentReader; 對于普通的命名空間 "http://www.springframework.org/schema/beans", 則直接用 BeanDefinitionParserDelegate的parseBeanDefinitionElement來進行解析; 若遇到其他命名空間的, 則通過NamespaceHandlerResolver 來獲取對應的 NamespaceHandler 來進行解析
(PS: NamespaceHandler 也是通過META-INF/Spring.handlers 下面定義的命名空間對應的Namespacehandler, 并通過反射來進行創(chuàng)建, 具體看 DefaultNamespacehandlerResolver 的gethandlerMappings )

10. IOC 主要組件 NamespaceHandler

Spring解析XML 時, 主要依據(jù)命名空間來選擇對應的 NamespaceHandler 來進行解析

1. http://www.springframework.org/schema/beans 對應 默認的解析類 BeanDefinitionParserDelegate
2. 當遇到其他命名空間時, 則通過 DefaultNamespaceHandlerResolver.resolve(namespaceUri) 來獲取對應的 NamespaceHandler 來進行解析(比如遇到 <mvc...>, <aop...>, <tx...>, 或者 dubbo 中的<dubbo>)

DefaultNamespaceHandlerResolver 通過獲取所有 "META-INF/spring.handlers" 里面定義的 Namespacehandler, 并找到namespace與之對應的進行解析

11. IOC 主要組件 BeanFactoryPostProcessor

BeanFactoryPostProcessor: 對這個名詞進行分割; BeanFactoryPostProcessor = BeanFactory(bean工廠) + Post(后) + Processor(處理器); 這樣就好理解了!

public interface BeanFactoryPostProcessor {
        // 這個方法在 BeanFactory 加載好所有的 Bean 信息到容器后, 實例化任何Bean實例之前(Bean在容器中有實例化(Instantiation)與初始化(Initialization)的差別, 這點很重要)
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

對于這個類, 最常見的就是用于修改 Bean 的屬性, 比如一開始在對應屬性上面設置 "${}" 設置這樣的占位符, 然后通過對應類進行賦值


BeanFactoryPostProcessor.jpg

如圖:

BeanFactoryPostProcessor:      定義了方法執(zhí)行的入口(在加載所有Bean信息到容器之后)
PropertiesLoaderSupport:       Properties加載/解析的方式方法
PropertyResourceConfigurer:    繼承PropertiesLoaderSupport, 實現(xiàn)BeanFactoryPostProcessor接口, 其中定義執(zhí)行方法的主邏輯, 并留下模板方法 processorProperties(), 留給子類去實現(xiàn)
PropertyOverrideConfigurer:    這個類主要在 properties 文件里面寫入 beanName.fieldname=fieldvalue 這樣的鍵值對來進行解析數(shù)據(jù)
PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer: 這兩個類都是繼承PropertyResourceConfigurer, 但與PropertyOverrideConfigurer不同的是, 這兩個類都是通過"${}" 這種占位符號來確定哪個數(shù)據(jù)需要替換成 Properties 里面的數(shù)據(jù), 其中還涉及到了非常有效的工具類 PlaceholderResolver(這個類是來獲取對應數(shù)據(jù)中所有的 ${} 中的數(shù)據(jù), 其中涉及到遞歸獲取, 這種獲取的方式其實很值得借鑒), 當然還有我們熟悉的設計模式 --> 觀察者模式, 通過 BeanDefinition 的觀察者 BeanDefinitionVisitor 來進行 visitor 每一個 BeanDefinition中的屬性(見BeanDefinitionVisitor)
12. IOC 主要組件 BeanPostProcessor

BeanPostProcessor 接口是Spring IOC 中擴展機制的提現(xiàn), 自己可以在BeanPostProcessor的回調方法中實現(xiàn) "實例化邏輯, 依賴分析"等;
它具有以下特定:

1. 可以在容器中注入多個 BeanPostProcessor, 并且通過 Ordered接口來控制 BeanPostProcessor實現(xiàn)的次序;
2. BeanPostProcessor 的 postProcessbeforeInitialization方法作用在 bean 的初始化方法(PS: 這里的初始化方法主要是通過xml中配置的, 或者實現(xiàn) InitializingBean接口而具有的 afterPropertiesSet)前面調用, 作用在 Bean 實例化, 并且設置好 XML 中配置的依賴熟悉之后調用(PS: 其中包括InstantiationAwareBeanPostProcessr的postProcessPropertyValues 之后 ---> postProcessPropertyValues 主要是將 bean中被 @Autowired,@Resource, @PersistenceContext, @Required 注解修飾屬性注入對應的值);而在Spring容器自己提供的幾個 BeanPostProcesser的實現(xiàn)類中, 可以看到在 ApplicationContextAwareProcessor 中完成了一下 Aware 接口的喚醒
3. BeanPostProcessor 的 postProcessAfterInitialization方法主要作用在 Bean的初始化方法之后執(zhí)行(PS: 這時的bean已經實例化,并且進行類依賴注入+Aware接口的喚醒), 對于這個接口, 最常見的就是通過這個接口實現(xiàn)對 Bean 的 AOP(PS: 其中涉及到一個 IOC 容器中配置多個 AbstractAutoProxyCreator 的情況, 而其內部通過advisedBeans來判斷 Bean 是否已經被 動態(tài)代理了); 在自動AOP中, 主要有基于命名空間的 AspectJAwareAdvisorAutoProxyCreator 與 基于 @AspectJ注解風格的 AnnotationAwareAspectJAutoProxyCreator (PS: 針對這兩個類, 在介紹AOP中會詳細解析)
4. InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation: Spring中 bean 的實例化前置處理器, 當系統(tǒng)中配置 customTargetSourceCreators 時, 將通過特定的 TargetSource 來對 Bean 進行動態(tài)代理, 若類已經被動態(tài)代理了, 則相應的也會執(zhí)行 BeanPostProcessor.postProcessAfterInitialization 方法(PS: postProcessAfterInitialization 里面可能有些其他的邏輯需要執(zhí)行)
5. InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantion: bean 實例的后置方法, 其主要是控制是否需要將 xml 中配置的 Spring 屬性進行注入 + InstantiationAwareBeanPostProcessor.postProcessPropertyValue(PS: postProcessPropertyValue這個方法主要是注入被注解修飾的屬性)是否執(zhí)行, 一般情況就是返回 true
6. InstantiationAwareBeanPostProcessor 的 postProcessProperty: 這是一個非常重要的方法, 主要完成Bean中被注解注釋的屬性的注入(比如: AutowiredAnnotationBeanPostProcessor 處理 @Autowired, @Value; RequiredAnnotationBeanPostProcessor處理 @Resource; PersistenceAnnotationBeanPostProcessor處理@PersistenceContext等注解)(PS: SpringMVC 的@RequestMapping 與 事務的 @Transactional 又是不同的處理邏輯)
7. SmartInstantiationAwareBeanPostProcessor 的 predictBeanType: 預測Class的類型, 當系統(tǒng)中發(fā)現(xiàn)無法確定Bean類型, 并且存在SmartInstantiationAwareBeanPostProcessor, 就會通過這個方法來獲取對應的class類型(PS: 這個方法主要的實現(xiàn)在 AbstractAutoProxyCreator里面)
8. SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors: 預測類的構造函數(shù), 之所以有這個方法, 主要存在 @Lookup 注解(PS: 這個注解很少使用), 這個determineCandidateConstructors方法在實例化 Bean的過程中會被調用具體看 AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors 方法
9. SmartInstantiationAwareBeanPostProcesso r的 getEarlyBeanReference: 預測Bean實例, 在 AbstractAutoProxyCreator中這個方法與postProcessAfterInitialization中只有一個會執(zhí)行 Bean 的代理過程(PS: 這是為什么呢, 看看 earlyProxyReferences就知道了, 兩個方法在執(zhí)行 wrapIfNecessary 都會通過 earlyProxyReferences 判斷是否已經創(chuàng)建好 AOP 對象); 對于這個getEarlyBeanReference 方法是在 Bean 被提早暴露時才會調用
舉例: 
      兩個類:  class A { B b;}; class B { A a; }; 都注入到 Spring 容器, 
      1. XmlBeanDefinitionReader 將描述 A,B兩個類的xml 文件讀入, 并解析成 BeanDefinition, 然后注入到 DefaultListableBeanFactory中;
      2. DefaultListableBeanFactory 通過 getBean 方法開始實例化這兩個類, 在創(chuàng)建 A 的時, 發(fā)現(xiàn)A是單例, 其容器允許循環(huán)引用, 并且 A 不在 map -> singletonsCurrentlyInCreation(表示類是否在創(chuàng)建) 中, 則將 A 包裝成 ObjectFactory 類, 放入單例工廠中, 已備被其他創(chuàng)建的類引用, 而 ObjectFactory 中是通過 AbstractAutowireCapableBeanFactory.getEarlyBeanReference --> SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference --> AbstractAutoProxyCreator.getEarlyBeanReference 來暴露創(chuàng)建的動態(tài)代理對象
      3. 而在實例化 A 后, 發(fā)現(xiàn) A 依賴于 B(這里的依賴信息可能存在于xml 或通過 @Autowired/@Resource 注解), 則開始創(chuàng)建類 B
      4. 同樣在創(chuàng)建類 B 時, 發(fā)現(xiàn) B 依賴于 A, 所以直接通過 earlySingletonObjects 來獲取上面提早暴露的 ObjectFactory, 接著會 AbstractAutowireCapableBeanFactory.getEarlyBeanReference --> SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference --> AbstractAutoProxyCreator.getEarlyBeanReference 來得到最終暴露出來的 A 對象

BeanPostProcessor 的分類, 各個子類的作用, 包括 BeanFactory 中如何解決循環(huán)引用(只有scope是單例, 并且依賴不是存在在構造函數(shù)中才能解決循環(huán)引用) 進行了介紹, 后續(xù)會對個別 BeanPostProcessor 詳細的解析

13. IOC 主要組件 FactoryBean

FactoryBean: Spring容器中 某類特定Bean的工廠類(這里其實就涉及到了抽象工廠模式), FactoryBean 充斥著整個IOC容器, 一開始接觸 FactoryBean的同學可能不深刻理解這個類的好處, 其實看一下 ProxyFactoryBean(生成動態(tài)代理的 FactoryBean), ScheduledExecutorFactoryBean(生成定時線程執(zhí)行器的 FactoryBean), TransactionProxyFactoryBean(基于目標 Target 生成通過切面控制事務的動態(tài)代理類), JobDetailFactoryBean(生成基于 org.quartz.JobDetail 的實例), 就能知道 FactoryBean 主要其實是對于一些創(chuàng)建過程復雜的類進行通過操作的類,

14. IOC 主要組件 BeanFactory

BeanFactory: 是Spring IOC 容器的頂層接口, 其中定義了獲取Bean的一般接口, 如下:

// Spring 的 Bean 容器最頂層的接口, 定義了 Ioc 容器的基本規(guī)范
public interface BeanFactory {

    // 通過在BeanName名字前面加 & 來獲取生成對象的 factory
    String FACTORY_BEAN_PREFIX = "&";

    // 通過 Bean 的名字, 獲取對應的實例
    Object getBean(String name) throws BeansException;

    // 獲取指定名稱的 Bean, 其中 requiredType 指的是 Bean的類型
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    // 獲取指定名稱的 Bean
    <T> T getBean(Class<T> requiredType) throws BeansException;

    // 獲取指定名稱的 Bean, 其中 args 指的是 構造函數(shù)/工廠方法的參數(shù)
    Object getBean(String name, Object... args) throws BeansException;

    // 獲取指定類型的 Bean, 其中 args 指的是 構造函數(shù)/工廠方法的參數(shù)
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    // 判斷容器是否含有 Bean
    boolean containsBean(String name);

    // 這個名稱對應的 Bean 是否是 singleton 類型
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    // 這個名稱對應的 Bean 是否是 prototype 類型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    // 判斷指定名稱對應的 Bean 是否與 typeToMatch 相匹配(這個方法使用得非常多)
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    // 判斷指定名稱對應的 Bean 是否與 typeToMatch 相匹配(這個方法使用得非常多)
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 獲取指定 Name 的 bean 類型(PS: 一個特例, 若遇到 FactoryBean, 則會通過 FactoryBean.getObjectType 來獲取最終對象的類型)
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    // 獲得 Bean 的別名
    String[] getAliases(String name);
}

上面接口主要定義了獲取 Bean 的接口, 至于 BeanFactory 的繼承(HierachicalBeanFactory), 自動裝配(AutowireCapableBeanFactory), 批量獲取 bean(ListableBeanFactory) 這些特性都是由子接口進行定義, 如下圖:


BeanFactory.jpg

乍一看, 圖中類/接口好復雜, 沒事, 我們一層一層梳理:

接口:
   第一層: BeanFactory:                         這個接口里面定義獲取 Bean 的基礎方法
   第二層: HierarchicalBeanFactory:             這個接口定義了獲取 parentBeanFactory 的方法(PS: 這里其實也存在著委派機制, 當子BeanFactory 獲取不到bean時, 會通過父BeanFactory來進行獲取, 但是反過來, 父BeanFactory若獲取不到Bean, 則不會再到子BeanFactory中獲取, 這種父子BeanFactory形式通常在于: 在 Tomcat的web.xml里面配置 ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> 通過反射直接創(chuàng)建 XmlWebApplicationContext  <-- 這個是 parentBeanFactory, 與之對應的 子BeanFactory 是 由 HttpServletBean.init() --> FrameworkServlet.initServletBean --> FrameworkServlet.initWebApplicationContext --> FrameworkServlet.createWebApplicationContext(這時會將上面的父beanFactory設置到子BeanFactory中)) 
           ListableBeanFactory:                (基于類型)獲取容器中所有 BeanNames, 獲取被注解注釋的 BeanName 等方法
           AutowireCapableBeanFactory:         這里面定義了, 創(chuàng)建Bean, 自動裝配 Bean, 初始化 Bean, 為特定 Bean 解決對應依賴屬性的方法
   第三層: ConfigurableBeanFactory:             增加配置Bean功能的BeanFactory, 這個接口, 繼承 SingletonBeanFactory, 具備了注冊單例bean的接口, 除此之外 其中還定義了配置 ConversionServere(Spring里面的類型轉換器, Spring 默認的是 DefaultConversionService, 主要是完成數(shù)據(jù)類型的轉換器的注冊); 配置 BeanPostProcessor(Bean后置處理器)的方法, 銷毀 Bean的方法
           ConfigurableListableBeanFactory:    這個接口里面定義了 preInstantiateSingletons (預實例化Bean的方法), 獲取指定名稱的 BeanDefinition 的方法等
       (PS: 這個第三層接口主要是針對第二層接口的功能延伸, 其中 ConfigurableBeanFactory 具備了 注冊單例Bean的功能)
實現(xiàn)類:
           AbstractBeanFactory:                這個類繼承了 FactoryBeanRegistrySupport 具備了注冊單例+支持FactoryBean的能力, 本身也實現(xiàn)了創(chuàng)建 Bean 的主邏輯(getBean 方法), 并留下了 createBean, getBeanDefinition, containsBeanDefinition 等模板方法
           AbstractAutowireCapableBeanFactory: 這個類繼承了 AbstractBeanFactory 并實現(xiàn)了模板方法 createBean, 并實現(xiàn)了接口 AutowireCapableBeanFactory, 完成了對 BeanPostProcessor 的處理
           DefaultListableBeanFactory:         這個類是 Spring IOC 里面功能最全的 Bean 容器, 我們常用的 ApplicationContext 都是基本都是在內部有個 DefaultListableBeanFactory(基于 ApplicationContext 繼承 BeanFactory, 所以你也可以將這種程序設計方式視為 代理方式)
PS:        一開始看 Spring IOC 時被 BeanFactory 的繼承接口給嚇住了(哇 這么多的接口繼承關系, 層級又是這么多), 結果才發(fā)現(xiàn), 這么多接口中只有第一層與第二層接口之間有明顯的擴展, 而下面的接口, 都是逐漸逐漸擴充對應的方法

上面是 BeanFactory 的接口設計及實現(xiàn), 接口層面主要是3級, 都是對容器功能一點一點的擴充, 而其中 AbstractBeanFactory 設計了創(chuàng)建類的主邏輯(getBean方法), 并且預留了創(chuàng)建類的模板方法(createBean), 而最終的實現(xiàn)類就是 DefaultListableBeanFactory, 工作中常用的:

1. XmlBeanFactory(基于 XmlBeanDefinitionReader讀取xml配置的Bean依賴關系)
2. XmlWebApplicationContext(用于web容器中的BeanFactory)
3. ClassPathXmlApplicationContext(通過在 classpath 下面查找指定文件的 BeanFactory)
4. FileSystemXmlApplicationContext(直接通過文件相對路基獲取xml配置文件的 BeanFactory)
5. AnnotationConfigWebApplicationContext (通過掃描指定目錄下面的 class 文件, 并將被特定注解修飾的額類加載到容器中的 BeanFactory)

都是或多或少的用到 DefaultListableBeanFactory(要是繼承, 要么就是將DefaultListableBeanFactory設置為其內部的一個變量)

15. IOC 總結

上面簡單的介紹了一下 Spring IOC 里面的主要組件, 其中涉及到的組件還是比較多的, 一開始進行看源碼時可能被浩瀚的代碼給淹沒, 從而恐懼, 接著就放棄了(相信很多人都會經歷過這幾個過程), 當然我也經歷過, 當然直到現(xiàn)在自己對 Spring 里面有些細節(jié)的東西還不是非常了解, 但其實沒關系, 個人覺得只要把握主要的設計思想以及常見的架構設計就可以了!(畢竟全部弄精還是非常耗時的一個工程)

16. 參考資料

Spring技術內幕分析
Spring IOC 原理
Spring 5 源碼分析
開濤的 Spring雜談
傷神的 Spring源碼分析
SpringMVC源碼分析系列
Spring Core
Spring MVC源碼剖析
Spring IOC 源碼分析
Spring源碼情操陶冶
Spring 揭秘 (PS: 這本書絕對給力)
Spring 技術內幕
Spring 源碼深度分析
看透 Spring MVC 源代碼分析與實踐
Spring 高級程序設計 (PS:這本書已經絕版, 所以當時是自己下載 pdf, 然后聯(lián)系淘寶賣家忙幫復印, 其實就是英文版本的 "Pro Spring 3")
深入分析 Java Web(PS: 許令波寫的, 雖然是本老書, 但是里面分析得確實很深入)
expert one-on-one J2EE Development without EJB (PS: Spring 作者自己寫的書, 當時也是下載 PDF, 聯(lián)系淘寶賣家復印購買到的)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容