章節地址 ###7.6自定義一個bean的生命 (nature) ####7.6.1 lifecycle callbacks(生命週期回調) 與容器的bean的生命週期管理相關,你可用實現spring的InitializingBean和DisposableBean接口.對於前者,容器調用afterPropertiesSet()方法,對於後者,容器調用destroy()方法,容許你在bean的初始化和銷燬中添加一些行爲.html
通常而來,spring框架使用BeanPostProcessor實現來處理任何它能發現的回調接口並調用正確的方法.若是你要自定義spring沒有提供開箱即用的功能或其餘生命週期行爲,你能夠本身實現一個 BeanPostProcessor接口.對於更多信息,查看Section 5.8,"Container Extension Points".java
另外對於初始化和銷燬回調,spring管理的對象也能夠實現Lifecycle接口,這樣這些對象能夠做爲容器生命週期的驅動參與啓動和關閉過程.mysql
生命週期回調會在這節描述
####初始回調 org.springframework.beans.factory.IntializingBean接口容許一個bean在bean的全部屬性被容器設置以後參與初始化工做.InitializingBean接口指定了一個單獨的方法:web
void afterPropertiesSet() throws Exception;
提醒一下,你沒有必要使用InitializingBean接口,由於你沒有必要同spring代碼耦合.另外,你也可使用@PostConstruct註解或者指定一個POJO初始化方法.這xml-based 的配置元數據下,你可使用init-method屬性來指定方法的名稱,但該方法必須是無參的.在java配置下,你可使用@Bean的initMethod屬性.詳情查看Recieving lifecycle callbacks. 例如:spring
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/> public class ExampleBean { public void init() { // do some initialization work } }
他等同於sql
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/> public class AnotherExampleBean implements InitializingBean { public void afterPropertiesSet() { // do some initialization work } }
但上一個例子不會和spring耦合. ###Destruction callbacks (銷燬回調) 實現org.springframework.beans.factory.DisposableBean接口能夠容許一個bean在持有它的容器在銷燬時獲得一個回調.DisposableBean接口只申明瞭一個方法.數據庫
void destroy() throws Exception;
你不須要使用DisposableBean回調接口,由於你不必同spring代碼耦合.另外,使用@PreDestroy註解或制定一個被該bean定義支持的泛型方法.在基於xml的配置元數據中,你可使用<bean/>定義裏的destroy-method屬性.在java配置中,你可使用@Bean的destroyMethod屬性.查看Recieving lifecycle callbacks;apache
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/> public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
等同於下面編程
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/> public class AnotherExampleBean implements DisposableBean { public void destroy() { // do some destruction work (like releasing pooled connections) } }
但上例無spring代碼耦合.app
####默認的初始化和銷燬方法(Default initialization and destroy methods)
當你編寫初始化和銷燬方法回調而不使用spring特定的InitializingBean和DisposableBean回調接口時,通常而言,你須要將這些方法名爲init,initialze,dispose等.一個項目中關於生命週期回調的方法名稱最好標準化,這樣全部的開發者可使用它們並保持一致.
你能夠配置spring容器使其去查找每個bean上的名字類似的初始化和銷燬回調方法.這意味着你做爲一個應用開發者,能夠編寫本身的應用classes,並使用一個叫inti()的初始化回調方法,而不須要在再每一個類定義上配置init-method="init".當這些bean被建立時,spring容器會調用這些方法(與以前提到的生命週期契約一致).這個功能強制要求初始化和銷燬方法有一個贊成的命名規範.
假設你的初始化回到方法都命名爲init(),銷燬回調方法命名爲destroy(),你的以下組裝你的類: public class DefaultBlogService implements BlogService {
private BlogDao blogDao; public void setBlogDao(BlogDao blogDao) { this.blogDao = blogDao; } // this is (unsurprisingly) the initialization callback method public void init() { if (this.blogDao == null) { throw new IllegalStateException("The [blogDao] property must be set."); } } }
xml定義以下: <beans default-init-method="init">
<bean id="blogService" class="com.foo.DefaultBlogService"> <property name="blogDao" ref="blogDao" /> </bean> </beans>
在高級的<beans/>元素裏的default-init-method屬性,可使spring容器在Beans裏查找一個叫init的方法來做爲初始化方法回調.當一個bean被建立或裝配,若是這個bean有該方法,它就會在合適的時間調用.
你能夠在beans元素裏經過default-destroy-method方法來配置銷燬方法.
當已存在的bean有命名約定變種的回調方法時,你能夠用<bean>屬性裏的init-method和destroy-method方法來指定他們的方法名稱.
spring容器保證每個bean被全部的依賴組裝完以後,其配置的初始化回調能夠被及時的調用.所以這些方法被原生的bean的引用調用,這意味着這意味着AOP攔截器沒有對這些bean起做用.一個目標被徹底建立,而後一個AOP代理以及相關的攔截器鏈就會被申請.若是這個目標bean和代理被定義爲分離,你的代碼甚至能夠繞過代理,直接訪問目標bean.所以,並不老是要用攔截器來調用初始化方法,由於這樣的話會使目標類的生命週期和它的代理/攔截器耦合並在你的代碼同原生目標類交互時留下奇怪的代碼.
####Combining lifecycle mechanisms(組合生命週期機制) 在spring 2.5中,你有三個選項來控制生命週期行爲:InitializingBean和DisposableBean回調接口,自定義init()和destroy()方法,@PostConstruct和@PreDestroy註解.你可使用這些機制來控制一個特定的bean.
可是,若是配置了相同的方法名稱.例如,對於一個叫init的初始化方法,對於多個生命週期機制,這個方法只被執行依次,緣由之後章節介紹.
同一個bean混合生命週期機制中的不一樣的初始化方法,會以下調用
銷燬方法同上:
####啓動和關閉回調(Startup and shutdown callbacks) Lifecycle接口定義了任何有本身生命週期需求的對象的必要的方法(例如開始和結束一些後臺進程)
public interface Lifecycle { void start(); void stop(); boolean isRunning(); }
全部的被spring管理的對象能實現該接口.而後,當ApplicationContext接受到啓動或中止標誌,好比在運行時中止/重啓場景,它會級聯調用這些被上下文定義的生命週期實現.這個操做是經過代理LifecycleProcessor來實現.
public interface LifecycleProcessor extends Lifecycle { void onRefresh(); void onClose(); }
注意,LifecycleProcessor自身實現了對Lifecycle接口的擴展.它添加了兩個方法來對應上下文的刷新和關閉.
注: 要明白org.springframework.context.lifeCycle接口這是一個對啓動/中止通知的顯示契約,並不意味着它會在上下文刷新時自動重啓.能夠考慮使用實現org.springframework.context.SmartLifecycle來替代對一個bean的自動啓動方法更好控制.另外,請明確,中止通知不會先於銷燬.在常規的中止中,全部的生命週期bean會在銷燬回調信號傳播以前先接受中止信號.可是,在一個上下文生命週期的熱啓動或者終止刷新嘗試,只有銷燬方法被調用.
啓動和關閉調用的順序很是重要.若是兩個對象間有依賴關係,那麼依賴的一方要晚於它的依賴啓動,而且要早於它的依賴中止.可是,有時直接依賴是不可知的.你可能只知道一些類的對象要比其餘類的對象先啓動.不少狀況下,SmartLifecycle接口定義了其餘選項,一個繼承了Phased接口的名爲getPhase()方法.(phase:階段,層次)
public interface Phased { int getPhase(); } public interface SmartLifecycle extends Lifecycle, Phased { boolean isAutoStartup(); void stop(Runnable callback); }
當啓動時,最低階段的對象先啓動,當中止時,這個順序相反.所以,當一個實現了SmartLifecycle接口的對象,經過getPhase()方法返回了Integer.MIN_VALUE,它將是最早啓動和最後關閉的.反之,若是階段值是Integer.MAX_VALUE,則代表該對象是最後啓動並最早中止(由於它依賴其餘運行的進程).當思考階段值時,對於一些沒有實現SmartLifecycle接口的對象來默認值很是重要,默認值是0.因此,任何負值都代表一個對象應該在標準組件以前啓動(在他們以後中止),當值爲正數則反之.
如你所見SmartLifecycle定義的中止方法接受一個回調.任何實如今該實現完整的中止一個進程時,必須回調的run()方法.這樣對於保持同步很是有必要,由於LifecycleProcessor接口的默認實現,DefaultLifecycleProcessor須要等待各個階段對象集合要調用的超時值.默認的各個階段的超時值是30秒.你能夠在上下文裏定義一個名叫"lifecycleProcessor"的 bean重寫默認的生命週期處理器.若是你只想改變超時時間,能夠按下面的例子:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor"> <!-- timeout value in milliseconds --> <property name="timeoutPerShutdownPhase" value="10000"/> </bean>
如上所示,LifecycleProcessor接口也定義了刷新和關閉上下文的方法回調.當上下文被關閉時,若是其stop()方法被明確調用,這將會簡化關閉的過程.'refresh'回調保證了SmartLifecycle beans的另外一個功能.當上下文被刷新(在全部的對象都被實例化和初始化後),這個回調會被調用,並且此時默認的生命週期處理器會檢查每一個SmartLifecycle對象的isAutoStartup()方法返回的boolean值.若是值爲"true",那麼該對象將會在此時啓動,而不是等待一個上下文明確的調用或本身的start()方法(不一樣於上下文刷新,對於一個標準的上下文實現來講,上下文啓動不會自動發生).不一樣依賴關係間的階段值決定他們的啓動順序,和上文描述的相同.
####如何優雅的在non-web應用中中止spring ioc容器(Shutting down the Spring IOC container gracefully in non-web applications)
這個部分只適用於非web應用.spring的基於web的上下文實現早已有了當相關web應用中止時,如何優雅關閉spring IOc容器上下文的代碼.
若是你在非web應用環境中使用spring ioc容器;例如,在一個非客戶端桌面環境中,你註冊了一個JVM關閉的鉤子.這樣作能夠保證一個優雅的關閉,調用你全部單例bean的銷燬方法全部全部的資源會獲得釋放.固然,你必須一直正確的配置和實現這些銷燬回調.
要註冊一個關閉鉤子,你能夠調用在ConfigurableApplicationContext接口上申明的registerShutdownHook()方法.
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public final class Boot { public static void main(final String[] args) throws Exception { ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext( new String []{"beans.xml"}); // add a shutdown hook for the above context...添加鉤子 ctx.registerShutdownHook(); // app runs here...app運行 // main method exits, hook is called prior to the app shutting down... //若是存在main方法,app關閉時,鉤子先調用 } }
####7.6.2 ApplicationContextAware and beanNameAware 當一個ApplicationContext建立了一個實現了org.springframework.context.ApplicationContextAware接口的實現對象實例時,該實例將會配置指向該ApplicationContext的引用.
public interface ApplicationContextAware{ void setApplicationContext(ApplicationContext applicationContext) throws beansException; }
這些beans能夠用程序來操做建立它們的ApplicationContext,經過ApplicationContext接口,或者將其強轉爲該接口的一個已知的子類,例如ConfigurableApplicationContext(它會暴露其餘的功能).一種用戶就是能夠程序式的獲取其餘beans.有時這個功能頗有用,然而,你通常要避免使用它,由於這會形成與spring的代碼耦合,也不符合控制反轉的風格(協做對象將屬性的形式提供給beans).ApplicationContext提供了其餘功能:訪問文件系統,發佈應用事件,訪問messageSourece.其餘功能可查看Section 7.15 "Additional Capabilities of the Application context"
在spring2.5,自動注入是另外一種方式獲取ApplicationContext的引用.傳統的constructor和byType注入模式將分別爲構造器參數或setter方法屬性提供一個ApplicationContext類型的依賴.爲了更好的靈活性,也爲了注入字段和混合參數方法,使用了基於註解的注入功能.若是你這麼作,這個ApplicationContext會注入到指望ApplicationContext類型的字段,構造器參數,或者方法參數中,只要這個字段,構造器,或方法持有@Autowired註解.對於更多的信息,查看Section 7.9.2,"@Autowired".
當一個ApplicationContext建立了一個實現了org.springframework.beans.factory.BeanNameAware接口的類是,這個類會被提供了一個引用去設置它協做對象的命名定義.
public interface BeanNameAware { void setBeanName(String name) throws BeansException; }
這個回調調用順序:在正常bean屬性被操做以後,在初始化以前(如InitializingBean的afterPropertiesSet方法或者一個自定義的init-method方法)
####7.6.3 Other Aware interfaces(其餘感知接口) 除了以上討論的applictionContextAware和BeanNameAware外,spring還提供了一些其餘Aware接口,容許beans來指向容器,但他們須要一些基礎依賴.很是重要的感知接口總結以下,你可用經過依賴的類型來區分它的名字
name injected Dependency ApplicationContextAware Declaring ApplicationContext ApplicationEventPublisherAware Event publisher of the enclosing ApplicationContext BeanClassLoaderAware Class loader used to load the bean classes BeanFactoryAware Declaring BeanFactory BeanNameAware Name of the declaring bean BootsrapContextAware 容器在資源適配器BootstrapContext中運行,通常只在JCA感知的ApplicationContext中得到 LoadTimeWeaverAware MessageSoureceAware 釋放消息的配置策略,支持參數化和國際化 NotificationPublisherAware spring JMX 提醒發佈者 PortletConfigtAware 容器運行的當前PortletConfig,web應用專用 PortlerContextAware 容器運行的當前PortletContext,web應用專用 ResourceLoaderAware 低級別的資源訪問的配置的加載器 ServletConfigAware 容器運行的當前ServletConfig.只能在web應用中獲取 ServletContextAware 容器運行的當前ServletContext,只在web應用中獲取
注意這些接口的使用會使你的代碼和spring耦合,且不符合控制反轉風格.所以,他們被推薦爲須要對容器進行編程訪問的基礎組件Bean.
##7.8 Container Extension Points(容器擴展點) 通常而言,應用開發者不須要ApplicationContext實現的子類.替代的是,spring ioc容器能夠經過插入特定的集成接口來擴展.本節描述這些集成接口. ###7.8.1 Customizing beans using a BeanPostProcessor BeanPostProcessor 接口能夠定義一個回調方法,你能夠實現來提供本身的(或重寫容器默認的)實例化邏輯,依賴解決邏輯等等.若是你打算在spring 容器完成實例化,配置,初始化以後,你能夠插入一兩個BeanPostProcessor的實現.
你能夠配置混合BeanPostProcessor實例,你能夠經過設置order屬性來控制這些BeanPostProcessor執行的順序.不過只有當你實現了Ordered接口時才能設置該屬性.因此你須要考慮是否實現Ordered接口.對於更多的細節,參考BeanPostProcessor和Odered接口文檔.也能夠查看programmatic registration of BeanPostProcessor
BeanPostProcessor操做bean的實例,也就是說Spring ioc容器實例化一個bean的實例,而後BeanPostProcessor進行他們的工做.
BeanPostProcessors 的做用域是每一個容器.你正在使用容器層次結構時,這是惟一相關的.若是你在容器中定義一個BeanPostProcessor,那麼容器中只有一個post-processbean.那麼它們會後置處理容器裏的bean.換句話說,一個容器裏bean是不會被其餘bean處理的,即便這兩個容器部分結構相同.
要改變實際的bean定義(bean定義藍色的印刷體),你須要使用7.8.2裏描述的BeanFactoryPostProcessor.
org.springframework.beans.factory.config.BeanPostProcessor接口實際上由兩個回調方法組成.當一個類被註冊爲容器的post-process時,每一個bean的實例被容器建立時,該Post-process會在容器初始化方法以前(例如InitializingBean的afterPropertiesSet或其餘初始化方法),bean自身初始化回調以後獲得一個回調.這些後置處理器能夠對bean實例作任何操做,包括徹底忽略其餘回調.一個後處理器的bean通常會檢查回調接口或者將Bean裝入一個代理裏.一些spring AOP的組件類有時會做爲 bean的後處理器來實現以提供相應代理注入邏輯.
一個ApplicationContext自動檢測任何在配置元數據中定義的實現了BeanPostProcessor接口的bean.ApplicationContext將這些beans註冊爲後處理器,這樣它們能夠在其餘bean建立以後回調.bean的後處理器能夠在容器裏像其餘bean同樣部署.
記住,當你使用@Bean的工廠方法在一個配置類裏申明一個BeanPostProcessor時,這個工廠方法的返回類型應該是其自己的實現或至少是org.springframework.beans.factory.config.BeanPostProcessor接口,以清晰的指明其位一個後處理器.不然,ApplicationContext將沒法在它徹底建立以前經過類型自動檢測到它.因爲BeanProcessor須要儘早實例化已供上下文中其餘bean實例化以後調用,因此儘早的類型檢測很重要.
上文已說過BeanProcessor註冊經過ApplicationContext來自動檢測,你也能夠在ConfigurableBeanFactory裏使用addBeanPostProcessor方法來註冊它們.你能夠在註冊以前來進行邏輯判斷或你能夠在層次結構裏經過上下文複製一個post processors.雖然BeanPostProcessor能夠程序化添加,但與Ordered接口無關.bean處理器啓動的順序和它註冊的順序同樣.記住,經過程序註冊的BeanPostProcessor的啓動要早於自動檢測發現的處理器,無關於具體的order值.
實現BeanPostProcessor接口的類都是特殊的,由容器區別對待.全部的bean後處理器和他們引用的bean會在容器啓動就會做爲ApplicationContext特定的啓動階段進行自動實例化.接下來,全部的bean後處理器都會被有序註冊,並被容器裏其餘bean調用.由於AOP的自動代理是做爲一個BeanPostProcessor實現的,無論BeanPostProcessor仍是他們直接引用的bean都不適合自動代理.因此你不須要向它們注入切面.
對於這些bean,你應該看過這樣一條信息日誌消息:"bean foo沒有被全部的BeanPostProcessor接口處理(例如,不適合動態代理)"
記住:若是注入到你的BeanPostProcessor的bean使用了autowiring或@Resource(可能會降級到autowiring),當spring進行類型匹配搜索時,可能會獲得意外的beans,所以使他們不適合自動代理其餘類的bean後處理.例如,若是你有一個@Resource的依賴,它的位置的field/setter沒有同bean的名字相匹配,或者沒有使用name屬性,那麼spring將會經過類型匹配來訪問其餘beans.
下面的例子展現如何在ApplicationContext中編寫,註冊,使用BeanPostProcessor.
###Example:Hello World,BeanPostProcessor-style
第一個例子展現了基本用法,介紹了一個BeanPostProcessor的實現容器建立時如何調用在每一個bean的toString()方法,並將它們打印在系統控制檯上.
查看下面的BeanProcessor的自定義實現;
package scripting; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.BeansException; public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor { // simply return the instantiated bean as-is public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; // we could potentially return any object reference here... } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("Bean '" + beanName + "' created : " + bean.toString()); return bean; } }
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://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同樣被依賴注入.(上述的配置被一個Groovy 腳本定義,spring動態語言支持查看35章)
下面是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 = (Messenger) ctx.getBean("messenger"); System.out.println(messenger); } }
上面的應用輸出以下:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961
####例子:RequiredAnnotationBeanPostProcessor 在聯結一個自定義的BeanPostProcessor實現時使用回調接口或者註解是擴展spring ioc容器的一個通用方法.一個例子是Spring的RequiredAnnotationBeanPostProcessor,一個BeanPostProcessor的實現,能夠保證每一個被註解標註的javaBean的屬性都會注入一個實際值.
###7.8.2 經過beanFactoryPostProcessor來自定義配置元數據 下一個擴展點是beanFactory後處理器(org.springframework.beans.factory.config.BeanFactoryPostProcessor).它在語義上同BeanPostProcessor類似,但有一個主要區別:BeanFactory後處理器能夠讀取配置元數據,即spring ioc容器容許一個BeanFactory後處理器來讀取配置元數據並可以在容器實例化除了BeanFactoryPostProcessor以外的bean以前來改變元數據. 你能夠配置混合的BeanFacotryPostProcessor,並經過order屬性來控制這些BeanFacotryPostProcessor的執行順序.不過,只有你實現了Ordered接口才能設置該屬性.若是你要寫你本身的BeanFactoryPostProcessor,你須要考慮是否實現Order接口.你能夠經過查閱BeanFactoryProcessor和Order接口的文檔來了解更多細節.
你要改變一個實際的bean實例,能夠經過BeanPostProcessor來實現.可是若是你用BeanFactory來實例化Bean,會致使實例提早產生,這樣會破壞原有的容器生命週期;這樣還有其餘負面影響,如繞過bean後處理.
另外,beanFactoryPostProcessor的定義域是容器級的.當你使用容器層次結構時,才與之相關.不能被其餘容器使用.哪怕該容器有相同的結構.
一個Bean工廠後處理器在一個ApplicationContext裏申明以後就會執行,用來改變定義容器的配置元數據.spring中包含了大量的已定義的bean工廠後處理器,例如PropertyOverrideConfigurer和PropertyPlaceholderConfigurer.例如,一個自定義的BeanFactoryPostProcessor也能夠用來註冊一個自定義屬性編輯器.
應用上下文將會自動檢測全部實現BeanFactoryPostProcessor接口的bean.它會在適合的時候將這些Bean當作bean工廠後處理器來使用.你能夠像其餘bean同樣來部署他們.
實例化配置:你不須要將工廠後處理器設置爲懶實例化.若是沒有其餘bean指向BeanPostProcessor,那麼後處理器將不會實例化.並且,將它設爲懶初始化會被忽略.即便你在beans元素裏設置了deault-lazy-init屬性爲true,也沒用.
####例子: 類名稱屬性提示配置器 你能夠經過PropertyPlaceholderConfigurer來實例化bean定義的屬性值,在一個獨立的使用標準java屬性格式的文件裏.這樣作能夠保證用戶經過自定義環境特定的屬性(如數據庫鏈接或密碼)來部署一個應用,且沒有修改容器裏主要xml定義文件的風險和困難.
思考下面的基於xml的元數據配置中,數據庫屬性定部分.這個例子展現了經過實例化屬性文件來配置屬性.在運行時,一個PropertyPlaceholderConfigure將會用來替換DataSource數據裏的部分屬性.他們以${property-name}的形式來替換屬性
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:com/foo/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屬性格式配置的實際值:
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
因此,這個字符串${jdbc.username}將會被替換爲運行時的值'sa',其餘的值也如此.另外,這個placeholder的前綴和後綴也能夠自定義.
spring2.5裏引入了context命名空間,它能夠經過一個檢測的配置元素來配置屬性提醒器.一個或更多的位置能夠經過location屬性列表的形式來提供.
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
PropertyPlaceholderConfigurer不只能夠經過Properties來查找屬行.默認的它還能夠檢測java系統屬性,若是他沒有在特定的屬性文件裏找到這些屬性.你能夠經過配置器的systemPropertiesMode屬性來配置其行爲,有如下三個值:
never(0);歷來不檢測系統屬性;
fallback(1):若是在屬性文件裏發現則檢測系統屬性,此爲默認.
override(2):在檢測特定屬性文件前,先檢測系統屬性.它容許系統屬性來重寫這些屬性資源.
查閱PropertyPlaceholderConfigurer的java文檔來獲取更多信息. 另外一種配置形式; <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath:com/foo/strategy.properties</value> </property> <property name="properties"> <value>custom.strategy.class=com.foo.DefaultStrategy</value> </property> </bean>
<bean id="serviceStrategy" class="${custom.strategy.class}"/>
在PropertyPlaceholderConfigurer的properties屬性裏添加配置值.<value>custom.strategy.class=com.foo.DefaultStrategy</value>,下面就能夠經過${custom.strategy.class}來配置了. ####例子:屬性重寫配置器 the PropertyOverrideConfigurer 這個PropertyOverrideConfigurer,組成了PropertyPlaceholderConfigurer,卻和後者不一樣.若是一個重寫的屬性文件裏沒有特定bean的屬性值,那麼原來的值還有用.
bean定義不會察覺哪一個bean的屬性重寫,根據重寫機制,若是一個屬性有多個值,那麼最後一個值會勝出.
屬性配置文件單行寫法以下:
beanName.property=value
例如:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
這樣將會重寫dataSource的Bean的driverClassName和url屬性.
固然你能夠這麼定義:foo.fred.bob.sammy=123,前提是你的屬性會被容器初始化.spring2.5引入了context命名空間,你能夠這樣配置屬性重寫器:
<context:property-override location="classpath:override.properties"/>
###7.8.3 Customizing instantiation logic with a FactoryBean(自定義工廠bean的初始化邏輯) 實現了org.springframework.beans.factory.FactoryBean接口的均可以看作是本身的工廠類;
工廠類接口是spring ioc容器初始化邏輯中一個可插拔的點.在複雜的初始化代碼上,相對於冗長的xml文件,若是你有更好的java代碼表現,你能夠建立本身的FactoryBean,將這些複雜的初始化代碼寫在類裏,並將你的自動以FactoryBean推到容器裏.
FactoryBean接口提供了三個方法:
FactoryBean的概念和接口在spring不少地方使用,spring本身有超過50個FactoryBean實現;
當你須要一個工廠Bean的實例時,你須要使用ApplicationContext的getBean()方法,而後參數爲bean的id加上&符號;如調用getBean("myBean")返回bean的實例,調用getBean("&myBean"),則返回其工廠Bean.