Bean的自動裝配及作用域

考拉熊_12發表於2018-12-20

1.XML配置裡的Bean自動裝配

Spring IOC 容器可以自動裝配 Bean,需要做的僅僅是在 <bean> 的 autowire 屬性裡指定自動裝配的模式。自動裝配方式有:

  • byType(根據型別自動裝配): 若 IOC 容器中有多個與目標 Bean 型別一致的 Bean. 在這種情況下, Spring 將無法判定哪個 Bean 最合適該屬性, 所以不能執行自動裝配.
  • byName(根據名稱自動裝配): 必須將目標 Bean 的名稱和屬性名設定的完全相同.

示例程式碼:

Person.java,Person裡面有三個屬性:name,address,car。

package com.java.spring.autowire;

public class Person {
	private String name;
	private Address address;
	private Car car;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public Car getCar() {
		return car;
	}
	public void setCar(Car car) {
		this.car = car;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", address=" + address + ", car=" + car + "]";
	}
}

Address.java

package com.java.spring.autowire;

public class Address {
	private String city;
	private String street;
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	@Override
	public String toString() {
		return "Address [city=" + city + ", street=" + street + "]";
	}
}

Car.java

package com.java.spring.autowire;

public class Car {

	private String brand;
	private double price;
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Car [brand=" + brand + ", price=" + price + "]";
	}
}

1.1 使用byName進行自動裝配

使用byName根據bean的名字和當前bean的setter風格的屬性名進行自動裝配,若有匹配的自動轉配,沒有匹配的賦值為空。

<bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"></bean>
<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byName"></bean>

執行後輸出:

Person [name=Tom, address=Address [city=上海, street=南京路], car=Car [brand=Audi, price=500000.0]]

若配置如下:

<bean id="address1212" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"></bean>
<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byName"></bean>

address1212與setter風格的屬性名address不一致,則address不能被賦值:

Person [name=Tom, address=null, car=Car [brand=Audi, price=500000.0]]

1.2 使用byType進行自動裝配

byType根據bean的型別和當前bean的屬性的型別進行自動裝配,若IOC容器中有1個以上的型別匹配的bean,則拋異常。

<bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"></bean>
<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byType"></bean>

執行後輸出:

Person [name=Tom, address=Address [city=上海, street=南京路], car=Car [brand=Audi, price=500000.0]]

若配置如下:

<bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"></bean>
<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="car1231" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byType"></bean>

拋異常顯示:(原因是有兩個Car型別的bean)

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.java.spring.autowire.Car] is defined: expected single matching bean but found 2: car,car1231

在 Bean 配置檔案裡設定 autowire 屬性進行自動裝配將會裝配 Bean 的所有屬性. 然而, 若只希望裝配個別屬性時, autowire 屬性就不夠靈活了. autowire 屬性要麼根據型別自動裝配, 要麼根據名稱自動裝配, 不能兩者兼而有之.一般情況下,在實際的專案中很少使用自動裝配功能,因為和自動裝配功能所帶來的好處比起來,明確清晰的配置文件更有說服力一些。

2.Bean之間的關係:繼承和依賴

2.1 Spring 允許繼承 Bean 的配置, 被繼承的 Bean 稱為父 Bean. 繼承這個父 Bean 的 Bean 稱為子 Bean。子 Bean可以 從父 Bean 中繼承配置, 包括 Bean 的屬性配置,子 Bean 也可以覆蓋從父 Bean 繼承過來的配置。

<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="car2" class="com.java.spring.autowire.Car" p:price="300000.0000" parent="car"></bean>

在主方法中獲取Bean例項:

Car car=(Car) ctx.getBean("car2");

 執行後輸出:

Car [brand=Audi, price=300000.0]

2.2 父 Bean 可以作為配置模板, 也可以作為 Bean 例項. 若只想把父 Bean 作為模板, 可以設定 <bean> 的abstract 屬性為 true, 這樣 Spring 將不會例項化這個 Bean。

若設定為抽象Bean,則不能被例項化。

<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000" abstract="true"></bean>

在主方法中獲取例項:

Car car=(Car) ctx.getBean("car");

報異常:

Exception in thread "main" org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name `car`: Bean definition is abstract

並不是 <bean> 元素裡的所有屬性都會被繼承. 比如: autowire, abstract 等.也可以忽略父 Bean 的 class 屬性, 讓子 Bean 指定自己的類, 而共享相同的屬性配置. 但此時 abstract 必須設為 true。

2.2 Spring 允許使用者通過 depends-on 屬性設定 Bean 前置依賴的Bean,前置依賴的 Bean 會在本 Bean 例項化之前建立好。如果前置依賴於多個 Bean,則可以通過逗號,空格或的方式配置Bean 的名稱。

<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" p:address-ref="address" depends-on="car"></bean>

若沒有配置car這個Bean,則會報錯。

3.Bean的作用域

3.1 singleton

在 Spring 中, 可以在 <bean> 元素的 scope 屬性裡設定 Bean 的作用域. 預設情況下, Spring 只為每個在 IOC 容器裡宣告的 Bean 建立唯一一個例項, 整個 IOC 容器範圍內都能共享該例項:所有後續的 getBean() 呼叫和 Bean 引用都將返回這個唯一的 Bean 例項.該作用域被稱為singleton, 它是所有 Bean 的預設作用域。

<bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"></bean>
<bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"></bean>
<bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" p:address-ref="address" p:car-ref="car"></bean>

在主方法中獲取例項:

public class Main {
	public static void main(String[] args){
		ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-relation.xml");
		Person person1=(Person) ctx.getBean("person");
		Person person2=(Person) ctx.getBean("person");
		System.out.println(person1==person2);
	}

 System.out.println(person1==person2);列印結果為true,person1和person2為同一個物件。

3.2 prototype

原型的,容器初始化時不建立Bean例項,而是在每次請求時都建立一個新的Bean例項並返回。

相關文章