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' 中。
留言列表
