Spring(四) Spring容器(2)

6.Spring容器中的Beanjava

6.1 Bean定義和Bean別名node

對於開發者來講,開發者使用Spring作2件事:(1)開發Bean (2)配置Bean。spring

 

<beans.../>標籤的屬性:數組

default-lazy-initsession

default-mergeide

default-autowire測試

default-autowire-condidatesui

default-init-methodthis

default-destroy-methodspa

<beans.../>的定義對每個bean都有效,<bean.../>對單個bean有效,若是這二者衝突,<bean.../>會覆蓋<beans.../>的定義。<bean.../>也能夠採用name屬性,用於指定Bean的別名,經過訪問Bean別名也能夠訪問Bean實例。

指定別名有2種方式:

(1)經過name屬性指定:能夠指定多個,使用逗號、冒號或者空格分隔多個別名;

(2)經過alias元素指定:一個元素是name,一個元素是alias。而且這個標籤,不是在<bean.../>裏,而是跟<bean.../>並列的。

新建一個測試類,AliasTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package  com.pmpa.ch03;
 
public  class  AliasTest {
     
     private  String name;
     private  int  age;
     public  String getName() {
         return  name;
     }
     public  void  setName(String name) {
         this .name = name;
     }
     public  int  getAge() {
         return  age;
     }
     public  void  setAge( int  age) {
         this .age = age;
     }
     @Override
     public  String toString() {
         return  "AliasTest [name="  + name +  ", age="  + age +  "]" ;
     }
     
     
 
}

配置文件:

1
2
3
4
5
< bean  id = "aliastest"  class = "com.pmpa.ch03.AliasTest"  name = "#221,iuffs,googke" >
     < property  name = "name"  value = "honda"  ></ property >
     < property  name = "age"  value = "13"  ></ property >
</ bean >
< alias  name = "googke"  alias = "Sun" ></ alias >

測試類BeanTest.java

1
2
AliasTest at = ctx.getBean( "Sun" , AliasTest. class );
System.out.println(at);

運行結果:

1
AliasTest [name=honda, age=13]

能夠看到,經過別名「Sun」,Spring也找到了這個Bean,並正常輸出。

 

6.2 容器中Bean的做用域

 

Bean包含5種做用域:

singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個實例

prototype:原型模式,每次經過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean實例

request:對於每次HTTP請求,使用request定義的Bean都將產生一個新實例,即每次HTTP請求將會產生不一樣的Bean實例。只有在Web應用中使用Spring時,該做用域纔有效

session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新實例。一樣只有在Web應用中使用Spring時,該做用域纔有效

globalsession:每一個全局的HTTP Session,使用session定義的Bean都將產生一個新實例。典型狀況下,僅在使用portlet context的時候有效。一樣只有在Web應用中使用Spring時,該做用域纔有效

 

6.2.1 singleton和prototype做用域測試實例:

若是不指定Bean的做用域,默認是singleton。prototype做用域的Bean的建立、銷燬的系統代價比較大,應儘可能避免使用。Spring配置文件的<bean.../>標籤經過scope屬性來配置bean的做用域。

ScopeTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package  com.pmpa.ch03;
 
public  class  ScopeTest {
     private  String idNo;
 
     public  String getIdNo() {
         return  idNo;
     }
 
     public  void  setIdNo(String idNo) {
         this .idNo = idNo;
     }
 
     @Override
     public  String toString() {
         return  "ScopeTest [idNo="  + idNo +  "]" ;
     }
     
}

配置文件 beans03.xml

1
2
3
4
5
6
< bean  id = "scope1"  class = "com.pmpa.ch03.ScopeTest"  scope = "prototype" >
     < property  name = "idNo"  value = "152301ABC" ></ property >
</ bean >
< bean  id = "scope2"  class = "com.pmpa.ch03.ScopeTest"  scope = "singleton" >
     < property  name = "idNo"  value = "110332CDE" ></ property >
</ bean >

測試類BeanTest.java:

1
2
3
4
5
6
7
8
9
//prototype做用域Bean的測試:
ScopeTest st_prototype_1 = ctx.getBean( "scope1" , ScopeTest. class );
ScopeTest st_prototype_2 = ctx.getBean( "scope1" , ScopeTest. class );
System.out.println( "prototype類型的對象1和2是不是同一對象:"  + (st_prototype_1 == st_prototype_2));
         
//sigleton做用域Bean的測試:
ScopeTest st_singleton_1 = ctx.getBean( "scope2" , ScopeTest. class );
ScopeTest st_singleton_2 = ctx.getBean( "scope2" , ScopeTest. class );
System.out.println( "sigleton類型的對象1和2是不是同一對象:"  + (st_singleton_1 == st_singleton_2));

運行結果:

1
2
prototype類型的對象1和2是不是同一對象:false
sigleton類型的對象1和2是不是同一對象:true

對於singleton做用域的Bean,每次請求該id的bean,都將返回同一個共享實例

6.2.2 request、session、globalsession做用域測試實例(待補充):

 

6.3 配置依賴

 

BeanFactory和ApplicationContext實例化容器中Bean的時機不一樣:前者等到程序須要Bean實例時才建立;後者在容器建立ApplicationContext實例時,會初始化容器中的全部singleton Bean。

ApplicationContext能夠在容器初始化階段檢驗出配置錯誤

Spring容許經過以下元素爲setter方法、構造器參數指定參數值。

value

ref

bean

list、set、map、props

以上4種狀況分別表明Bean類的4種類型的成員變量

6.3.1 value:

value元素用於指定基本類型及其包裝、字符串類型的參數。前邊講述的內容中,包含不少value賦值的情形,這裏再也不贅述。

6.3.2 ref:

若是須要爲Bean設置的屬性值是容器中的另外一個Bean實例,則應該使用<ref.../>元素(其實,經常使用的是ref屬性,前邊事例都是這樣。)這種術語也叫做「注入合做者Bean」。ref實例在前邊例子中也不少,再也不贅述。

自動裝配注入合做者Bean

Spring能自動裝配Bean與Bean之間的依賴關係,即無需使用ref顯示指定依賴Bean,而是由Spring容器檢查XML配置文件內容,根據某種規則,爲調用者Bean注入被依賴的Bean。

自動裝配經過<beans.../>的default-autowrite屬性指定,也能夠經過<bean.../>元素的autowire屬性指定。

自動裝配能夠減小配置文件的工做量,可是下降了依賴關係的透明性和清晰性。

auto-wire屬性的可用值:

no:不使用自動裝配,這是默認配置。

byName:根據setter方法名進行自動裝配。

byType:根據setter方法的形參類型來自動裝配。若是找到多個和形參類型匹配的Bean,則拋出異常。

constructor:與byType相似,區別是用於自動匹配構造器的參數。

autodetect:Spring容器根據Bean內部結構,自行決定使用constructor或byType策略。

AutoWireTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package  com.pmpa.ch03;
 
public  class  AutoWireTest {
     
     private  String uName;
     private  Car car;
     private  House house;
     public  String getuName() {
         return  uName;
     }
     public  void  setuName(String uName) {
         this .uName = uName;
     }
     public  Car getCar() {
         return  car;
     }
     public  void  setCar(Car car) {
         this .car = car;
     }
     public  House getHouse() {
         return  house;
     }
     public  void  setHouse(House house) {
         this .house = house;
     }
     
     public  void  testAutoWire()
     {
         System.out.println( "begin testing autowire "  + uName);
         car.carTest();
         house.testHouse();
     }
     
}

在外部,建立2個類,分別是Car和House,這2個類很簡單。

配置文件beans03.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
< bean  id = "benz"  class = "com.pmpa.ch03.Car" >
     < property  name = "brand"  value = "benz" ></ property >
     < property  name = "speed"  value = "270" ></ property >
</ bean >
 
< bean  id = "biguiyuan"  class = "com.pmpa.ch03.House" >
     < property  name = "address"  value = "GuoMao" ></ property >
     < property  name = "price"  value = "78900000" ></ property >
</ bean >
 
< bean  id = "autowiretest"  class = "com.pmpa.ch03.AutoWireTest"  autowire = "byType" >
     < property  name = "uName"  value = "自動裝配測試1" ></ property >
</ bean >

這時候,建立的2個bean實例benz和biguiyuan的類型分別是Car和House,因此若是autowiretest實例的autowire屬性設置爲byType,則能夠自動裝配這2個屬性。

測試類BeanTest.java

1
2
AutoWireTest awt = ctx.getBean( "autowiretest" , AutoWireTest. class );
awt.testAutoWire();

運行結果:

1
2
3
begin testing autowire 自動裝配測試1
The car benz can reach the speed of 270.0
The house GuoMao can reach the price of 7.89E7

經過byType自動裝配成功。若是想經過byName完成自動裝配,則須要修改配置文件,修改Car和House類型的2個bean實例的id(修改爲什麼Id,須要根據類AutoWireTest的2個setter方法來肯定,應該是car和house),修改以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
< bean  id = "car"  class = "com.pmpa.ch03.Car" >
     < property  name = "brand"  value = "benz" ></ property >
     < property  name = "speed"  value = "270" ></ property >
</ bean >
 
< bean  id = "house"  class = "com.pmpa.ch03.House" >
     < property  name = "address"  value = "GuoMao" ></ property >
     < property  name = "price"  value = "78900000" ></ property >
</ bean >
 
< bean  id = "autowiretest"  class = "com.pmpa.ch03.AutoWireTest"  autowire = "byName" >
     < property  name = "uName"  value = "自動裝配測試1" ></ property >
</ bean >

當一個Bean既使用自動裝配依賴,又使用ref顯示指定依賴時,則顯示指定的依賴會覆蓋自動裝配的依賴。

 

6.3.3 注入嵌套Bean:

若是某個Bean所依賴的Bean不想被Spring容器直接訪問,可使用嵌套Bean。

把<bean.../>配置成<property.../>或者<constructor-args.../>的子元素,那麼該<bean.../>元素配置的Bean僅僅做爲setter注入、構造注入的參數,這種Bean就是嵌套Bean。因爲容器不能獲取嵌套Bean,所以不須要爲嵌套Bean指定id元素

注意以下的配置文件:

1
2
3
4
5
< bean  id = "chinese02"  class = "com.pmpa.ch02.Chinese" >
     < property  name = "axe" >
         < bean  class = "com.pmpa.ch02.SteelAxe" ></ bean >
     </ property >
</ bean >

使用嵌套Bean與使用ref引用容器中另外一個Bean在本質上是同樣的。 以前的寫法是<property name="..." ref="..."/>,如今改爲<property name="..."><bean class="..."/></property>。注意這種寫法中,不能指定bean id屬性。

 

6.3.4 注入集合值:

若是須要調用形參類型爲集合的setter方法,或者調用形參類型爲集合的構造器,則可以使用集合元素<list.../>、<set.../>、<map.../>、<props.../>分別來設置類型爲List、Set、Map和Properties的集合參數值。

下面定義一個包含集合屬性的java類,Student.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package  com.pmpa.ch03;
 
import  java.util.Arrays;
import  java.util.List;
import  java.util.Map;
import  java.util.Properties;
import  java.util.Set;
 
public  class  Student {
     
     private  String name;
     private  List<String> schools;
     private  Map scores;
     private  Map<String,Car> carPhases;
     private  Properties examinations;
     private  Set infos;
     private  String[] careers;
     public  String getName() {
         return  name;
     }
     public  void  setName(String name) {
         this .name = name;
     }
     public  List<String> getSchools() {
         return  schools;
     }
     public  void  setSchools(List<String> schools) {
         this .schools = schools;
     }
     public  Map getScores() {
         return  scores;
     }
     public  void  setScores(Map scores) {
         this .scores = scores;
     }
     public  Map<String, Car> getCarPhases() {
         return  carPhases;
     }
     public  void  setCarPhases(Map<String, Car> carPhases) {
         this .carPhases = carPhases;
     }
     public  Properties getExaminations() {
         return  examinations;
     }
     public  void  setExaminations(Properties examinations) {
         this .examinations = examinations;
     }
     public  Set getInfos() {
         return  infos;
     }
     public  void  setInfos(Set infos) {
         this .infos = infos;
     }
     public  String[] getCareers() {
         return  careers;
     }
     public  void  setCareers(String[] careers) {
         this .careers = careers;
     }
     @Override
     public  String toString() {
         return  "Student [name="  + name +  ", schools="  + schools +  ", scores="  + scores +  ", carPhases="  + carPhases
                 ", examinations="  + examinations +  ", infos="  + infos +  ", careers="  + Arrays.toString(careers) +  "]" ;
     }
     
}

分別爲<property.../>元素增長<list.../>、<set.../>、<map.../>、<props.../>子元素來配置這些集合類型的參數值。

配置文件定義bean03.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
< bean  id = "toyota"  class = "com.pmpa.ch03.Car" >
     < property  name = "brand"  value = "toyota" ></ property >
     < property  name = "speed"  value = "180" ></ property >
</ bean >
< bean  id = "bmw"  class = "com.pmpa.ch03.Car" >
     < property  name = "brand"  value = "bmw" ></ property >
     < property  name = "speed"  value = "270" ></ property >
</ bean >
< bean  id = "bently"  class = "com.pmpa.ch03.Car" >
     < property  name = "brand"  value = "bently" ></ property >
     < property  name = "speed"  value = "460" ></ property >
</ bean >
 
< bean  id = "student"  class = "com.pmpa.ch03.Student" >
     < property  name = "name"  value = "Tom White" ></ property >
     <!-- 配置List集合類型 -->
     < property  name = "schools" >
         < list >
             <!-- 下面每一個value標籤,定義一個list的元素,根據list泛型的類型,也可使用ref、bean等等標籤 -->
             < value >衡水一中</ value >
             < value >北京工業大學</ value >
             < value >斯坦福大學</ value >
         </ list >
     </ property >
     <!-- 配置Map集合類型 -->
     < property  name = "scores" >
         < map >
             <!-- 下面每一個entry標籤,定義一個map的元素,也就是key-value對 -->
             < entry  key = "數學"  value = "78" ></ entry >
             < entry  key = "語文"  value = "132" ></ entry >
             < entry  key = "英語"  value = "104" ></ entry >
         </ map >
     </ property >  
     <!-- 配置Map集合類型,Map<String,Car> -->
     < property  name = "carPhases" >
         < map >
             <!-- 下面每一個entry標籤,定義一個map的元素,也就是key-value對 -->
             < entry  key = "打工階段"  value-ref = "toyota" ></ entry >
             < entry  key = "創業階段"  value-ref = "bmw" ></ entry >
             < entry  key = "成功階段"  value-ref = "bently" ></ entry >
         </ map >
     </ property >  
     <!-- 配置Properties集合屬性 -->
     < property  name = "examinations" >
         < props >
             <!-- 每一個prop元素都配置一個屬性項,其中key指定屬性名 -->
             < prop  key = "血常規" >正常</ prop >
             < prop  key = "尿常規" >脂肪肝</ prop >
         </ props >
     </ property >  
     <!-- 配置Set集合屬性 -->
     < property  name = "infos" >
         < set >
             <!-- 每一個value、ref、bean都配置一個Set元素 -->
             < value >簡單的字符串賦值</ value >
             < bean  class = "com.pmpa.ch03.House" ></ bean >
             < ref  bean = "car" ></ ref >
             <!-- Set裏能夠繼續配置一個List -->
             < list >
                 < value >Set中的List</ value >
                 < set >< value  type = "java.lang.String" >List中的Set</ value ></ set >
             </ list >
         </ set >
     </ property >
     <!-- 配置數組集合類型 -->
     < property  name = "careers" >
         < list >
             <!-- 每一個value標籤是一個數組元素 -->
             < value >IBM</ value >
             < value >Google</ value >
             < value >Oracle</ value >
         </ list >
     </ property >
</ bean >

測試類BeanTest.java

1
2
3
System.out.println( "-----------------------測試集合注入------------------------" );
Student student = ctx.getBean( "student" , Student. class );
System.out.println(student);

運行結果:

1
2
-----------------------測試集合注入------------------------
Student [name=Tom White, schools=[衡水一中, 北京工業大學, 斯坦福大學], scores={數學=78, 語文=132, 英語=104}, carPhases={打工階段=Car [brand=toyota, speed=180.0], 創業階段=Car [brand=bmw, speed=270.0], 成功階段=Car [brand=bently, speed=460.0]}, examinations={血常規=正常, 尿常規=脂肪肝}, infos=[簡單的字符串賦值, com.pmpa.ch03.House@6d7b4f4c, Car [brand=benz, speed=270.0], [Set中的List, [List中的Set]]], careers=[IBM, Google, Oracle]]

說明:

  1. Spring對List元素和數組的處理是一致的,都使用<list.../>元素配置。

  2. <list.../>、<set.../>、<map.../>、<props.../>又能夠接受value;ref;bean;list、set、map、props元素。

  3. Properties類型,其key和value只能是字符串。

  4. <entry.../>元素支持4個屬性:key、key-ref(key爲容器中的其餘bean實例)、value、value-ref(value爲容器中的其餘bean實例,上邊例子中有說明)。

  5. Spring容器支持集合的合併,子Bean中的結合屬性值能夠從其父Bean的集合屬性繼承和覆蓋而來。

 

6.3.4  組合屬性:

使用car.brand 等相似格式爲對象成員變量的屬性賦值。爲Bean的組合屬性設置參數時,除最後一個屬性外,其餘屬性值都不容許爲null。

CombinationTest.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package  com.pmpa.ch03;
public  class  CombinationTest {
  private  String name;
  private  Car car =  new  Car();
  private  House house =  new  House();
  public  String getName() {
   return  name;
  }
  public  void  setName(String name) {
   this .name = name;
  }
  public  Car getCar() {
   return  car;
  }
  public  void  setCar(Car car) {
   this .car = car;
  }
  public  House getHouse() {
   return  house;
  }
  public  void  setHouse(House house) {
   this .house = house;
  }
  @Override
  public  String toString() {
   return  "CombinationTest [name="  + name +  ", car="  + car +  ", house="  + house +  "]" ;
  }
}

配置文件:

1
2
3
4
5
6
< bean  id = "combinationtest"  class = "com.pmpa.ch03.CombinationTest" >
  < property  name = "name"  value = "combination" />
  < property  name = "car.brand"  value = "honda" ></ property >
  < property  name = "car.speed"  value = "193"  ></ property >
  < property  name = "house.address"  value = "XiDan"  ></ property >
</ bean >

運行結果:

1
2
-----------------------測試組合屬性------------------------
CombinationTest [name=combination, car=Car [brand=honda, speed=193.0], house=House [address=XiDan, price=0.0]]

使用組合屬性指定參數值時,除了最後一個屬性外,其餘屬性都不能爲Null,不然將引起NullPointerException異常,若是感受自學困難的話,能夠去參加java培訓來提升。例如,上面配置文件爲car.brand指定參數值,則CombinationTest的car就必定不能爲null,因此該類在設置private屬性時,要直接new一個對象。是這樣:private Car car = new Car();而不能是這樣:private Car car;
這種賦值方法,底層spring執行時,須要先調用getter方法,再調用setter方法,

1
combinationtest.getCar().setBrand( "honda" );

也就是說組合屬性只有最後一個屬性才調用setter方法,其他都調用getter方法——這也是爲何前面屬性都不能爲null的原因。

相關文章
相關標籤/搜索