日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

beanfactorypostprocessor_Spring源码分析(六)容器的扩展点(BeanFactoryPostProcessor)

發布時間:2025/3/20 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 beanfactorypostprocessor_Spring源码分析(六)容器的扩展点(BeanFactoryPostProcessor) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前的文章我寫了BeanDefinition的基本概念和合并,其中很對次提到了容器的擴展點,這篇文章就寫這方面的知識。這部分的內容主要涉及到官網的1.8小節。按照官網介紹來說,容器的擴展點可以分為三類,BeanPostProcessor,BeanFactoryPostProcessor以及FactoryBean。本文主要講BeanFactoryPostProcessor,對應官網的1.8.2小節

總覽:

先看官網怎么說:

從上面這段話可以總結如下幾點:

  • BeanFactoryPostProcessor可以對bean配置元數據進行操作。也就是說Spring容器運行BeanFactoryPostProcessor讀取指定bean的配置元數據,并可以在bean被實例化之前修改它。這里說的配置元數據其實就是我們之前講的BeanDefinition。
  • 我們可以配置多個BeanFactoryPostProcessor,并且只有我們配置的BeanFactoryPostProcessor同時實現了Ordered接口的話,我們還可以控制這些BeanFactoryPostProcessor的執行順序
  • 接下來,我們通過demo來感受下BeanFactoryPostProcessor的作用

    例子:

    這里以官網上的demo為例:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations" value="classpath:com/something/jdbc.properties"/> </bean><bean id="dataSource" destroy-method="close"class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean>

    實際值來自標準Java Properties格式的另一個文件:

    # jdbc.properties jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root

    在上面的例子中,我們配置了一個PropertyPlaceholderConfigurer,為了方便理解,我們先分析下這個類,其UML類圖如下:

    • Ordered用于決定執行順序
    • PriorityOrdered這個接口直接繼承了Ordered接口,并且沒有做任何擴展,知識作為一個標記接口,也用于決定BeanFactoryPostProcessor的執行順序。在后文源碼分析時能看到它的作用
    • Aware相關的接口以后我在接受Bean的生命周期回調時再同一分析
    • FunctionalInterface是Java8新增的一個接口,也只是起一個標記的作用,標記該接口是一個函數式接口
    • PropertiesLoaderSupport這個類主要包含定義了屬性的加載方法,包含的屬性如下:

    • PropertyResourceConfigurer這個類主要可以對讀取到的屬性進行一些轉換
    • PlaceholderConfigurerSupport主要負責對占位符進行解析。其中幾個屬性如下:

    • PropertyPlaceholderConfigurer繼承了上面這些類的所有功能,同時可以配置屬性的解析順序:

    對這個類有一些了解后,我們回到之前的例子中,為什么在jdbc.properties文件配置的屬性值會被應用到BasicDataSource這個Bean呢。我畫個圖:

    這個流程圖就如上圖,可以看到我們通過PropertyPlaceholderConfigurer這個特殊的BeanFactoryPostProcessor完成了BeanDefinition中屬性值中的占位符替換。在BeanDefinition被解析處理后,Bean實例化之前對其進行了更改。

    在上圖中,創建bean的過程我們暫且不管,還有一個問題需要弄清楚,Spring是如何掃描并解析成BeanDefinition呢?這里就不得不提接下來需要分析的接口:BeanDefinitionRegistryPostProcessor

    org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor:

    先看這個接口的UML類圖:

    從上圖可以得出兩個結論:

  • BeanDefinitionRegistryPostProcessor直接繼承了BeanFactoryPostProcessor,所以它也是一個bean工廠的后置處理器
  • Spring只提供了一個內置的BeanDefinitionRegistryPostProcessor的實現類,這個類就是ConfigurationClassPostProcessor,實際上我們上面說的掃描解析成BeanDefinition的過程就是這個類完成的
  • 我們來看下這個接口定義

    BeanDefinitionRegistryPostProcessor:

    BeanFactoryPostProcessor:

    相比于正常的BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor多提供了一個方法,那么多提供的這個方法有什么用呢,會在什么時候執行呢,先說結論:

    這個方法的作用也是為了擴展,相比于BeanFactoryPostProcessor的postProcessBeanFactory方法,這個方法的執行時機會更靠前,Spring自身利用這個特性完成了BeanDefinition的掃描注解。我們對Spring進行擴展時,也可以利用這個特性來完成掃描功能。比如最新版的mybatis就是這么做的。關于mybatis和Spring的整合,我打算在寫完Spring的掃描以及容器的擴展點這一系列文章后單獨用一篇文章進行分析。

    接下來我們直接分析其源碼,驗證上面的結論。

    執行流程源碼分析:

    在分析源碼前,我們看看下面這個圖,方便大家對Spring的執行流程有個大概的了解:

    上圖表示的是AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class)的執行流程。我們這次分析的代碼主要是其中3-5-1流程。代碼比較長,拆分為兩步:

    BeanDefinitionRegistryPostProcessor執行流程:

    BeanFactoryPostProcessor執行流程:

    ......承接上半部分代碼......

    通過源碼分析,我們可以將整個Bean工廠的后置處理器的執行流程總結如下:

    首先,要明白一點,上圖分為左右兩個部分,代表的不是兩個接口,而是兩個方法

    • 一個是BeanDefinitionRegistryPostProcessor特有的postProcessBeanDefinitionRegistry方法
    • 另一個是BeanFactoryPostProcessor的postProcessBeanFactory方法

    這里我們以方法為維度區分更好說明問題,postProcessBeanDefinitionRegistry方法的執行時機早于postProcessBeanFactory。并且他們按照上圖從左至右的順序執行。

    另外在上面進行代碼分析的時候有一個問題,當在執行postProcessBeanDefinitionRegistry方法時,Spring采用了循環的方式,不斷的查找是否有新增的BeanDefinitionRegistryPostProcessor,就是下面這段代碼:

    boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}

    但是在執行postProcessBeanFactory并沒有進行類似的查找,這是為什么呢?

    我自認為主要是Spring在設計時postProcessBeanFactory這個方法不是用于重新注冊一個Bean的,而是修改,我們可以看下這個方法上的爭端Java doc

    其中最重要的一段話:All bean definitions will have been loaded,所有的BeanDefinition都已經被加載了。

    再對比下postProcessBeanDefinitionRegistry這個方法上的Java doc

    注意這段話:This allows for adding further bean definitions before the next post-processing phase kicks in.運行我們在下一個后置處理器執行前添加更多的BeanDefinition

    使用過程的幾個問題:

  • 可以不可以在BeanFactoryPostProcessor去創建一個bean,這樣有什么問題?
  • 從技術上來說是可以的,但是正常情況下我們不該這么做,可能會存在該執行的bean工廠后置處理器沒有被應用到這個bean上

  • BeanFactoryPostProcessor可以被配置為懶加載嗎?
  • 不能,即使配置了也不會生效,我們將bean工廠后置處理器配置為懶加載這個行為本身就沒任何意義

    總結:

    在這篇文章中,我們最需要了解及掌握的就是BeanFactoryPostProcessor執行的順序,總結:

    • 先執行直接實現了BeanDefinitionRegistryPostProcessor接口的后置處理器,所有實現了BeanDefinitionRegistryPostProcessor接口的類有兩個方法,一個是特有的postProcessBeanDefinitionRegistry方法,一個是繼承自父接口的postProcessBeanFactory

    postProcessBeanDefinitionRegistry方法早于postProcessBeanFactory

    方法執行,對于postProcessBeanDefinitionRegistry的執行順序又遵循如下原子:

    a. 先執行實現了PriorityOrdered接口類中的postProcessBeanDefinitionRegistry方法

    b. 再執行實現了Ordered接口類中的postProcessBeanDefinitionRegistry方法

    c. 最后執行沒有實現上面兩個接口類中的postProcessBeanDefinitionRegistry方法

    執行完所有的postProcessBeanDefinitionRegistry方法后,再次執行實現了

    BeanDefinitionRegistryPostProcessor接口類中的postProcessBeanDefinitionRegistry方法

    • 再執行直接實現了BeanFactoryPostProcessor接口的后置處理器

    a. 先執行實現了PriorityOrdered接口類中的postProcessBeanFactory方法

    b. 再執行實現了Ordered接口類中的postProcessBeanFactory方法

    c. 最后執行沒有實現上面兩個接口類中的postProcessBeanFactory方法

    不吃竹子的滾滾:Spring源碼分析(十四)Spring中的BeanWrapper及類型轉換

    不吃竹子的滾滾:Spring源碼分析(十二)ApplicationContext詳解(中)

    不吃竹子的滾滾:Spring源碼分析(十一)ApplicationContext詳細介紹(上)

    不吃竹子的滾滾:Spring源碼分析(十)Spring中Bean的生命周期(下)

    不吃竹子的滾滾:Spring源碼分析(九)Spring中Bean的生命周期(上)

    不吃竹子的滾滾:Spring源碼分析(八)容器的擴展點(BeanPostProcessor)

    不吃竹子的滾滾:Spring源碼分析(七)容器的擴展點(FactoryBean)

    不吃竹子的滾滾:Spring源碼分析(六)容器的擴展點(BeanFactoryPostProcessor)

    不吃竹子的滾滾:Spring源碼分析(五)BeanDefinition(下)

    不吃竹子的滾滾:Spring源碼分析(四)BeanDefinition(上)

    不吃竹子的滾滾:Spring源碼分析(三)自動注入與精確注入

    不吃竹子的滾滾:Spring源碼分析(二)依賴注入及方法注入

    不吃竹子的滾滾:Spring源碼分析(一)Spring容器及Spring Bean

    總結

    以上是生活随笔為你收集整理的beanfactorypostprocessor_Spring源码分析(六)容器的扩展点(BeanFactoryPostProcessor)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。