Spring學習系列之——第三章:Spring中Bean的配置(二)

  上一篇中簡單了說了一下使用XML進行bean的配置以及bean的兩種注入方式:屬性注入,即set方法注入;構造方法注入,即通過指定與構造方法一致的參數個數與類型。在構造方法注入中,可以使用index指定參數位置,index是0從開始的,還可以使用type屬性指定參數類型,通過這二者組合,IoC容器就可以明確的知道使用哪個構造方法進行依賴注入。


  但是上面做的那些工作,也只是對單個bean的配置,在我們的複雜的應用系統的實現中,我們往往需要多個bean之間相互協作,共同完成系統的功能。在這一篇文章中你將會找到答案,如何引用其他的bean


 引用其他的bean的方法一般來說有兩種:一是通過ref屬性或者標籤,爲bean的屬性或者構造參數指定要引用的bean,;二是在使用內部bean,即在屬性或者構造方法裏面包含bean的聲明。


使用ref標籤或者屬性引用其他bean

  我們結合上一篇的代碼,新建一個Person類,Person有一個Car,代碼如下,Person類有三個屬性:name,age以及car,car是Car類型的:

package com.study.spring;

public class Person {
	private String name;
	private int age;
	private Car car;
	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;
	}
	public Car getCar() {
		return car;
	}
	public void setCar(Car car) {
		this.car = car;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
	}
	public Person() {
		super();
	}
	public Person(String name, int age, Car car) {
		super();
		this.name = name;
		this.age = age;
		this.car = car;
	}
}

  接下來讓我們看看如何去配置一個Person類型的bean,下面是配置文件:

<bean id="car2" class="com.study.spring.Car">
	<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
	<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
	<constructor-arg value="240" type="int"></constructor-arg>
</bean>

<bean id="person" class="com.study.spring.Person">
	<property name="name" value="Aces"></property>
	<property name="age" value="18"></property>
	<!-- 可以使用property的ref屬性,建立bean之間的引用關係 -->
	<property name="car" ref="car2"></property>
</bean>

<bean id="person2" class="com.study.spring.Person">
	<property name="name" value="Aces"></property>
	<property name="age" value="18"></property>
	<!-- 可以使用property的子節點ref標籤,建立bean之間的引用關係 -->
	<property name="car">
		<ref bean="car2" />
	</property>
</bean>

<bean id="person3" class="com.study.spring.Person">
	<property name="name" value="Aces"></property>
	<property name="age" value="18"></property>
	<!-- 內部bean,不能被外部使用,只能在內部使用 -->
	<property name="car">
		<bean class="com.study.spring.Car">
			<constructor-arg value="Ford" type="java.lang.String"></constructor-arg>
			<constructor-arg value="Changan" type="java.lang.String"></constructor-arg>
			<constructor-arg value="20000" type="double"></constructor-arg>
		</bean>
	</property>
</bean>

  這裏定義了三個Person類型的bean:person、person2、person3,這裏的ref標籤中引用的car2,是上一篇文章中給出的car2的,爲了方便大家看清楚,所以這裏把car2的定義也給了出來。順便複習一下,這裏的三個Person類型的bean(person、person2、person3)的三個屬性都是通過<property>標籤進行注入的,即通過屬性注入的,而Car類型的bean(car2)是通過<constructor-arg>標籤進行注入的,即通過構造方法注入

  可以看到引入其他的bean的配置實在是太簡單了,我們可以事先定義好要使用的bean,然後通過ref屬性引用,即第一種配置方法;也可以通過<ref>標籤,即第二種配置方法。這兩種方式都是引用的我們事先定義好的bean,即先有了car2,然後直接通過ref屬性進行引用。

  下面看一下我們的第三種配置方式,我們在<property>標籤的內部,定義了一個bean,我們把這種bean稱之爲內部bean,這種bean對外部是不可見的,即外部不能夠使用它,相應的也可以不設置id和name屬性(因爲外面反正也用不了,(*^__^*) 嘻嘻……)。內部bean的定義可以使用我們上一篇文章中說的bean的配置方法進行定義,使用屬性注入或者構造方法注入都是可以的。說了這麼多,到底管不管用呢,下面看一下程序運行結果(大家看的時候可能看不完全圖片,可以點擊圖片在新窗口看完整圖片):

wKiom1VHeKWzS-ahAAG9CFQymFU660.jpg  可以看到person和person2這兩個bean的輸出中關於car的部分,和car2是一樣的,你可能注意到了,price是0.0,這是因爲我們的car2中也是0.0,我們就沒有給car的price屬性賦值,我們的配置文件中第三個參數是int類型的,也就是會賦值給maxSpeed屬性。而person3中關於car的輸出是和我們內部bean的定義是一致的。


  接下來讓我們看一下使用構造方法注入的定義形式:

<!-- 通過構造器來配置bean -->
<bean id="person4" class="com.study.spring.Person">
	<constructor-arg value="Aces"></constructor-arg>
	<constructor-arg value="18"></constructor-arg>
	<constructor-arg ref="car2"></constructor-arg>
	<!-- 
	<constructor-arg>
		<ref bean="car2"/>
	</constructor-arg>
	 -->
</bean>

<!-- 通過構造器來配置bean -->
<bean id="person5" class="com.study.spring.Person">
	<constructor-arg value="Aces"></constructor-arg>
	<constructor-arg value="18"></constructor-arg>
	<!-- 測試賦值null,null必須這麼寫,是專有標記 -->
	<constructor-arg>
		<null />
	</constructor-arg>
</bean>

<!-- 級聯賦值 -->
<bean id="person6" class="com.study.spring.Person">
	<constructor-arg value="Aces"></constructor-arg>
	<constructor-arg value="18"></constructor-arg>
	<constructor-arg ref="car2"></constructor-arg>
	<!-- 級聯賦值,其實和屬性注入是一樣的,也是通過set方法,
		  注意:屬性需要先初始化之後纔可以對級聯屬性進行賦值,否則會有異常,
		  和struts2不同,struts2會自動的創建對象併爲級聯屬性賦值
	 -->
	<property name="car.price" value="30000"></property>
</bean>

<!-- 這個bean的配置是有問題的,因爲沒有對car進行賦值,所以car是null,
	spring不會自動的創建一個car對象並對其賦值,
	所以不能直接對car.price進行級聯賦值 

<bean id="person7" class="com.study.spring.Person">
	<property name="name" value="Aces"></property>
	<property name="age" value="18"></property>
	<property name="car.price" value="30000"></property>
</bean>
-->

  這裏又給出了4個Person類型的bean的定義,person4、person5、person6、person7。其中person4、person5、person6都是通過構造方法進行注入,可以通過constructor-arg的ref屬性,直接指定已經定義的bean,即引用外部bean的方法,也可以使用constructor-arg的子標籤<ref>來引用外部的bean,即對應person4的配置方式。

  看一下person5的定義,賦值爲null,必須要這麼定義,這是null的專有標誌。

  看一下person6的定義,因爲我們的car2一直沒有給price賦值,讓人一直覺得很不爽(不知道你有沒有覺得不爽,O(∩_∩)O哈哈~),這裏就解決了這個問題,我們可以對依賴的bean進行級聯賦值,但是需要注意的是:屬性需要先初始化之後纔可以對級聯屬性進行賦值,否則會有異常,和struts2不同,struts2會自動的創建對象併爲級聯屬性賦值。下面person7的定義就很好的說明了這個問題,person7的這種定義方式,我們沒有爲car賦值(其實他就是null),進行級聯賦值的時候,就會拋出異常,當然了上面被我註釋掉了,就是爲了說明這個問題。下面給出一個把person7放開的一個運行結果截圖:

wKiom1VHf-zjgKaiAAWpL0AENm8628.jpg可  以看到什麼輸出都沒有,上面的那兩個輸出是構造方法和set方法中添加的打印語句,因爲我們前面已經說過了,IoC容器會在初始化的時候,創建所有的bean,當它創建person7的時候,因爲我們沒有初始化car屬性,而是直接進行級聯賦值,所以它拋出了異常。其實不管你是用屬性注入還是構造方法注入,他們的結果是一樣的,可以按照個人習慣,靈活使用。

  下面給一個person7註釋掉之後的運行結果截圖:

wKioL1VHhO7BUSwMAAVKTttQBy8265.jpg  不知道大家有沒有注意到car2的price已經變成了30000.0了,爲什麼會這樣,什麼時候變的?請大家看一下person6的定義,有沒有找到?

  可能有些人還在想怎麼沒有給出測試類,只是給出了測試結果,我開始是認爲學習spring的肯定都是有一定java基礎的,其實測試類非常簡單,與《Spring學習系列之——第一章:Spring版本的HelloWorld》文章中給出的類似,獲取bean,然後調用類的打印。下面一併給出來好了,省的大家再去翻找,測試類真心沒內容呀。。。。測試類代碼如下:

package com.study.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		
		//1.創建Spring的IOC容器對象,在創建容器的時候,完成了bean的初始化和屬性的設置
		//ApplicationContext代表IOC容器,在初始化上下文的時候就實例化所有單例的bean
		//ClassPathXmlApplicationContext:是ApplicationContext接口的實現類,該類從類路徑下來加載配置文件
		//FileSystemXmlApplicationContext:是ApplicationContext接口的實現類,該類從文件系統中加載配置文件
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		//2.從IOC容器獲取bean實例
		HelloWorld helloWorld = (HelloWorld)ctx.getBean("helloWorld");
		//利用類型返回IOC容器中的bean,但要求IOC容器必須只能有一個該類型的Bean
		//HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
		
		//3.調用bean的方法
		helloWorld.hello();
		
		Car car = (Car)ctx.getBean("car");
		System.out.println(car);
		
		Car car2 = (Car)ctx.getBean("car2");
		System.out.println(car2);
		
		Car car3 = (Car)ctx.getBean("car3");
		System.out.println(car3);
		
		Person person = (Person)ctx.getBean("person");
		System.out.println(person);
		
		
		Person person2 = (Person)ctx.getBean("person2");
		System.out.println(person2);
		
		Person person3 = (Person)ctx.getBean("person3");
		System.out.println(person3);
		
		Person person4 = (Person)ctx.getBean("person4");
		System.out.println(person4);
		
		Person person5 = (Person)ctx.getBean("person5");
		System.out.println(person5);
		
		Person person6 = (Person)ctx.getBean("person6");
		System.out.println(person6);
		
//		Person person7 = (Person)ctx.getBean("person7");
//		System.out.println(person7);
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章