Spring主要提供以下兩種方法用於依賴注入
例子:
public class Communication { private Messaging messaging; /* * DI via Setter */ public void setMessaging(Messaging messaging){ this.messaging = messaging; } public void communicate(){ messaging.sendMessage(); } }
如上Communication類有一個messaging屬性,並含有setMessaging方法,那麼使用Setter方法注入的時候,只需要使用如下XML配置即可:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="activeMqMessaging" class="com.websystique.spring.domain.impl.ActiveMQMessaging" /> <bean id="communication" class="com.websystique.spring.Communication"> <property name="messaging"> <ref bean="activeMqMessaging" /> </property> </bean> </beans>
這裡省略了ActiveMQMessaging的定義,實際上ActiveMQMessaging類是Messaging
接口的一個實現類。
例子
public class Communication { private Encryption encryption; /* * DI via Constructor Injection */ public Communication(Encryption encryption){ this.encryption = encryption; } public void communicate(){ encryption.encryptData(); } }
注意以上Communication類有一個構造方法Communication(Encryption encryption),且含有一個入參,類型為Encryption,那麼使用構造方法注入的時候,XML配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="rsaEncryption" class="com.websystique.spring.domain.impl.RSAEncryption" /> <bean id="communication" class="com.websystique.spring.Communication"> <constructor-arg type="com.websystique.spring.domain.Encryption"> <ref bean="rsaEncryption" /> </constructor-arg> </bean> </beans>
注意,這裡省略了RSAEncryption的定義,不用在意這些細節,該類是Encryption
接口的一個實現類。
另外,為了避免構造方法重載帶來的歧義,這裡指定了入參類型為com.websystique.spring.domain.Encryption。
bean的裝配有兩種方式,手動裝配和自動裝配。注意,不要混淆,bean的裝配是依賴注入的具體行為,依賴注入的時候需要根據bean的名稱或類型等進行裝配。
手動裝配:通過在<property> 或者 <constructor>標簽中使用ref屬性,在上一小節的“依賴注入”部分使用的就是手動裝配;
<!-- default example (autowire="no") --> <bean id="driver" class="com.websystique.spring.domain.Driver"> <property name="license" ref="license"/> </bean> <bean id="license" class="com.websystique.spring.domain.License" > <property name="number" value="123456ABCD"/> </bean>
自動裝配:在<bean>標簽中使用autowire
屬性;
<bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/>
本小節主要關注自動裝配,自動裝配有以下四種方式:
autowire="byName"
: 根據名稱autowire="byType"
: 根據類型autowire="constructor"
: 根據構造方法入參類型autowire="no"
: 不使用自動裝配,即默認方式,手動裝配autowire="byName"
例子:
public class Application { private ApplicationUser applicationUser; public ApplicationUser getApplicationUser() { return applicationUser; } public void setApplicationUser(ApplicationUser applicationUser) { this.applicationUser = applicationUser; } @Override public String toString() { return "Application [applicationUser=" + applicationUser + "]"; } }
該類有一個屬性叫applicationUser
,那麼根據名稱自動裝配的XML配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- byName example --> <bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/> <bean id="applicationUser" class="com.websystique.spring.domain.ApplicationUser" > <property name="name" value="superUser"/> </bean>
</beans>
autowire="byType"
例子
public class Employee { private EmployeeAddress address; public EmployeeAddress getAddress() { return address; } public void setAddress(EmployeeAddress address) { this.address = address; } @Override public String toString() { return "Employee [address=" + address + "]"; } }
該類有一個屬性類型為EmployeeAddress
,那麼根據類型自動裝配的XML配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- byType example --> <bean id="employee" class="com.websystique.spring.domain.Employee" autowire="byType"/> <bean id="employeeAddress" class="com.websystique.spring.domain.EmployeeAddress" > <property name="street" value="112/223,SantaVila"/> <property name="city" value="Nebraska"/> </bean> </beans>
autowire="constructor"
例子
public class Performer { private Instrument instrument; public Performer(Instrument instrument){ this.instrument = instrument; } @Override public String toString() { return "Performer [instrument=" + instrument + "]"; } }
該類有一個構造方法,入參的類型為Instrument,那麼根據構造方法自動裝配的XML配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- constructor example --> <bean id="performer" class="com.websystique.spring.domain.Performer" autowire="constructor"/> <bean id="instrument" class="com.websystique.spring.domain.Instrument" > <property name="name" value="PIANO"/> </bean> </beans>
autowire="no"
public class Driver { private License license; public void setLicense(License license) { this.license = license; } public License getLicense() { return license; } @Override public String toString() { return "Driver [license=" + license + "]"; } }
該類有一個屬性license,由於我們不打算使用自動裝配功能,那麼只能使用手動裝配了,XML配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- default example (autowire="no") --> <bean id="driver" class="com.websystique.spring.domain.Driver" autowire="no"> <property name="license" ref="license"/> </bean> <bean id="license" class="com.websystique.spring.domain.License" > <property name="number" value="123456ABCD"/> </bean> </beans>
注意,如果不配置license的ref引用的話,license將為null。
主要涉及以下三個注解
@Autowired
@Resource
@Qualifier
@Autowired可應用於構造方法、屬性、setter方法或配置類@Configuration的方法上,該注解根據bean的數據類型進行裝配,如果你想希望根據bean的名稱進行裝配可以使用帶name屬性的@Resource
注解;另外@Qualifier
注解經常與@Autowired注解結合使用,用於解決一個應用中存在多個同種類型的bean的情況,下面將給出各個注解的示例。
@Autowired
(根據類型自動裝配)setter方法上
@Component("driver") public class Driver { private License license; @Autowired public void setLicense(License license) { this.license = license; } @Override public String toString() { return "Driver [license=" + license + "]"; } //getter }
構造方法上
@Component("driver") public class Driver { private License license; @Autowired public Driver(License license){ this.license = license; } @Override public String toString() { return "Driver [license=" + license + "]"; } }
屬性上
@Component("driver") public class Driver { @Autowired private License license; //getter,setter @Override public String toString() { return "Driver [license=" + license + "]"; } }
@Resource
(根據名稱裝配)@Component("application") public class Application { @Resource(name="applicationUser") private ApplicationUser user; @Override public String toString() { return "Application [user=" + user + "]"; } }
@Qualifier
(與@Autowired
結合使用,實現按名稱裝配)例子背景::存在兩個Car接口的實現類,其中一個Car接口的實現類已被注冊為bean,且name為Mustang
@Component public class Bond { @Autowired @Qualifier("Mustang") private Car car; public void showCar(){ car.getCarName(); } }
注意,以上例子如果不使用@Qualifier
限定的話,將拋出如下異常,表明存在多個類型相同的bean:
最後提醒下,被@Autowired注解標注默認情況下能保證成功注入,如果注入不成功(往往是找不到,或存在歧義),Spring會拋出異常。當然,有時候可能會有特殊需求,不希望bean被強制裝配,那麼可以在@Autowired上添加required=
false
屬性,表明該bean的裝配是可選的,找不到的話,就為null吧,如下示例:
@Component("driver") public class Driver { @Autowired(required=false) private License license; //getter,setter @Override public String toString() { return "Driver [license=" + license + "]"; } }
基於以上原因,雖然@Autowired注解與@Resource功能類似,但是@Autowired還是比@Resource強大了那麼一點點,個人建議使用@Autowired注解。
http://websystique.com/spring/spring-dependency-injection-example-with-constructor-and-property-setter-xml-example/
http://websystique.com/spring/spring-beans-auto-wiring-example-using-xml-configuration/
http://websystique.com/spring/spring-dependency-injection-annotation-beans-auto-wiring-using-autowired-qualifier-resource-annotations-configuration/