亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

BeanDefinition繼承與容器拓展點是什么

發布時間:2021-12-02 17:17:28 來源:億速云 閱讀:145 作者:柒染 欄目:大數據

這篇文章將為大家詳細講解有關BeanDefinition繼承與容器拓展點是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

1.7 Bean Definition繼承

bean定義包含一些配置信息,包括構造函數參數、屬性值、和容器特定信息,例如初始化方法、靜態工廠方法名等等。子bean定義繼承父bean定義配置數據。子bean定義能夠覆蓋一些值或者增加其他需要。使用父bean和子bean定義能夠保存一些類型。實際上,這是一種模版模式。

如果你編程式使用ApplicationContext接口,子bean定義通過ChildBeanDefinition類描述。大多數用戶不在這個級別使用(備注:應用開發人員一般不會接觸)。相反,它們在例如ClassPathXmlApplicationContext之類的類中聲明性地配置bean定義。當你使用基于XML配置元數據,你可以通過使用parent屬性指示一個子bean的定義,指定parent bean作為這個屬性的值。下面例子顯示怎樣做:

<bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>
<!--parent指定繼承父類-->
<bean id="inheritsWithDifferentClass"
        class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">  
    <property name="name" value="override"/>
    <!-- the age property value of 1 will be inherited from parent -->
</bean>

如果沒有指定,子bean定義將使用父定義中的bean類,但也可以覆蓋它。在后面這種情況下,子bean類必須兼容父bean定義(也就是說,必須接受父bean的屬性值)。

bean定義繼承作用域、構造參數值、屬性值、和覆蓋父類方法,并可以添加新值。任何作用域、初始化方法、銷毀方法或static工廠方法設置都會覆蓋對應的父bean設置。

其余設置始終從子bean定義中獲取:依賴、自動裝配、依賴檢查、單例和懶加載。

前面的例子通過使用abstract屬性顯示標記父bean定義作用一個抽象,如果父bean定義沒有指定類,顯示地標記父bean定義為abstract是需要的,像下面例子展示:

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override"/>
    <!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

bean不能被實例化,因為它是不完整的,并且它被顯示的標記為abstract。當一個定義是abstract,它僅僅作為一個bean定義的模版且父bean定義為子bean定義服務。嘗試自己使用這樣的抽象父bean,通過將其引用為另一個beanref屬性或使用父bean ID進行顯式的getBean()調用將返回錯誤。類似地,容器的內部preInstantiateSingletons()方法將忽略定義為抽象的bean定義。

默認情況下,ApplicationContext會預先實例化所有單例。因此,重要的是(至少對于單例bean),如果有一個(父)bean定義僅打算用作模板,并且此定義指定了一個類,則必須確保將abstract屬性設置為true ,否則應用程序上下文將實際上(試圖)預先實例化抽象Bean

參考實例:com.liyong.ioccontainer.starter.XmlBeanDefinitionInheritanceContainer

1.8 容器拓展點

典型地,應用程序開發者不需要實現ApplicationContext類。相反,Spring IoC容器通過插件實現指定的集成接口去擴展。下面的章節描述這些接口的集成。

1.8.1 通過使用BeanPostProcessor自定義bean

BeanPostProcessor接口定義回調方法,你可以實現這個接口提供你自己的(或者覆蓋容器的默認設置)初始化邏輯、依賴解析邏輯等等。如果你想實現一些自定義邏輯,在Spring容器完成實例化、配置、初始化bean之后,你可以插入一個或多個自定義BeanPostProcessor實現。

你可以配置多個BeanPostProcessor實例并且你可以通過設置order屬性來控制這些BeanPostProcessor實例的執行順序。僅僅BeanPostProcessor實現Ordered接口是可以設置這個屬性。如果自己實現BeanPostProcessor,你應該考慮實現Ordered接口。更多詳情,查看 BeanPostProcessorOrdered接口。參見有關以編程方式注冊BeanPostProcessor實例的說明。

BeanPostProcessor接口在bean(對象)實例上操作。也就是說,Spring IoC容器實例化一個bean實例,然后BeanPostProcessor實例執行它們的工作。(備注:在Spring容器初始化bean過程中執行相關的回調操作)

BeanPostProcessor實例是按容器劃分作用域。僅僅在使用繼承容器才有意義。如果在一個容器中定義BeanPostProcessor,僅僅在那個容器中的bean被后置處理。換句話說,定義在一個容器中的bean不會被在其他容器定義的BeanPostProcessor所處理,即使兩個容器都屬于同一層次結構。

改變實際bean定義(也就是定義bean的藍圖),你需要使用BeanFactoryPostProcessor,如使用BeanFactoryPostProcessor自定義配置元數據中所述。

org.springframework.beans.factory.config.BeanPostProcessor接口恰好地由兩個回調方法組成。當一個類作為后置處理起被注冊到容器中時,對于每個被容器創建bean實例,后置處理器從容器初始化方法(例如:InitializingBean.afterPropertiesSet()或者任何被聲明init方法)被調用之前,并且任何bean初始化回調之后獲得回調。后置處理器能夠處理bean實例任何操作,包括忽略所有的回調。Bean后處理器通常檢查回調接口,或者可以用代理包裝BeanSpring AOP基礎設施類中實現bean的后置處理去提供一個代理包裝邏輯。

ApplicationContext自動的檢查所有bean,這些bean在配置元數據中實現了BeanPostProcessor接口。ApplicationContext注冊這些bean作為后置處理器,以便以后在創建bean時可以調用它們。Bean后處理器可以與其他bean相同的方式部署在容器中。

注意,當通過在類上使用@Bean工廠方法聲明BeanPostProcessor時,工廠方法返回類型應該是實現類本身或只是實現org.springframework.beans.factory.config.BeanPostProcessor接口,清晰地表明該bean的后處理器性質。否則,ApplicationContext無法在完全創建之前按類型自動檢測它。由于BeanPostProcessor需要及早實例化才能應用于上下文中其他bean的初始化,因此這種早期類型檢測至關重要。

編程式地注冊BeanPostProcessor實例

推薦的去注冊BeanPostProcessor方式是通過ApplicationContext自動檢測(前面描述),可以使用addBeanPostProcessor方法以編程方式針對ConfigurableBeanFactory注冊它們。當注冊之前你需要評估條件邏輯甚至需要跨層次結構的上下文復制后置處理器時,這是非常有用的。注意,然而,BeanPostProcessor實例編程式的添加不遵循Ordered排序接口。在這里,注冊的順序決定了執行的順序。<u>需要注意是編程式的注冊BeanPostProcessor實例總是在這些通過自動檢測的后置處理器之后被處理,而不管顯示的順序</u>。

BeanPostProcessor實例和AOP自定代理

實現BeanPostProcessor接口的類是特殊的,并且容器對它們的處理方式有所不同。在啟動時會實例化它們直接引用的所有BeanPostProcessor實例和Bean,這是ApplicationContext特殊啟動階段的一部分。接下來,以排序方式注冊所有BeanPostProcessor實例,并將其應用于容器中的所有其他bean。因為AOP自動代理是作為BeanPostProcessor本身實現的,所以BeanPostProcessor實例或它們直接引用的bean都不適合進行自動代理,因此,沒有編織的方面。

對于任何這樣的bean,你應該查看日志消息:

Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying).

如果你有通過使用自動裝配或@Resource注入beanBeanPostProcessor中(可能回退到自動裝配),當搜索類型匹配的依賴項候選者時,Spring可能會訪問意外的Bean,因此使它們不適合進行自動代理或其他類型的Bean后處理。例如,如果你有一個用@Resource標注的依賴項,其中字段或Setter名稱不直接與bean的聲明名稱相對應,并且不使用name屬性,那么Spring將訪問其他bean以按類型匹配它們。

下面的例子展示了在ApplicationContext中怎樣去編寫、注冊和使用BeanPostProcessor接口。

例子:Hello World

第一個例子說明基礎的使用。這個例子展示一個自定義BeanPostProcessor實現并調用通過容器創建的每個beantoString()方法并且打印結果字符串到控制臺。

下面的清單展示了自定義BeanPostProcessor實現類定義:

package scripting;

import org.springframework.beans.factory.config.BeanPostProcessor;

public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

    // simply return the instantiated bean as-is
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean; // we could potentially return any object reference here...
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) {
      //打印bean信息
        System.out.println("Bean '" + beanName + "' created : " + bean.toString());
        return bean;
    }
}

下面beans元素使用InstantiationTracingBeanPostProcessor

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/lang
        https://www.springframework.org/schema/lang/spring-lang.xsd">

    <lang:groovy id="messenger"
            script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
        <lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
    </lang:groovy>

    <!--
    when the above bean (messenger) is instantiated, this custom
    BeanPostProcessor implementation will output the fact to the system console
    -->
    <bean class="scripting.InstantiationTracingBeanPostProcessor"/>

</beans>

注意怎樣定義InstantiationTracingBeanPostProcessor。它甚至沒有名字,并且它是一個bean,可以像其他bean一樣被依賴注入。(前面的配置還定義了一個由Groovy腳本支持的beanSpring動態語言支持詳情在“動態語言支持”一章中。)

下面的Java應用程序運行前面的代碼和配置:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
        Messenger messenger = ctx.getBean("messenger", Messenger.class);
        System.out.println(messenger);
    }

}

前面的應用輸出結果類似下面:

Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
org.springframework.scripting.groovy.GroovyMessenger@272961

例子:RequiredAnnotationBeanPostProcessor

將回調接口或與自定義BeanPostProcessor實現結合使用是擴展Spring IoC容器常用方法。SpringRequiredAnnotationBeanPostProcessor是一個示例,它是Spring發行版附帶的BeanPostProcessor實現,可以確保標有(任意)注解的bean上的JavaBean屬性實際上(配置為)依賴注入了一個值。說明:就是常用的依賴注入。

參考代碼:com.liyong.ioccontainer.starter.XmlBeanPostProcessorIocContainer

1.8.2 BeanFactoryPostProcessor自定義配置元數據

下一個拓展點是org.springframework.beans.factory.config.BeanFactoryPostProcessor。這個接口語義類似BeanPostProcessor,一個重要的不同點:BeanFactoryPostProcessor是操作在bean的配置元數據上。也就是說,Spring IoC容器允許除BeanFactoryPostProcessor實例外其他任何bean被BeanFactoryPostProcessor讀取配置元數據和改變它。

你可以配置多個BeanFactoryPostProcessor實例,并且你可以通過設置order屬性在這些BeanFactoryPostProcessor實例上來控制順序。然而,如果BeanFactoryPostProcessor實現Ordered接口才能設置這個屬性。如果你寫自己的BeanFactoryPostProcessor,你應該考慮實現Ordered接口。更多關于BeanFactoryPostProcessorOrdered接口詳細信息。

如果想去改變實際bean實例(也就是,這個對象是從配置元數據被創建的),你需要使用BeanPostProcessor(前面描述通過使用BeanPostProcessor自定義bean)。從技術上講,可以在BeanFactoryPostProcessor中使用Bean實例(例如,通過使用BeanFactory.getBean()),這樣做導致過早的初始化bean,違反了標準容器生命周期。這會導致負面的影響,例如:繞過后置處理。

同樣,BeanFactoryPostProcessor實例是按容器劃分。(如果你使用分層的容器才會有意義) <u>如果你定義在容器中定義一個BeanFactoryPostProcessor,它僅適用于該容器中的bean定義。在一個容器中的bean定義不會被其他的容器中BeanFactoryPostProcessor后置處理,即使兩個容器在同一個層級</u>。

Bean工廠后處理器在ApplicationContext中聲明時會自動執行,以便將更改應用于定義容器的配置元數據。Spring包括一些預定義的工廠后置處理器,例如PropertyOverrideConfigurer

PropertySourcesPlaceholderConfigurer。你可以使用一個自定義的BeanFactoryPostProcessor-例如,注冊一個自定義屬性編輯器。

ApplicationContext自動地檢測任何部署到容器中并實現BeanFactoryPostProcessor接口的實例bean。使用這些bean作為bean工廠后置處理器,在適當的時間。你可以像其他ban一樣部署這些后置處理器。

BeanPostProcessors一樣,通常不希望配置BeanFactoryPostProcessors進行延遲初始。如果沒有其他bean引用Bean(Factory)PostProcessor,這個后置處理器不會被初始化。因此,標記它為延遲初始化將被忽略并且Bean(Factory)PostProcessor將被提前初始化即使你的<beans />聲明default-lazy-init屬性為true。

參考代碼:com.liyong.ioccontainer.starter.XmlBeanFactoryPostProcessorIocContainer

例如:類名替換PropertySourcesPlaceholderConfigurer

可以使用PropertySourcesPlaceholderConfigurer通過使用標準Java屬性格式將屬性值從bean定義外部化到一個單獨的文件中(意思是:bean配置數據可以配置到一個單獨文件中)。這樣做使部署應用程序的人員可以自定義特定于環境的屬性,例如數據庫URL和密碼,而無需為修改容器的主要XML定義文件而復雜或冒風險。

考慮下面基于XML配置元數據片段,DataSource使用占位符值定義:

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <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>

這個例子顯示從外部化Properties文件的屬性配置。在運行時,PropertySourcesPlaceholderConfigurer應用元數據替換DataSource的屬性值。將要替換的值指定為$ {property-name}格式的占位符,該格式遵循Antlog4jJSPEL樣式。

真實值來自于標準的Properties格式的其他文件:

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

因此,${jdbc.username}字符串在運行時被替換為sa值,并且同樣應用到其他的占位符在properties文件中匹配這些key。PropertySourcesPlaceholderConfigurer檢查Bean定義的大多數屬性和屬性中的占位符。此外,你可以自定義占位符的前綴和后綴。

context命名空間在Spring2.5中被引入,你可以配置一個專用配置元素的占位符。在location屬性中你可以提供一個或多個location通過逗號分隔,類似下面例子:

<context:property-placeholder location="classpath:com/something/jdbc.properties"/>

PropertySourcesPlaceholderConfigurer不僅僅在你指定的Properties中查找屬性。默認情況,如果在指定的屬性文件中沒有找到屬性,它會再次檢查Spring Environment屬性和常規的Java System屬性。

你可以使用PropertySourcesPlaceholderConfigurer去替代類名稱,有時候者非常有用,當你在運行時必須選擇一個特定的實現類。下面例子展示怎樣去做:

<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer">
 <property name="locations">
     <value>classpath:com/something/strategy.properties</value>
 </property>
 <property name="properties">
     <value>custom.strategy.class=com.something.DefaultStrategy</value>
 </property>
</bean>

<bean id="serviceStrategy" class="${custom.strategy.class}"/>

如果在運行時無法將類解析為有效的類,則在即將創建bean時,即在非lazy-init bean的ApplicationContextpreInstantiateSingletons()階段,bean的解析將失敗。

參考代碼:com.liyong.ioccontainer.starter.XmlPropertySourcesPlaceholderConfigurerIocContainer

例子:PropertyOverrideConfigurer

另一個bean工廠后處理器PropertyOverrideConfigurer類似于PropertySourcesPlaceholderConfigurer,但與后者不同,原始定義可以具有bean屬性的默認值,也可以完全沒有值。如果覆蓋的屬性文件對于一些bean屬性沒有符合內容,默認的上下文定義被使用。

注意:bean定義沒有意識到被覆蓋,因此從XML定義文件中不能立即看出覆蓋的配置正在被使用。由于存在覆蓋機制,在多個PropertyOverrideConfigurer實例情況下對應相同bean屬性不同的值,最后一個將被使用。

屬性文件配置格式:

beanName.property=value

下面清單顯示格式化例子:

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

此示例文件可與容器定義一起使用,容器定義包含一個名為dataSource的bean,該bean具有driverurl屬性。

復合屬性名也是被支持的,只要路徑的每個組件(被覆蓋的最終屬性除外)都是非空的(可能是由構造函數初始化的)。下面的例子,bean的tom屬性fredsammy屬性設置只123:

tom.fred.bob.sammy=123

指定的重寫值總是文本值。它們沒有被轉譯為bean引用。當XML bean定義中的原始值指定bean引用時,這種約定也適用。

context命名空間在Spring2.5中被引入,可以使用專用配置元素配置屬性覆蓋,類似下面例子:

<context:property-override location="classpath:override.properties"/>

參考代碼:com.liyong.ioccontainer.starter.XmlPropertyOverrideConfigurerIocContainer

1.8.3 FactoryBean自定義初始化邏輯

可以為本身就是工廠的對象實現org.springframework.beans.factory.FactoryBean接口。

這個FactoryBean接口是Spring IoC容器的實例化邏輯可插拔點。如果你有一個復雜的初始化代碼在Java中比冗余XML更好的表達,你可以創建你自己的FactoryBean,在實現類中寫復雜的初始化邏輯,然后插入你的自定義FactoryBean到容器中。

FactoryBean接口提供三個方法:

  • Object getObject():返回這個工廠創建的一個實例。這個實例可能被共享,依賴于這個工廠返回的是單例或原型。

  • boolean isSingleton():如果FactoryBean返回一個單例返回true否則為false

  • Class getObjectType():返回由getObject()方法返回的對象類型;如果類型未知,則返回null

FactoryBean概念和接口在Spring框架中一些地方被使用到。Spring有超過50個FactoryBean接口的實現。

當你需要向容器獲取一個實際的FactoryBean實例本身而不是由它產生的bean時請在調用ApplicationContext的getBean()方法時在該bean的ID前面加上一個符號。因此,對于id為myBean的給定FactoryBean,在容器上調用getBean(“myBean”)將返回FactoryBean的產生的bean,而調用getBean(“&myBean”)將返回FactoryBean實例本身。

關于BeanDefinition繼承與容器拓展點是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

比如县| 额尔古纳市| 丘北县| 红桥区| 那坡县| 武乡县| 鹤山市| 惠来县| 龙川县| 齐河县| 岳阳县| 社旗县| 夹江县| 宜都市| 枣庄市| 中宁县| 海口市| 汝城县| 隆化县| 固安县| 名山县| 新建县| 丰台区| 玉环县| 同心县| 连城县| 延川县| 呼伦贝尔市| 天峨县| 万盛区| 体育| 娄烦县| 龙门县| 五台县| 滨海县| 海晏县| 隆林| 石楼县| 宁晋县| 承德市| 曲水县|