close

Auto-wiring

config設定中autowire屬性可以依據當時的的狀況(no(預設)、byName、byType、constructor、autodetect)去自動綁定,而不需要去大量去撰寫的程式碼。

  • byName

Customer.java

package com.example;
 
public class Customer 
{
	private Address address;

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "Customer [address=" + address + "]";
	}

}

Address.java

package com.example;
 
public class Address 
{
	private String fulladdress;

	public String getFulladdress() {
		return fulladdress;
	}

	public void setFulladdress(String fulladdress) {
		this.fulladdress = fulladdress;
	}

	@Override
	public String toString() {
		return "Address [fulladdress=" + fulladdress + "]";
	}
	
}

Main.java

package com.example;

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

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"Beans.xml");

		Customer cust = (Customer) context.getBean("customer");
		System.out.println(cust);
	}
}

修改前Beans.xml

<bean id="customer" class="com.example.Customer" >
    <property name="address" ref="address" />
</bean>
<bean id="address" class="com.example.Address" >
    <property name="fulladdress" value="Taipei, TW" />
</bean>

修改後Beans.xml

<bean id="customer" class="com.example.Customer" autowired="byName"/>
<bean id="address" class="com.example.Address" >
    <property name="fulladdress" value="Taipei, TW" />
</bean>

修改前/後結果顯示如下所示:

Customer [address=Address [fulladdress=Taipei, TW]]

當autowire是使用byName時,address bean id的名稱需和customer bean的名稱(address)相同。若是設定不同則會產生下列結果:

Beans.xml

<bean id="customer" class="com.example.Customer" autowire="byName"/>
<bean id="addressA" class="com.example.Address" >
    <property name="fulladdress" value="Taipei, TW" />
</bean>

結果顯示如下所示:

Customer [address=null]

  • byType

Person.java

package com.example1;
 
public class Person 
{
	private Ability ability;

	public Ability getAbility() {
		return ability;
	}

	public void setAbility(Ability ability) {
		this.ability = ability;
	}

	@Override
	public String toString() {
		return "Person [ability=" + ability + "]";
	}

}

Ability.java

package com.example1;
 
public class Ability 
{
	private String skill;

	public String getSkill() {
		return skill;
	}

	public void setSkill(String skill) {
		this.skill = skill;
	}

	@Override
	public String toString() {
		return "Ability [skill=" + skill + "]";
	}

}

Main.java

package com.example1;

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

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"Beans1.xml");

		Person person = (Person) context.getBean("person");
		System.out.println(person);
	}
}

修改前Beans1.xml

<bean id="person" class="com.example1.Person" >
    <property name="ability" ref="invisible" />
</bean>

<bean id="invisible" class="com.example1.Ability" >
    <property name="skill" value="Invisible" />
</bean>

修改後Beans1.xml

<bean id="person" class="com.example1.Person" autowire="byType" />
<bean id="invisible" class="com.example1.Ability" >
    <property name="skill" value="Invisible" />
</bean>

修改前/後結果顯示如下所示:

Person [ability=Ability [skill=Invisible]]

需要注意的是當autowire設定為byType時,bean的data type必須是唯一的,否則會出現下列錯誤:

Beans1.xml

<bean id="person" class="com.example1.Person" autowire="byType" />
<bean id="steal" class="com.example1.Ability" >
    <property name="skill" value="Steal" />
</bean>
<bean id="invisible" class="com.example1.Ability" >
    <property name="skill" value="Invisible" />
</bean>

結果顯示如下所示:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in class path resource [Beans1.xml]: Unsatisfied dependency expressed through bean property 'ability': :** No qualifying bean of type [com.example1.Ability] is defined: expected single matching bean but found 2: steal,invisible; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.example1.Ability] is defined: expected single matching bean but found 2: steal,invisible**

  • constructor

In Spring, “Autowiring by Constructor” is actually autowiring by Type in constructor argument. It means, if data type of a bean is same as the data type of other bean constructor argument, auto wire it.

Developer.java

package com.example2;

public class Developer {
	private Language language;

	public Developer(Language language) {
		this.language = language;
	}

	@Override
	public String toString() {
		return "Developer [language=" + language + "]";
	}

}

Language.java

package com.example2;

public class Language {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Language [name=" + name + "]";
	}

}

Main.java

package com.example2;

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

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"Beans2.xml");

		Developer developer = (Developer) context.getBean("developer");
		System.out.println(developer);
	}
}

修改前Beans2.xml

<bean id="developer" class="com.example2.Developer">
    <constructor-arg>
        <ref bean="language"/>
    </constructor-arg>
</bean>
<bean id="language" class="com.example2.Language" >
    <property name="name" value="Java" />
</bean>

修改後Beans2.xml

<bean id="developer" class="com.example2.Developer" autowire="constructor"/>
<bean id="language" class="com.example2.Language" >
    <property name="name" value="Java" />
</bean>

修改前/後結果顯示如下所示:

Developer [language=Language [name=Java]]

  • autodetect

autowire若是為autodetect時,default autowire為constructor,若找不到則是改為byType。

autowire並沒有辦法在設定檔自動偵測是否有綁定,因此可透過dependency- check去檢查綁定狀況,主要有四種相依檢查方式:simple、objects、all、none(預設)。simple是檢查primitivey資料型態、objects是檢查物件屬性、all則是檢查所有屬性。

Beans2.xml

<bean id="developer" class="com.example2.Developer" dependency-check="all"/>
<bean id="language" class="com.example2.Language" >
    <property name="name" value="Java" />
</bean>

如果相依檢查發現有未完成的依賴關係,則會丟出Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example2.Developer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.example2.Developer.()

需注意的是使用dependency-check需將http://www.springframework.org/schema/beans/spring-beans-3.0.xsd改為http://www.springframework.org/schema/beans/spring-beans-2.5.xsd,否則會出現下列訊息:

Exception in thread "main" org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 6 in XML document from class path resource [Beans2.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 101; cvc-complex-type.3.2.2: 不允許屬性 'dependency-check' 出現在元素 'bean' 中。

arrow
arrow
    全站熱搜

    Codeless 發表在 痞客邦 留言(0) 人氣()