首先明確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>來注入集合參數值