什麼是自動裝配
自動裝配幫我們省去了 property標籤配置操作,Spring會自動根據 屬性名稱,類型,構造器來進行自動注入。
例如不進行自動裝配配置如下:
<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
通過屬性名稱自動裝配配置如下:
<bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName"></bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
自動裝配類型
Spring自動裝配分爲4種:
- default
default 不進行自動裝配 默認採用 default。
配置方式如下:
<bean autowire="default"></bean>
- byName
通過名稱進行自動裝配。
配置方式如下:
<bean autowire="byName"></bean>
- byType
通過注入Bean的類類型來進行匹配。
配置方式如下:
<bean autowire="byType"></bean>
- constructor
通過構造器進行注入。
配置方式如下:
<bean autowire="constructor"></bean>
需要注意的是在spring2.5 時候還有一種類型autowire=“autodetect” 它表示優先執行構造器的方式如果構造器沒有就執行byType 不過在spring3.0的時候就廢除了
自動裝配的具體實現
1 默認方式:
spring xml配置文件配置如下:
<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault" autowire="default">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserDefault類代碼如下:
public class UserDefault {
private Country country;
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
}
Country 類代碼如下:
public class Country {
private String name="CHINA";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
進行測試:
測試類代碼如下:
@Test
public void userDefault() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserDefault user = (UserDefault)appliction.getBean("userDefault");
System.out.println("country:"+user.getCountry().getName());
}
測試結果:
必須爲要注入成員屬性設置set 方法並且set方法名稱與注入的bean 名稱一致
2 通過名稱
spring xml配置文件配置如下:
<bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName">
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByName類 和 UserDefault 類內容一致
進行測試:
測試類代碼如下:
@Test
public void userByName() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByName user = (UserByName)appliction.getBean("userByName");
System.out.println("country:"+user.getCountry().getName());
}
測試結果:
注入的成員屬性必須有set方法 並且set方法名稱與屬性名稱一樣
3 通過類型
spring xml配置文件配置如下:
<bean id="userByType" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByType" autowire="byType"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByType 和 UserDefault 類內容一致
進行測試:
測試類代碼如下:
@Test
public void userByType() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByType user = (UserByType)appliction.getBean("userByType");
System.out.println("country:"+user.getCountry().getName());
}
測試結果:
必須set方法 但是set方法名稱可以與屬性名稱不同
4 通過構造器
spring xml配置文件配置如下:
<bean id="userByConstructor" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="constructor"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByConstructor 具體代碼如下:
public class UserByConstructor {
private Country country;
public UserByConstructor(Country country) {
super();
this.country = country;
}
public Country getCountry() {
return country;
}
}
進行測試:
測試類代碼如下:
@Test
public void userByConstructor() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByConstructor user = (UserByConstructor)appliction.getBean("userByConstructor");
System.out.println("country:"+user.getCountry().getName());
}
測試結果:
constructor 的方式無需提供set方法
@Resource和@Autowired區別
- @Resource 通過 byName 方式自動裝配
- @Autowired 通過ByType 方式自動裝配
- @Autowired 和@Qualifier 可以實現ByName的效果
如果Spring中有2個類型相同的Bean在通過@Autowired會報錯 我們可以通過@Qualifier 標籤來進行區分。
需要注意的是@Resource是javax.annotation包下的註解類 通過註解注入無需提供set方法
註解注入實戰演示
1 @Resource
首先要創建我們演示的基礎類:
ICountry接口類 方便創建多個Bean操作演示用
package cn.zhuoqianmingyue.ioc.di.autowire;
public interface ICountry {
String getName();
}
CountryResource 類和CountryResource2 類都實現ICountry 表示同一類型的Bean
package cn.zhuoqianmingyue.ioc.di.autowire;
import org.springframework.stereotype.Component;
@Component
public class CountryResource implements ICountry{
private String name="CountryResource";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package cn.zhuoqianmingyue.ioc.di.autowire;
import org.springframework.stereotype.Component;
@Component
public class CountryResource2 implements ICountry{
@Override
public String getName() {
return "CountryResource2";
}
}
用戶類 用於依賴CountryResource 類和CountryResource2 類
package cn.zhuoqianmingyue.ioc.di.autowire;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component("userResource")
public class UserResource{
@Resource(name="countryResource2")
private ICountry countryResource;
public ICountry getCountryResource() {
return countryResource;
}
}
測試類:
@Test
public void userResource() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserResource user = (UserResource)appliction.getBean("userResource");
System.out.println("country:"+user.getCountryResource().getName());
}
測試結果:
根據上面案例結果是:沒有配置Bean的名稱會根據類名來進行自動裝配
如果我們在@Component 標籤指定名稱 代碼如下:
@Component("c1")
public class CountryResource implements ICountry{}
@Component("c2")
public class CountryResource2 implements ICountry{}
@Component("userResource")
public class UserResource{
@Resource(name="c1")
private ICountry countryResource;
}
測試結果:
指定Bean的名稱 將按照指定名稱進行自動裝配
如果將name改成c3 我們沒有配置任何名稱爲c3 的Bean
@Component("userResource")
public class UserResource{
@Resource(name="c3")
}
會報如下錯誤:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘c3’
如果Bean名稱相同如下面代碼示例:
@Component("c2")
public class CountryResource implements ICountry{}
@Component("c2")
public class CountryResource2 implements ICountry{}
會報如下錯誤:
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [ioc-di-autowire.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘c2’
2 @Autowired
創建CountryResource3 這裏我們不實現ICountry接口
@Component
public class CountryResource3 {
public String getName() {
return "CountryResource3";
}
}
創建名稱爲UserAutowired的Bean 然後注入 CountryResource3
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
public CountryResource3 getCountryResource3() {
return countryResource3;
}
}
測試類代碼:
@Test
public void userAutowired() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserAutowired user = (UserAutowired)appliction.getBean("userAutowired");
System.out.println("country:"+user.getCountryResource3().getName());
}
測試結果:
我們將ICountry 接口注入UserAutowired Bean中
具體代碼如下:
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
@Autowired
private ICountry countryResource;
public ICountry getCountryResource() {
return countryResource;
}
public CountryResource3 getCountryResource3() {
return countryResource3;
}
}
會報如下錯誤:
1WARN t.support.ClassPathXmlApplicationContext: 554 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userAutowired’: Unsatisfied dependency expressed through field ‘countryResource’; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘cn.zhuoqianmingyue.ioc.di.autowire.ICountry’ available: expected single matching bean but found 2: c1,c2
這是我們需要通過@Qualifier標籤來指定注入c1 還是c2
具體代碼如下:
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
@Autowired
@Qualifier("c1")
private ICountry countryResource;
}
測試代碼:
@Test
public void userAutowired() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserAutowired user = (UserAutowired)appliction.getBean("userAutowired");
System.out.println("country:"+user.getCountryResource3().getName());
System.out.println("country:"+user.getCountryResource().getName());
}
測試結果:
Spring xml配置文件ioc-di-autowire.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<context:component-scan base-package="cn.zhuoqianmingyue"></context:component-scan>
<!-- default -->
<!--<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault" autowire="default">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>-->
<!-- byName -->
<!-- <bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName"></bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>-->
<!-- byType -->
<!-- <bean id="userByType" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByType" autowire="byType"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean> -->
<!-- byConstructor -->
<bean id="userByConstructor" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="constructor"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
<!-- 這種方式spring3.0就廢除掉了 -->
<!--
<bean id="userByAutodetect" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="autodetect"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
-->
</beans>