Spring:設值注入用法
首先明確Java中什麼是依賴關係:
類A依賴類B的意思是,如果A的物件要完成某一操作,必須使用B的物件的某些操作來幫忙,才能完成。簡言之,B作為A的某個方法的方法引數存在。如下:
class A{
public void f(B b){
}
}
class B{
}
Spring的作用就是管理JavaEE中的各個元件,並把所有的Java物件都稱之為Bean,因此完全可以把任何的Java類都部署在Spring中,但是Java類中必須有相應的構造器。
設值注入通過<property/>元素驅動Spring執行setter方法,為引數傳入引數值,而Java類的成員變數又可以是各種資料型別,除了基本的資料型別外,還可以是其他Java例項,也可以是Spring容器中其他Bean例項,甚至是Java集合,陣列等,因此Spring允許如下元素為setter方法、構造器引數指定引數值。
1:value 用於注入基本資料型別
2:ref 當注入的成員變數屬於Sping容器中的其他Bean例項則應使用ref元素。
3:bean 稱之為注入巢狀Bean,當某個Bean所依賴的Bean不想被容器訪問,則可以使用巢狀Bean,其本質與ref一樣
4:list、set、map、props 當注入的成員變數屬於集合時則使用這些元素。
Spring可以為任何Java物件注入任何型別的屬性,只要該Java物件為該屬性提供了相應的setter方法,Spring就是通過該方法,完成的相應賦值和注入。
一:當注入普通屬性時—————value元素的使用
1:我們定義一個Bean例項的實現類 Test.java
package com.mao.test;
public class Test {
private String userName;
//為Spring容器注入普通屬性提供setter方法
public void setUserName(String userName) {
this.userName = userName;
}
public void input(){
System.out.println("正在呼叫setUserName()方法,傳入的引數為:"userName);
}
}
該類中聲明瞭一個普通屬性 userName,並提供了set方法,Spring容器也正是通過該方法完成的屬性注入。
2:我們的配置檔案beans.xml
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 建立一個id為test的Bean例項 -->
<bean id="test" class="com.mao.test.Test">
<!-- 通過setName方法為引數賦值 引數值為VipMao -->
<property name="userName" value="VipMao"></property>
</bean>
</beans>
說一下配置檔案,我們定義了一個id為test的Bean例項,他的實現類是com.mao.test包下的Test.java(也就是上面那個程式),然後<bean>內定義了個<property>標籤,name屬性的值表示呼叫哪個屬性的set方法進行注入賦值,value屬性得值表示傳入的引數是什麼。上面的配置檔案就是:有一個test的Bean例項,然後Spring容器通過setUserName方法,將VipMao引數注入給userName屬性。咱們僅僅需要提供一個setter方法,然後"坐等"Spring通過該setter方法完成賦值並注入給userName屬性。
3:我們的測試類 TestManager.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestManager {
public static void main(String[]args){
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
//獲取Bean例項
Test t=(Test) ctx.getBean("test");
//執行input方法
t.input();
}
}
4:執行結果
正在呼叫setUserName()方法,傳入的引數為:VipMao
可以看出,在主程式測試類中我們並沒有通過程式碼設定name屬性的值,而是<property/>元素驅動Spring容器通過相應的set方法,將value元素的值注入給屬性,但是前提是:
(1):在Bean 例項中提供了相應的setter方法(Spring容器通過該方法注入)
(2):該屬性為普通屬性(上面的name屬性為String型)
二:注入的屬性為Spring中的另一個Bean屬性----ref元素的使用
如果我們在一個Bean例項中的一個方法中使用了另一個Bean例項,也就是上面說的依賴關係,或者說需要為Bean設定的屬性值是容器中的另一個Bean的例項,則應該使用ref元素。如下例子:
1:Bean例項 Person.java
package com.mao.test;
public class Person {
private Chinese chinese;
public Person() {
System.out.println("----------Spring容器通過呼叫無參建構函式建立Bean例項----------");
}
public void setChinese(Chinese chinese) {
this.chinese = chinese;
}
public void useChinese(){
System.out.println(chinese.say());
}
}
上面聲明瞭一個Chinese屬性,並提供了setter方法,在Person類useChinese()方法中用到了chinese例項,接下來我們看一下Spring容器怎麼通過ref元素將Chinese例項注入給chinese2:我們的配置檔案beans.xml
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 定義chinesePerson Bean例項,實現類Chinese類 -->
<bean id="chinesePerson" class="com.mao.test.Chinese"></bean>
<!-- 建立一個person Bean 實現類Person類-->
<bean id="person" class="com.mao.test.Person">
<!-- 驅動呼叫person的setChinese()方法,將容器中的chinesePerson Bean例項作為傳入引數 -->
<property name="chinese" ref="chinesePerson"></property>
</bean>
</beans>
配置檔案中先定義了一個chinesePerson Bean例項,實現類是Chinese類,然後定義了一個person的Bean例項,<property>內的name和ref元素值就是:通過Person類的setChinese方法將容器中的chinesePerson Bean例項作為引數注入給chinese,這就相當於執行了 Chinese chinese=new
Chinese(); 只不過這個過程是Spring通過set方法實現的。
3:被引用的chinese Bean例項 Chinese.java
package com.mao.test;
public class Chinese {
public String say(){
return"我是中國人";
}
}<span style="font-size:14px;">
</span>
4:測試程式 PersonManager.java
public class PersonManager {
public static void main(String[]args){
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
//獲取person Bean例項
Person p=(Person) ctx.getBean("person", Person.class);
p.useChinese();
}
}
5:輸出結果:
可以看出,我們並沒有在主程式中通過new的方式建立Chinese物件,這一切都是Spring容器通過ref引用chinesePerson的Bean例項,將該例項作為引數通過setter方法完成賦值和注入,通過輸出結果我們也可以發現Spring容器是通過無引數構造器來建立Bean例項的
三:注入巢狀Bean
當某個Bean所依賴的Bean不想被Spring容器直接訪問時,例如上一個例子person的Bean例項需要依賴chinese的Bean例項,則可以使用巢狀Bean,將chinese的Bean例項巢狀進person的Bean例項,因為巢狀Bean例項的本質是和ref引用容器是一樣的,因此我們完成上一個例子,僅需稍微修改一下配置檔案beans.xml
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 建立一個person Bean 實現類Person類-->
<bean id="person" class="com.mao.test.Person">
<!-- 驅動呼叫person的setChinese()方法,將容器中的chinesePerson Bean例項作為傳入引數 -->
<property name="chinese">
<!-- 定義chinesePerson Bean例項,實現類Chinese類 -->
<bean class="com.mao.test.Chinese"></bean>
</property>
</bean>
</beans>
如上,將chinese的Bean例項巢狀到person Bean的<property>子元素,那麼該chinese Bean就僅僅作為setter注入的引數,由於不需要容易訪問該Bean,因此也就不需要指定id屬性。
其他程式碼不用改,執行結果依舊:
四:注入集合值
當我們需要注入集合值時,我們則可以使用集合元素<list/><set/><map/><props>分別為List、Set、Map、和Properties的集合設定屬性值,如下:
1:Chinese.java
package com.mao.collection;
import java.util.*;
public class Chinese implements Person{
// 下面是系列集合型別的成員變數
private List<String> schools;
private Map scores;
private Map<String , Axe> phaseAxes;
private Properties health;
private Set axes;
private String[] books;
public Chinese()
{
System.out.println("Spring例項化主調bean:Chinese例項...");
}
// schools的setter方法
public void setSchools(List schools)
{
this.schools = schools;
}
// scores的setter方法
public void setScores(Map scores)
{
this.scores = scores;
}
// phaseAxes的setter方法
public void setPhaseAxes(Map<String , Axe> phaseAxes)
{
this.phaseAxes = phaseAxes;
}
// health的setter方法
public void setHealth(Properties health)
{
this.health = health;
}
// axes的setter方法
public void setAxes(Set axes)
{
this.axes = axes;
}
// books的setter方法
public void setBooks(String[] books)
{
this.books = books;
}
// 訪問上面全部的集合型別的成員變數
public void test()
{
System.out.println("----開始輸出List集合--------");
Iterator it=schools.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("--------開始輸出Map集合---------- ");
System.out.println(scores);
System.out.println("---------開始遍歷<String,Axe集合>----------");
System.out.println(phaseAxes);
System.out.println("---------開始遍歷Properties----------");
System.out.println(health);
System.out.println("---------開始遍歷Set集合----------");
Iterator itSet=axes.iterator();
while(itSet.hasNext()){
System.out.println(itSet.next());
}
System.out.println("-----開始遍歷Array陣列集合-------------");
System.out.println(java.util.Arrays.toString(books));
for(String array:books){
System.out.println(array);
}
}
}
2:下面分別用<list/><set/><map/><props>來在配置檔案beans.xml中為集合設定引數值。
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="steelAxe" class="com.mao.collection.SteelAxe"></bean>
<bean id="stoneAxe" class="com.mao.collection.StoneAxe"></bean>
<bean id="chinese" class="com.mao.collection.Chinese">
<property name="schools">
<list>
<value>菜鳥學院</value>
<value>大牛學院</value>
<value>大神學院</value>
</list>
</property>
<property name="scores">
<map>
<entry key="語文" value="86"/>
<entry key="數學" value="95"/>
<entry key="英語" value="100"/>
</map>
</property>
<property name="phaseAxes">
<map>
<entry key="原始社會" value-ref="stoneAxe"/>
<entry key="農業社會" value-ref="steelAxe"/>
</map>
</property>
<property name="health">
<props>
<prop key="血壓">正常</prop>
<prop key="身高">175</prop>
</props>
</property>
<property name="axes">
<!-- 為呼叫setAxes()方法配置Set集合作為引數值 -->
<set>
<!-- 每個value、ref、bean..都配置一個Set元素 -->
<value>普通的字串</value>
<bean class="com.mao.collection.SteelAxe"/>
<ref bean="stoneAxe"/>
<!-- 為Set集合配置一個List集合作為元素 -->
<list>
<value>20</value>
<!-- 再次為List集合配置一個Set集合作為元素 -->
<set>
<value type="int">30</value>
</set>
</list>
</set>
</property>
<property name="books">
<list>
<value>Java從入門到精通</value>
<value>輕量級JavaEE企業應用實戰</value>
<value>經典JavaEE企業應用實戰</value>
</list>
</property>
</bean>
<bean id="example" class="com.mao.fuhe.Example">
<property name="person.name" value="VipMao"></property>
</bean>
</beans>
Spring容器也是通過<property>的name屬性呼叫相應的setter方法,完成相應集合的賦值注入。
3:主程式 TestManager.java
package com.mao.collection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestManager {
public static void main(String[]args){
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
Chinese chinese=(Chinese) ctx.getBean("chinese");
chinese.test();
}
}
4:執行結果:
總結:
Spring框架本質就是通過xml配置檔案來驅動Java程式碼,當程式要呼叫setter方法時,總需要傳入引數值,隨著引數值不同,Spring配置檔案也要改變:
1:形參型別是基本資料型別:String ,日期等 使用value
2:形參型別是符合型別:使用ref或者巢狀Bean
3:形參型別是集合,使用<list/><set/><map/><props>來注入集合引數值