1.Spring的自動裝配
在Spring的使用中季二,如果要將一個bean實例化檩咱,可以通過配置文件,也可以通過在java代碼里面的注解來實現(xiàn)胯舷,Spring能夠根據(jù)自動協(xié)作這些bean之間的關(guān)系刻蚯,這種自動協(xié)作的過程,也稱之為自動裝配桑嘶。
自動裝配模式有如下四種模式:
模式 | 說明 |
---|---|
no | no表示關(guān)閉自動裝配選項炊汹,必須通過顯示的設(shè)置才能確認依賴關(guān)系。這也是采用xml配置的默認選項逃顶。 |
byname | 基于bean的名稱name進行注入讨便,在進行Bean的自動裝配時,將屬性的name在配置文件中搜索匹配的Bean,如果找到name一致的bean,則進行注入以政,如果找不打到霸褒,則會拋出異常。 |
byType | 基于bean的類型進行注入盈蛮,在bean中自動裝配屬性的時候废菱,將定義的屬性類型與配置文件中定義的bean進行匹配,如果類型一致,就在屬性中注入昙啄,如果沒有找到這樣的bean,就拋出異常穆役。 |
constructor | 通過構(gòu)造函數(shù)自動裝配bean,這個操作與ByType是一致的,在自動裝配的過程中梳凛,將查找構(gòu)造函數(shù)的參數(shù)類型耿币,然后對所有構(gòu)造函數(shù)參數(shù)執(zhí)行自動裝配。 |
有三種方式可以實現(xiàn)spring Bean的裝配過程:
- xml配置
- @Autowired
- @Resource
2.xml配置實現(xiàn)裝配
首先定義了三個類韧拒, 分別為:
表示用戶關(guān)系的User類 :
package com.dhb.gts.javacourse.week5.springbean.v1;
import lombok.Data;
@Data
public class User {
//編號
private int id;
//姓名
private String name;
//年齡
private int age;
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
表示角色的Role類:
package com.dhb.gts.javacourse.week5.springbean.v1;
import lombok.Data;
@Data
public class Role {
//角色ID
private int roleId;
//角色名稱
private String roleName;
}
以及表示用戶角色關(guān)聯(lián)關(guān)系的UserRole類:
package com.dhb.gts.javacourse.week5.springbean.v1;
import lombok.Data;
@Data
public class UserRole {
//用戶
private User user;
//角色
private Role role;
public UserRole() {
}
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
}
2.1 xml實現(xiàn)基本的裝配
配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
<constructor-arg name="id" value="001"/>
<constructor-arg name="name" value="張三"/>
<constructor-arg name="age" value="22"/>
</bean>
<bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
<property name="roleId" value="1"/>
<property name="roleName" value="管理員"/>
</bean>
<bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" >
<property name="role" ref="role"/>
<property name="user" ref="user"/>
</bean>
</beans>
測試類:
package com.dhb.gts.javacourse.week5.springbean.v1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlTest1 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-1.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
}
}
這種方式需要在xml中對每一個屬性進行配置淹接,首先通過property裝配了User和Role,UserRole對象的兩個屬性role和user通過property進行關(guān)聯(lián)叛溢。這樣就能實現(xiàn)spring中最基本的一種裝配方式塑悼。
可以通過XmlTest1類進行測試,確認裝配的正確性楷掉。
UserRole(user=User(id=1, name=張三, age=22), role=Role(roleId=1, roleName=管理員))
2.2 xml通過byName實現(xiàn)自動裝配
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
<constructor-arg name="id" value="001"/>
<constructor-arg name="name" value="張三"/>
<constructor-arg name="age" value="22"/>
</bean>
<bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
<property name="roleId" value="1"/>
<property name="roleName" value="管理員"/>
</bean>
<bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="byName"/>
</beans>
測試代碼:
package com.dhb.gts.javacourse.week5.springbean.v1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlTest2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-2.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
}
}
這種裝配方式不用在UserRole中指定user和role對應(yīng)的具體類厢蒜,只需要增加一個屬性:autowire="byName",就能在自動裝配的過程中烹植,將根據(jù)UserRole的屬性的name查找context中name與之對應(yīng)的bean進行裝配斑鸦。
測試結(jié)果如下:
UserRole(user=User(id=1, name=張三, age=22), role=Role(roleId=1, roleName=管理員))
2.3 xml通過byType實現(xiàn)自動裝配
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
<constructor-arg name="id" value="001"/>
<constructor-arg name="name" value="張三"/>
<constructor-arg name="age" value="22"/>
</bean>
<bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
<property name="roleId" value="1"/>
<property name="roleName" value="管理員"/>
</bean>
<bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="byType"/>
</beans>
測試代碼:
package com.dhb.gts.javacourse.week5.springbean.v1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlTest3 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-3.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
}
}
這種裝配方式同樣不用在UserRole中指定user和role對應(yīng)的具體類,只需要增加一個屬性:autowire="byType"草雕,就能在自動裝配的過程中巷屿,將根據(jù)UserRole成員變量的類型查找context中類型與之對應(yīng)的bean進行裝配。
需要注意的是墩虹,byName方式可以確保bean的唯一性嘱巾,但是byType方式,無法確保bean的唯一性诫钓,如果出現(xiàn)多個bean的類型相同旬昭,則會報錯。
測試結(jié)果如下:
UserRole(user=User(id=1, name=張三, age=22), role=Role(roleId=1, roleName=管理員))
2.4 xml通過constructor實現(xiàn)自動裝配
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.dhb.gts.javacourse.week5.springbean.v1.User">
<constructor-arg name="id" value="001"/>
<constructor-arg name="name" value="張三"/>
<constructor-arg name="age" value="22"/>
</bean>
<bean id="role" class="com.dhb.gts.javacourse.week5.springbean.v1.Role">
<property name="roleId" value="1"/>
<property name="roleName" value="管理員"/>
</bean>
<bean id="userRole" class="com.dhb.gts.javacourse.week5.springbean.v1.UserRole" autowire="constructor">
<constructor-arg name="user" ref="user"/>
<constructor-arg name="role" ref="role"/>
</bean>
</beans>
測試代碼:
package com.dhb.gts.javacourse.week5.springbean.v1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlTest4 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v1-4.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
}
}
這種裝配方式同樣不用在UserRole中指定user和role對應(yīng)的具體類尖坤,只需要增加一個屬性:autowire="constructor"稳懒,就能在自動裝配的過程中,將根據(jù)UserRole構(gòu)造函數(shù)參數(shù)表constructor-arg配置的name查找context中name與之對應(yīng)的bean進行裝配慢味。
測試結(jié)果如下:
UserRole(user=User(id=1, name=張三, age=22), role=Role(roleId=1, roleName=管理員))
2.@Autowired實現(xiàn)裝配
@Autowired是采用byType實現(xiàn)的自動裝配场梆,在裝配的過程中,通過類型進行匹配纯路。
同樣或油,定義了Role
package com.dhb.gts.javacourse.week5.springbean.v2;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class Role {
//角色ID
@Value("2")
private Integer roleId;
//角色名稱
@Value("用戶")
private String roleName;
}
以及User
package com.dhb.gts.javacourse.week5.springbean.v2;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class User {
//編號
private Integer id;
//姓名
private String name;
//年齡
private Integer age;
@Autowired
public User(@Value("1") int id, @Value("用戶") String name,@Value("22") int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
2.1 注解在屬性上
UserRole代碼如下:
package com.dhb.gts.javacourse.week5.springbean.v2;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Data
public class UserRole {
//用戶
@Autowired
private User user;
//角色
@Autowired
private Role role;
public UserRole() {
}
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
}
如上所示,只需要在UserRole的屬性上增加@Autpwired,在context中查找與屬性類型一致的bean,就可以實現(xiàn)UserRole的自動裝配驰唬。
2.2 注解在構(gòu)造函數(shù)上
UserRole代碼如下:
package com.dhb.gts.javacourse.week5.springbean.v2;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Data
public class UserRole1 {
//用戶
private User user;
//角色
private Role role;
public UserRole1() {
}
@Autowired
public UserRole1(User user, Role role) {
this.user = user;
this.role = role;
}
}
注解在構(gòu)造函數(shù)上顶岸,等價于xml配置中的constructor配置腔彰。通過構(gòu)造函數(shù)的屬性值的類型去查找context中的bean。
2.3 注解在Set方法上
UserRole代碼如下:
package com.dhb.gts.javacourse.week5.springbean.v2;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@ToString
public class UserRole2 {
//用戶
private User user;
//角色
private Role role;
public User getUser() {
return user;
}
@Autowired
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
@Autowired
public void setRole(Role role) {
this.role = role;
}
public UserRole2() {
}
public UserRole2(User user, Role role) {
this.user = user;
this.role = role;
}
}
AutoWired也可以注解在set方法上來實現(xiàn)自動裝配辖佣。根據(jù)set方法的參數(shù)霹抛,從context中選擇type與之一致的bean實現(xiàn)裝配。
2.4 測試
測試代碼如下:
public class AutowiredTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v2.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
UserRole1 userRole1 = (UserRole1) context.getBean("userRole1");
System.out.println(userRole1.toString());
UserRole2 userRole2 = (UserRole2) context.getBean("userRole2");
System.out.println(userRole2.toString());
}
}
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.dhb.gts.javacourse.week5.springbean.v2">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
測試結(jié)果:
UserRole(user=User(id=1, name=用戶, age=22), role=Role(roleId=2, roleName=用戶))
UserRole1(user=User(id=1, name=用戶, age=22), role=Role(roleId=2, roleName=用戶))
UserRole2(user=User(id=1, name=用戶, age=22), role=Role(roleId=2, roleName=用戶))
3.@Resource實現(xiàn)裝配
同樣卷谈,通過J2EE的@Resource標(biāo)簽也能實現(xiàn)Bean的裝配杯拐,但是需要注意的是,這個注解不支持構(gòu)造函數(shù)世蔗,只支持屬性或者set方法端逼。需要注意的是,@Resource默認是采用byName的方式從contect中查找bean.
角色類:
package com.dhb.gts.javacourse.week5.springbean.v3;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class Role {
//角色ID
@Value("2")
private Integer roleId;
//角色名稱
@Value("用戶")
private String roleName;
}
用戶類:
package com.dhb.gts.javacourse.week5.springbean.v3;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class User {
//編號
private Integer id;
//姓名
private String name;
//年齡
private Integer age;
@Autowired
public User(@Value("1") int id, @Value("用戶") String name,@Value("22") int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
3.1 注解在屬性上
代碼如下:
package com.dhb.gts.javacourse.week5.springbean.v3;
import lombok.Data;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Data
public class UserRole {
//用戶
@Resource(type = User.class)
private User user;
//角色
@Resource(name = "role")
private Role role;
public UserRole() {
}
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
}
3.2 注解在set方法上
代碼如下:
package com.dhb.gts.javacourse.week5.springbean.v3;
import lombok.ToString;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@ToString
public class UserRole1 {
//用戶
private User user;
//角色
private Role role;
public UserRole1() {
}
public User getUser() {
return user;
}
@Resource
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
@Resource
public void setRole(Role role) {
this.role = role;
}
public UserRole1(User user, Role role) {
this.user = user;
this.role = role;
}
}
3.3 @Resource測試:
測試類:
public class ResourceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-v3.xml");
UserRole userRole = (UserRole) context.getBean("userRole");
System.out.println(userRole.toString());
UserRole1 userRole1 = (UserRole1) context.getBean("userRole1");
System.out.println(userRole1.toString());
}
}
測試配置:
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.dhb.gts.javacourse.week5.springbean.v3">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
測試結(jié)果:
UserRole(user=User(id=1, name=用戶, age=22), role=Role(roleId=2, roleName=用戶))
UserRole1(user=User(id=1, name=用戶, age=22), role=Role(roleId=2, roleName=用戶))
4.@Autowired與@Resource的比較
二者對比如下:
- @Autowired與@Resource都可以用來裝配bean. 都可以寫在字段上,或者在setter方法上污淋。 但是@Resource不支持在構(gòu)造函數(shù)上裝配顶滩。
- @Autowired默認按類型裝配(這個注解是屬業(yè)spring的),默認情況下必須要求依賴對象必須存在寸爆,如果要允許null 值礁鲁,可以設(shè)置它的required屬性為false,如:@Autowired(required=false) 而昨。如果我們想使用名稱裝配可以結(jié)合@Qualifier注解進行使用救氯。
- @Resource(這個注解屬于J2EE的),默認安照名稱進行裝配歌憨,名稱可以通過name屬性進行指定, 如果沒有指定name屬性墩衙,當(dāng)注解寫在字段上時务嫡,默認取字段名進行按照名稱查找,如果注解寫在setter方法上默認取屬性名進行裝配漆改。 當(dāng)找不到與名稱匹配的bean時才按照類型進行裝配心铃。