Spring Bean常用的的裝配方式詳解
Bean常用的裝配方式有3種:
- 基于xml的裝配
- 基于Annotation(注解)的裝配
- 基于Java配置類的裝配
基于xml的裝配
在xml文件中配置Bean。
如果依賴很多,xml配置文件會(huì)很臃腫,后期維護(hù)、升級(jí)不方便。自動(dòng)裝配可解決這一問(wèn)題。
基于xml的自動(dòng)裝配
在<bean>中使用autowired屬性完成依賴的自動(dòng)裝配,不再使用<property>手動(dòng)注入setter方法中的依賴,簡(jiǎn)化了配置,減少了xml中的代碼量。
autowire屬性的屬性值:
- no 不使用自動(dòng)裝配。缺省autowire屬性時(shí)默認(rèn)值就是no。
- byName 根據(jù)setter方法的名稱來(lái)自動(dòng)裝配
- byType 根據(jù)所依來(lái)的類型(Bean)來(lái)自動(dòng)裝配
- constructor 根據(jù)構(gòu)造函數(shù)的形參表的數(shù)據(jù)類型進(jìn)行byType方式的自動(dòng)裝配
- default 全局自動(dòng)裝配
1、byName
示例:
class Student{
private String name;
public Student(String name){
this.name=name;
}
public String getName(){
return name;
}
}
class Teacher{
private Student student;
public void setStudent(Student student) {
this.student = student;
}
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
Teacher依賴于Student,依賴的對(duì)象要寫(xiě)成成員變量的形式。如果要使用自動(dòng)裝配,依賴對(duì)象的注入只能使用setter方式。
byName,name指的是setXxx()注入依賴的那個(gè)xxx,比如setStudent(Student student),name指的是student,將set后面的部分提出來(lái),變成Camel寫(xiě)法。name不是指形參名的student。
xml中的配置:
<bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="byName" />
第一個(gè)Bean是基于xml的普通裝配,第二個(gè)Bean的配置是byName形式的自動(dòng)裝配。
byName自動(dòng)裝配的執(zhí)行過(guò)程:在這個(gè)Bean的定義中,找到setter方法,這里是setStudent(),其name是student(set后面部分提出來(lái),變成Camel寫(xiě)法),根據(jù)這個(gè)name(student)找打到id/name是student的Bean實(shí)例,將這個(gè)實(shí)例自動(dòng)注入。
所以對(duì)<bean>的id/name、setter方法的命名有嚴(yán)格要求。
原本是要用<property name ref="" />子元素注入依賴的,如果依賴較多,會(huì)寫(xiě)一大堆<property>子元素。自動(dòng)裝配,不管這個(gè)一Bean有多少個(gè)依賴,一句代碼搞定,減少了代碼量,由Spring容器自動(dòng)注入依賴。但Spring容器要做更多的工作,裝配速度會(huì)變慢。
說(shuō)明:自動(dòng)裝配只能完成setter形式的依賴注入,不能完成構(gòu)造器方式的依賴注入,且只能注入其它Bean,不能注入String、數(shù)組、集合等Java自帶的類型。
測(cè)試代碼:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Teacher teacher=applicationContext.getBean("teacher",Teacher.class);
teacher.say();
}
}
運(yùn)行,控制臺(tái)打印出"張三,叫家長(zhǎng)來(lái)一下。"。
2、byType
根據(jù)要注入的Bean的類型來(lái)自動(dòng)裝配。
在上面的例子中,setStudent(Student student),要注入的依賴是Student類型的實(shí)例。
byType自動(dòng)裝配的執(zhí)行過(guò)程:在這個(gè)Bean的定義中,找到setter方法,找到setter方法要注入的Bean的類型(Student),在Spring容器中找到Student類型的實(shí)例,注入。
如果Spring容器中該依賴有多個(gè)配置,比如:
<bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="student1" class="my_package.Student"> <constructor-arg value="李四" /> </bean>
它們都是Student這個(gè)Bean的配置,Spring容器不知道要注入的依賴是哪一個(gè),會(huì)報(bào)錯(cuò),所以依賴的bean只能有一個(gè)配置。
這種是可以的:
<bean id="student" class="my_package.Student" scope="prototype"> <constructor-arg value="張三" /> </bean>
雖然Spring容器中可能有這個(gè)Bean的多個(gè)實(shí)例,但這些實(shí)例是一樣的。
示例:
將byName示例中的xml中的配置修改如下即可
<bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="byType" />
3、constructor
class Student{
public String getName(){
return "張三";
}
}
class Teacher{
private Student student;
public Teacher(Student student){
this.student=student;
}
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
需要用構(gòu)造器注入依賴,Spring容器會(huì)自動(dòng)根據(jù)構(gòu)造器中參數(shù)類型,用byType方式注入對(duì)應(yīng)類型的依賴。
只能有一個(gè)構(gòu)造器,否則Spring容器不知道使用哪個(gè)構(gòu)造器。
xml中的配置:
<bean id="student" class="my_package.Student" /> <bean id="teacher" class="my_package.Teacher" autowire="constructor" />
4、default
<?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" default-autowire="byName"> <bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="teacher" class="my_package.Teacher" autowire="default" />
在<beans>中設(shè)置默認(rèn)的自動(dòng)裝配方式,在需要使用自動(dòng)裝配的<bean>指定autowire="default",這樣該<bean>使用的自動(dòng)裝配方式就是<beans>中設(shè)置的默認(rèn)方式。
統(tǒng)一了應(yīng)用的自動(dòng)裝配方式。
基于注解的裝配
基于xml裝配的方式,如果<bean>很多,xml文件依然很臃腫。基于注解的裝配解決了這一問(wèn)題。
基于注解的裝配是最常用的。
Spring常用的注解:
- @Autowired 按類型自動(dòng)裝配(byType)。
- @Qualifier 按名稱自動(dòng)裝配,不能單用,需要和@Autowired配合使用(byName)。
- @Resource 是byName、byType方式的結(jié)合。
記法:Autowired——Type,Qualifier——Name,ATQN。
示例 @Autowired
class Student{
private String name;
public Student(String name){
this.name=name;
}
public String getName(){
return name;
}
}
class Teacher{
@Autowired
private Student student;
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
不必寫(xiě)setter方法,也不必寫(xiě)構(gòu)造器。在依賴的對(duì)象上添加@Autowired注解(當(dāng)然也可以在setter方法上寫(xiě)),即按照類型自動(dòng)裝配依賴。
上面在Student類型的依賴上添加了@Autowired注解,會(huì)自動(dòng)在Spring容器中,找到Student類型的Bean,注入。相當(dāng)于byType。
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 <context:annotation-config /> <bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="teacher" class="my_package.Teacher"/> </beans>
基于注解的裝配都需要用<context:annotation-config />開(kāi)啟注解裝配,這句代碼是告訴Spring容器,下面的這些bean使用的是注解裝配。
<bean>中不使用autowire屬性。
測(cè)試:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
Teacher teacher=applicationContext.getBean("teacher",Teacher.class);
teacher.say();
}
}
可以看到控制臺(tái)打印出"張三,叫家長(zhǎng)來(lái)一下。"。
示例 @Qualifier
修改Teacher類代碼如下,其余不變。
class Teacher{
@Autowired
@Qualifier(value="student")
private Student student;
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
在依賴的Bean實(shí)例上添加@Qualifier,@Qualifier不能單獨(dú)用,還需要添加@Autowired。
@Qualifier是byName方式的自動(dòng)裝配,需要用value指定依賴Bean的id/name,Spring容器根據(jù)這個(gè)value找到id/name為vBean,注入。
可簡(jiǎn)寫(xiě)為@Qualifier("student")。
示例 @Resource
class Teacher{
@Resource(name = "student")
private Student student;
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
先根據(jù)name找到Spring容器中name/id為student的Bean,注入。即優(yōu)先以getName方式。
如果找不到name/id為指定值的Bean,或缺省name直接寫(xiě)@Resource,則以默認(rèn)的getName方式:寫(xiě)在字段上默認(rèn)name為成員變量名(student),寫(xiě)在setter方法上默認(rèn)為set后面部分得Camel寫(xiě)法,比如setStudent()默認(rèn)name為student。
如果還是找不到依賴的Bean,則以byType方式注入。
說(shuō)明
- 以上注解寫(xiě)在字段上、setter方法上均可,都是注入一個(gè)依賴。
- Spring提供了@Resource注解,但此注解需要第三方包javax.annotation-api.jar的支持。如果用Maven,會(huì)自動(dòng)添加Spring依賴的第三方包,比如commons-logging.jar、javax.annotation.jar,如果是自己添加Spring的jar庫(kù),則還需要手動(dòng)添加Spring依賴的第三方j(luò)ar包。
- 需要在xml中用<context:annotation-config />開(kāi)啟注解。
Spring常用的其它注解
- @Service 將業(yè)務(wù)層(Service層)的類標(biāo)識(shí)為Spring容器中的Bean
- @Controller 將控制層的類標(biāo)識(shí)為Spring容器中的Bean
- @Repository 將數(shù)據(jù)訪問(wèn)層(Dao層)的類標(biāo)識(shí)為Spring容器中的Bean
- @Component 將一個(gè)類標(biāo)識(shí)為Spring容器中的Bean,相當(dāng)于具有以上3個(gè)注解的功能。但一般都使用專門的,就是說(shuō)通常使用上面3個(gè)注解,很少使用@Component。
前3個(gè)是專用的,第四個(gè)是通用的。這些注解都只能在類(Bean)上使用。
示例
@Service
class Student{
public String getName(){
return "張三";
}
}
@Service
class Teacher{
@Resource(name = "student")
private Student student;
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
xml中的配置:
<context:component-scan base-package="my_package" /> <bean id="student" class="my_package.Student" />
需要使用 <context:component-scan base-package="" />指定要掃描的包,這樣會(huì)Spring容器會(huì)自動(dòng)掃描指定的包,如果包中有上面4個(gè)注解,就將之裝配為Bean。
<context:component-scan base-package="" />會(huì)自動(dòng)開(kāi)啟注解,所以不必再寫(xiě)<context:annotataion-config />。
其實(shí)上面4個(gè)注解的作用相當(dāng)于<bean class="" />。
標(biāo)注了這4個(gè)注解的類,Spring會(huì)自動(dòng)在xml中把這個(gè)類配置為Bean,就是說(shuō)在xml中不必寫(xiě)<bean class="" />。
但只能是<bean class="" />這樣基礎(chǔ)的配置,如果要<constructor-arg>、<property>傳遞Java自帶類型的參數(shù),或其他Bean必須使用這個(gè)Bean的id/name(這個(gè)Bean要配置id/name),就不能省略該Bean的配置。
上面的例子中,Teacher類缺省了<bean class="my_package.Teacher" />。
@Resource(name = "student") private Student student;
Teacher類要用到Student類的id/name,所以Student類寫(xiě)了配置。
其實(shí)不寫(xiě)Student類的配置,則會(huì)使用byType方式向Teacher注入依賴,也可以。
<context:component-scan base-package="my_package" />這句代碼不能缺省。
自動(dòng)裝配簡(jiǎn)化了配置,減少了代碼量,但需要Spring容器做更多的工作,所以創(chuàng)建Bean的速度要慢一些。
基于Java配置類的裝配
不使用xml文件配置Bean,而是單獨(dú)寫(xiě)一個(gè)類來(lái)配置Bean。
class Student{
private String name;
public Student(String name){
this.name=name;
}
public String getName(){
return name;
}
}
class Teacher{
private Student student;
public Teacher(Student student){
this.student=student;
}
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
@Configuration //表示這個(gè)類是用來(lái)配置Bean的
class Config{
@Value("張三") String name; //創(chuàng)建一個(gè)成員變量,相當(dāng)于String name="張三";
@Bean(name = "student") //配置一個(gè)Bean,相當(dāng)于xml中的一個(gè)<bean>
public Student student(){
Student student=new Student(name); //創(chuàng)建并返回Bean的實(shí)例。
return student;
}
@Bean(name = "teacher")
public Teacher teacher(){
return new Teacher(student()); //創(chuàng)建并返回Bean的實(shí)例,因?yàn)閷?xiě)了構(gòu)造器,所以可以直接構(gòu)造器注入依賴??芍苯诱{(diào)用本類中的其它方法創(chuàng)建依賴的實(shí)例,注入。
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(Config.class); //注意,和xml配置不同。參數(shù)是配置類。
Teacher teacher=applicationContext.getBean("teacher",Teacher.class);
teacher.say();
}
}
上面的例子是通過(guò)構(gòu)造器初始化Bean,也可以寫(xiě)setter方法,通過(guò)setter方法初始化Bean:
class Student{
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
class Teacher{
private Student student;
public void setStudent(Student student){
this.student=student;
}
public void say(){
System.out.println(student.getName()+",叫家長(zhǎng)來(lái)一下。");
}
}
@Configuration
class Config{
@Value("張三") String name;
@Bean(name = "student")
public Student student(){
Student student=new Student();
student.setName(name);
return student;
}
@Bean(name = "teacher")
public Teacher teacher(){
Teacher teacher=new Teacher();
teacher.setStudent(student());
return teacher;
}
}
基于Java配置類的裝配,會(huì)將Bean的配置耦合到應(yīng)用代碼中,不推薦使用?;贘ava配置類的注解還有其它的,此處不再介紹。
使用xml文件配置Bean,是為了解耦,但隨著B(niǎo)ean的增多,xml文件越來(lái)越臃腫,所以一般是折中使用注解+xml文件的方式。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Native打包本地鏡像的操作方法(無(wú)需通過(guò)Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無(wú)需通過(guò)Graal的maven插件buildtools,本文探索一下,如果不通過(guò)這個(gè)插件來(lái)生成鏡像,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
將本地的jar包打到Maven的倉(cāng)庫(kù)中實(shí)例
下面小編就為大家分享一篇將本地的jar包打到Maven的倉(cāng)庫(kù)中實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
Java之CMS和G1垃圾回收過(guò)程的異同說(shuō)明
CMS垃圾回收器主要基于并發(fā)-清理算法,目的是減少停頓時(shí)間,通過(guò)四個(gè)主要階段進(jìn)行垃圾回收:初始標(biāo)記、并發(fā)標(biāo)記、重新標(biāo)記和并發(fā)清理,G1垃圾回收器采用標(biāo)記-整理算法,是JDK9后的默認(rèn)垃圾收集器,設(shè)計(jì)為全功能全代收集器2024-09-09
Spring的自定義擴(kuò)展標(biāo)簽NamespaceHandler解析
這篇文章主要介紹了Spring的自定義擴(kuò)展標(biāo)簽NamespaceHandler解析,在很多情況下,我們需要為系統(tǒng)提供可配置化支持,簡(jiǎn)單的做法可以直接基于Spring的標(biāo)準(zhǔn)Bean來(lái)配置,Spring提供了可擴(kuò)展Schema的支持,這是一個(gè)不錯(cuò)的折中方案,需要的朋友可以參考下2023-12-12
SpringBoot中讀取jar包中的resources目錄下的文件的三種方式
這篇文章給大家總結(jié)了SpringBoot讀取 jar 包中的 resources 目錄下的文件的三種方式,文中有詳細(xì)的代碼示例供大家參考,,需要的朋友可以參考下2023-06-06
如何使用eclipse搭建maven多module項(xiàng)目(構(gòu)建父子項(xiàng)目)
這篇文章主要介紹了如何使用eclipse搭建maven多module項(xiàng)目(構(gòu)建父子項(xiàng)目) ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
SpringBoot監(jiān)聽(tīng)Redis key失效事件的實(shí)現(xiàn)代碼
這篇文章給大家介紹了SpringBoot實(shí)現(xiàn)監(jiān)聽(tīng)Redis key失效事件的方法,文中通過(guò)代碼示例給大家講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-02-02

