Spring3開發實戰 之 第二章:IoC/DI開發(2) – JAVA編程語言程序開發技術文章

通過<list/>、<set/>、<map/>及<props/>元素可以定義和設置與Java Collection類型對應List、Set、Map及Properties的值 ,示例如下:

java代碼:
[java] 
<bean id="moreComplexObject" class="example.ComplexObject"> 
<property name="adminEmails"> 
<props> 
<prop key="administrator">admin@somecompany.org</prop> 
<prop key="support">support@somecompany.org</prop> 
</props> 
</property> 
<property name="someList"> 
<list> 
<value>a list element followed by a reference</value> 
<ref bean="myDataSource" /> 
</list> 
</property> 
<property name="someMap"> 
<map> 
<entry> 
<key> <value>yup an entry</value> </key> 
<value>just some string</value> 
</entry> 
<entry> 
<key> <value>yup a ref</value> </key> 
<ref bean="myDataSource" /> 
</entry> 
</map> 
</property> 
<property name="someSet"> 
<set> 
<value>just some string</value> 
<ref bean="myDataSource" /> 
</set> 
</property> 
</bean> 
可以定義parent-style和child-style的<list/>、<map/>、<set/>或<props/>元素,子集合的值從其父集合繼承和覆蓋而來;也就是說,父子集合元素合並後的值就是子集合中的最終結果,而且子集合中的元素值將覆蓋父集全中對應的值。

java代碼:
[java]
<beans> 
<bean id="parent" abstract="true" class="example.ComplexObject"> 
    <property name="adminEmails"> 
        <props> 
            <prop key="administrator">administrator@somecompany.com</prop> 
            <prop key="support">support@somecompany.com</prop> 
        </props> 
    </property> 
</bean> 
<bean id="child" parent="parent" class= " example.Child" > 
    <property name="adminEmails"> 
        <props merge="true"> 
            <prop key="sales">sales@somecompany.com</prop> 
            <prop key="support">support@somecompany.co.uk</prop> 
        </props> 
    </property> 
</bean> 
<beans> 
在上面的例子中,childbean的adminEmails屬性的<props/>元素上使用瞭merge=true屬性。當child bean被容器實際解析及實例化時,其 adminEmails將與父集合的adminEmails屬性進行合並 。
註意到這裡子bean的Properties集合將從父<props/>繼承所有屬性元素。同時子bean的support值將覆蓋父集合的相應值
不同的集合類型是不能合並(如map和 list是不能合並的),否則將會拋出相應的Exception。merge屬性必須在繼承的子bean中定義,而在父bean的集合屬性上指定的merge屬性將被忽略
在JDK5以上的版本裡,Spring支持強類型集合
<null/>用於處理null值,Spring會把屬性的空參數當作空字符串處理。
1:以下的xml片斷將email屬性設為空字符串。
<bean class="ExampleBean">
  <property name="email"><value></value></property>
</bean>
這等同於Java代碼: exampleBean.setEmail(“”)。
2:而null值則可以使用<null>元素可用來表示。例如:
<bean class="ExampleBean">
  <property name="email"><null/></property>
</bean>
上述的配置等同於Java代碼:exampleBean.setEmail(null)。
針對常見的value值或bean的引用,Spring提供瞭簡化格式用於替代<value/>和<ref/>元素 。如下:

java代碼:
[java] 
<property name="myProperty"> 
  <value>hello</value> 
</property> 
<property name="myProperty"> 
  <ref bean="myBean"> 
</property> 
<entry> 
  <key> 
    <ref bean="myKeyBean" /> 
  </key> 
  <ref bean="myValueBean" /> 
</entry> 
完全等同於
<property name="myProperty" value="hello"/>
<property name="myProperty" ref="myBean"/>
<entry key-ref="myKeyBean" value-ref="myValueBean"/>
 
強調一點
隻有<ref bean=“xxx”>元素的簡寫形式,沒有<ref local=“xxx”>的簡寫形式。也就是說<property name=“myProperty” ref=“myBean”/> 裡面的ref是相當於<ref bean=“”>的形式。
組合屬性名稱
當設置bean的組合屬性時,除瞭最後一個屬性外,隻要其他屬性值不為null,組合或嵌套屬性名是完全合法的。例如,下面bean的定義:

java代碼:
[java] 
<bean id="foo" class="foo.Bar"> 
  <property name="fred.bob.sammy" value="123" /> 
</bean> 
表示foo  

bean有個fred屬性,此屬性有個bob屬性,而bob屬性又有個sammy屬性,最後把sammy屬性設置為123。為瞭讓此定義能工作, foo的fred屬性及fred的bob屬性在bean被構造後都必須非空,否則將拋出NullPointerException異常。
depends-on,用於當前bean初始化之前顯式地強制一個或多個bean被初始化。
示例:

java代碼:
[java] 
<bean id="beanOne" class="ExampleBean" depends-on="manager"/> 
<bean id="manager" class="ManagerBean" /> 
  
若需要表達對多個bean的依賴,可以在'depends-on'中將指定的多個bean名字用分隔符進行分隔,分隔符可以是逗號、空格及分號等。下面的例子中使用瞭'depends-on'來表達對多個bean的依賴。
 

java代碼:
[java] 
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"> 
  <property name="manager" ref="manager" /> 
</bean> 
  <bean id="manager" class="ManagerBean" /> 
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" /> 
延遲初始化bean
1:ApplicationContext實現的默認行為就是在啟動時將所有singleton bean提前進行實例化,這樣可能會增大資源的消耗,但會加快程序的運行速度。
 
2:可以將bean設置為延遲實例化。在XML配置文件中,延遲初始化將通過<bean/>元素中的lazy-init屬性來進行控制。例如:
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
</bean>
 
3:在容器層次中通過在<beans/>元素上使用'default-lazy-init'屬性來控制延遲初始化也是可能的。如下面的配置:
<beans default-lazy-init="true">
</beans>

 
自動裝配的優缺點
1:優點:
(1)自動裝配能顯著減少配置的數量。
(2)自動裝配可以使配置與java代碼同步更新。例如,如果你需要給一個java類增加一個依賴,那麼該依賴將被自動實現而不需要修改配置。
2:缺點:
(1)盡管自動裝配比顯式裝配更神奇,但是,正如上面所提到的,Spring會盡量避免在裝配不明確的時候進行猜測,因為裝配不明確可能出現難以預料的結果,而且Spring所管理的對象之間的關聯關系也不再能清晰的進行文檔化。
(2)對於那些根據Spring配置文件生成文檔的工具來說,自動裝配將會使這些工具沒法生成依賴信息。
(3)當根據類型進行自動裝配的時候,容器中可能存在多個bean定義跟自動裝配的setter方法和構造器參數類型匹配。雖然對於數組、集合以及Map,不存在這個問題,但是對於單值依賴來說,就會存在模棱兩可的問題。如果bean定義不唯一,裝配時就會拋出異常
將bean排除在自動裝配之外
1:<bean/>元素的 autowire-candidate屬性可被設為false,這樣容器在查找自動裝配對象時將不考慮該bean。
2:另一個做法就是使用對bean名字進行模式匹配來對自動裝配進行限制。其做法是在<beans/>元素的‘default-autowire-candidates’屬性中進行設置。
比如,將自動裝配限制在名字以 'Repository'結尾的bean,那麼可以設置為"*Repository“。對於多個匹配模式則可以使用逗號進行分隔。註意,如果在bean定義中的'autowire-candidate'屬性顯式的設置為'true' 或 'false',那麼該容器在自動裝配的時候優先采用該屬性的設置,而模式匹配將不起作用。

singleton
在每個Spring IoC容器中一個bean定義對應一個對象實例,在讀取配置文件創建IoC容器的時候就會根據配置初始化singleton的Bean實例
prototype
一個bean定義對應多個對象實例
request
在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。


session
在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。
global session
在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於web的Spring ApplicationContext情形下有效。

 
 
request、session以及global session僅在基於web的應用中使用
初始化web配置,Servlet 2.4及以上的web容器,如下配置:

java代碼:
[java]
<web-app> 
  <listener> 
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 
  </listener> 
</web-app> 
request作用域說明
等同於Http的Request
session作用域說明
針對某個HTTP Session,Spring容器會根據bean定義創建一個全新的bean實例,且該bean僅在當前HTTP Session內有效。與request作用域一樣,你可以根據需要放心的更改所創建實例的內部狀態,而別的HTTP Session中創建的實例,將不會看到這些特定於某個HTTP Session的狀態變化。當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉
global session
等同於標準的HTTP Session
問題:比如在調用一個singleton類型bean A的某個方法時,需要引用另一個非singleton(prototype)類型的bean B,對於bean A來說,容器隻會創建一次,這樣就沒法在需要的時候每次讓容器為bean A提供一個新的的bean B實例
解決方案:Lookup方法註入,示例如下:

java代碼:
[java]
Java類 
public abstract class HelloImpl implements HelloApi{ 
private T2 t2; 
public String helloSpring3(int a){ 
getT2().t1(); 
System.out.println("hello Spring3==="+a); 
return "Ok,a="+a; 

public abstract T2 getT2(); 

public class T2 { 
public void t1(){ 
System.out.println("now in t1"); 


配置文件:

java代碼:
[java] 
<bean id="helloBean" class="cn.javass.Spring3.hello.HelloImpl"> 
<lookup-method name="getT2" bean="t2"/> 
</bean> 
<bean id="t2" class="cn.javass.Spring3.hello.T2"></bean> 
  
Lookup方法註入的內部機制是Spring利用瞭CGLIB庫在運行時生成二進制代碼功能,通過動態創建Lookup方法bean的子類而達到復寫Lookup方法的目的
初始化回調
有兩種方法,如下:
1:實現org.springframework.beans.factory.InitializingBean接口,這種方法不被推薦,因為這樣和Spring耦合起來瞭。可以采用聲明式的方法,如下:
2:在Bean定義中指定一個普通的初始化方法,即在XML配置文件中通過指定init-method屬性來完成,配置如下:
<bean id="initBean" class="examples.ExampleBean" init-method="init"/>
析構回調
也有兩種方法,如下:
1:實現org.springframework.beans.factory.DisposableBean接口,這種方法不被推薦,因為這樣和Spring耦合起來瞭。可以采用聲明式的方法,如下:
<bean id="initBean" class="ex.ExampleBean" destroy-method="cleanup"/>
缺省的初始化和析構方法
配置在beans上,這樣就不用每個Bean都配瞭,如下:
<beans default-init-method="init">
context包的核心是ApplicationContext接口。它由BeanFactory接口派生而來,除瞭提供瞭BeanFactory所有的功能,還提供瞭以下的功能:
1:MessageSource, 提供國際化的消息訪問
2:資源訪問,如URL和文件
3:事件傳播,實現瞭ApplicationListener接口的bean
4:載入多個(有繼承關系)上下文 ,使得每一個上下文都專註於一個特定的層次,比如應用的web層
利用MessageSource實現國際化
1:在配置文件中添加

java代碼:
[java] 
<bean id="messageSource"        class="org.springframework.context.support.ResourceBundleMessageSource"> 
    <property name="basenames"> 
      <list> 
        <value>format</value> 
        <value>exceptions</value> 
      </list> 
    </property> 
  </bean> 
2:說明:上述配置是表示在classpath下有兩個標準的properties文件。文件格式是標準的properties格式,Spring通過ResourceBundle,使用JDK中解析消息的標準方式,來處理任何解析消息的請求。
3:測試代碼:
String msg = context.getMessage("testmsg", null, "Default", Locale.CHINA);
前面getmessage方法的第二個參數是用來從程序中向消息裡面傳值的,如下:

java代碼:
[java] 
消息文件:testmsg=this is a test,{0},{1} 
Java類:String msg = context.getMessage("testmsg", 
ew Object[]{"M1","M2"},"Default", Locale.CHINA); 
System.out.println("msg="+msg); 
前面getmessage方法的第四個參數是用來指定Locale的
對於國際化(i18n),Spring中不同的MessageResource實現與JDK標準ResourceBundle中的locale解析規則一樣。比如在上面例子中定義的messageSource bean,如果你想解析British (en-GB) locale的消息,那麼需要創建format_en_GB.properties的資源文件;中國的如msg_zh_CN.properties。Locale解析通常由應用程序根據運行環境來指定。
也可以把MessageSource當作資源註入到Bean中,Java類示例如下:

java代碼:
[java] 
public  class HelloImpl implements HelloApi{ 
private MessageSource ms = null; 
public void setMs(MessageSource ms){ 
this.ms = ms; 

public String helloSpring3(int a){ 
String msg = this.ms.getMessage("testmsg", null, "Default", Locale.CHINA); 
System.out.println("hello Spring3==="+msg); 
return "Ok,a="+a; 


配置文件示例如下:

java代碼:
[java] 
<bean id="helloBean" class="cn.javass.Spring3.hello.HelloImpl"> 
<property name="ms" ref="messageSource"></property> 
</bean> 
事件傳播
ApplicationContext中的事件處理是通過ApplicationEvent類和ApplicationListener接口來提供的。如果在上下文中部署一個實現瞭ApplicationListener接口的bean,那麼每當一個ApplicationEvent發佈到ApplicationContext時,這個bean就得到通知。
Spring提供瞭三個標準事件,如下:
ContextRefreshedEvent
當ApplicationContext初始化或刷新時發送的事件。這裡的初始化意味著:所有的bean被裝載,singleton被預實例化,以及ApplicationContext已就緒可用
ContextClosedEvent
當使用ApplicationContext的close()方法結束上下文時發送的事件。這裡的結束意味著:singleton bean 被銷毀
RequestHandledEvent
一個與web相關的事件,告訴所有的bean一個HTTP請求已經被響應瞭(也就是在一個請求結束後會發送該事件)。註意,隻有在Spring中使用瞭DispatcherServlet的web應用才能使用
 
示例,Java類:

java代碼:
[java]
public class T2 implements ApplicationListener{ 
@Override 
public void onApplicationEvent(ApplicationEvent arg0) { 
System.out.println("事件發生瞭=="+arg0); 


 
配置文件
<bean id="t2" class="cn.javass.Spring3.hello.T2"></bean>
Resource 接口 :
Spring的 Resource 接口是為瞭提供更強的訪問底層資源能力的抽象,典型的是訪問文件資源。基本的定義如下:

java代碼:
[java] 
public interface Resource extends InputStreamSource { 
    boolean exists(); 
    boolean isOpen(); 
    URL getURL() throws IOException; 
    File getFile() throws IOException; 
    Resource createRelative(String relativePath) throws IOException; 
    String getFilename(); 
    String getDescription(); 

public interface InputStreamSource { 
    InputStream getInputStream() throws IOException; 

可以使用ApplicationContext直接訪問資源,示例如下:

java代碼:
[java] 
InputStream in = context.getResource("msg_en_GB.properties").getInputStream(); 
byte bs[] = new byte[100]; 
in.read(bs); 
System.out.println("file content=="+new String(bs)); 
也可以向Bean裡面註入資源,示例如下:
在Java類當中添加:

java代碼:
[java] 
private Resource rs = null; 
public void setRs(Resource rs){ 
this.rs = rs; 

在配置文件中:

java代碼:
[java] 
<bean id="helloBean" class="cn.javass.Spring3.hello.HelloImpl"> 
<property name="rs" value="msg_en_GB.properties"></property> 
</bean> 
ApplicationContext能以聲明的方式創建,在web.xml中配置如下:

java代碼:
[java]  www.aiwalls.com
<context-param> 
  <param-name>contextConfigLocation</param-name> 
  <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> 
</context-param> 
<listener> 
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
 作者:jinnianshilongnian

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。