說起spring的注入,可能大家都有了解。可你認知幾種注入方式呢?你所認知的注入方式是否正確呢?我估計大多數人了解注入方式不全面,并且還會曲解一些概念。今天我們就參考最權威的官網來具體談談spring的注入方式。
這里想給大家復習一下Spring的基礎知識,對于后續理解有很大幫助
IOC&&DI
想必關于這兩個概念大家不會陌生,面試題經常會出現的。這里我們就從官網詳細文檔看一看。
詳細的翻譯具體概念我就不講了,在這我只說出自己的理解
其實IOC也被稱為DI,因為在spring中IOC作用就是不需要程序員來手動創建和管理JAVA類,而是由spring容器自動實例化Bean對象。怎么個IOC呢,其實就是通過DI(依賴注入)實現的。
補充一點關于spring的bean對象(后面簡稱bean)
其實bean對象就是java對象,不同的在于Bean對象是由spring創建管理對象。
bean對象 是 java對象,但java對象 不一定是 bean對象
我們的業務類,經過spring容器DI添加源數據從而生成一個Bean對象可以被使用。這也就是spring IOC容器的運行流程圖。
Configuration Metadata(IOC)
關于配置元數據,spring官方文檔給出了三種配置方式
- XML-based metadata 1.0版本
- Annotation-based configuration 2.5版本
- Java-based configuration 3.0版本
雖說三種,但其實我接觸也只有前兩種。本文也是關于前兩種詳細介紹。
基于 XML 的 bean 注入方式
xml手動配置bean (自動裝配可以通過set方法自動創建pojo類對象加上元數據信息構造成bean對象)
基于 XML 的 bean 注入方式的實現有三種方法:
- xml配置ref
- 屬性 setter方法注入(或設值注入)
- 構造方法注入
在基于 XML 的 bean 裝配中,我們需要了解一下自動注入模型
關于自動模型官網上解釋說:當使用基于xml的注入方式時,可以指定自動連接模式
也就是說spring 的自動注入的模型 (僅僅針對xml-based配置)
使用java,annotation另外兩種注入方式沒有注入模型
Autowiring Collaborators(自動注入的模型)
- no :(默認)沒有自動裝配。Bean引用必須由ref元素定義。
- byname:通過名稱查找bean自動裝配屬性。
- bytype:通過類型找bean,根據set或者構造方法注入
- construct 推斷構造方法 通過構造方法自動配置,如果多個構造方法選擇多個參數的構造方法
Annotation-based configuration(注解注入)
@Autowired和@Resource兩個注解實現。面試題中也經常會問到兩個注解的區別,我搜索網上的答案卻講的是@Autowired是通過bytype,@Resource是通過byname。但這種理解顯然是錯誤的,因為關于自動模型文章前面也已經說過 官網:當使用基于xml的注入方式時,可以指定自動連接模式
@Autowired和@Resource只不過是通過type,name去查找,而不是bytype以及byname模式。有什么區別?
區別在于byname通過名字找bean自動填充–>沒找到就會報錯
bytype通過類型去找bean自動填充–>沒找到就會報錯
1. @Autowired:type --> name --> error
不僅僅通過type找。type找不到,還可以通過name找。都找不到才會報錯
spring包中的AutowiredAnnotationBeanPostProcessor.java中的一個方法實現解析的
2. @Resource:name --> type --> error
不僅僅通過name找。name找不到,還可以通過type找。都找不到才會報錯
javax中的 commonAnnotationBeanPostProcessor.java中的一個方法實現解析的
這里再強調一下:
注解 無關注入的模型(no,byname,bytype,constract)
怎么說?還相信網上的知識點嗎?不相信我說的?那可以我們還是來用code證明。
Talk is cheap,show you my code
準備階段
- 創建一個spring項目
- 創建Appconfig類以及test類
- 創建幾個service類
Appconfig.java
package services;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
@Configurable
@ComponentScan("com.shadow")
public class Appconfig {
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
}
}
其余都為空
基于 XML 的 bean 注入方式
no方式配置
GoudanService.java
package services;
public class GoudanService {
GouService gouService; public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
<property name="gouService">
<ref bean="gouBean"></ref>
</property>
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
}
}
運行Test.java的result
想要在GoudanService中配置GouService,我們采用xml配置方式的no注入模型。雖然我們沒有配置注入模型參數但是xml默認是no。故所以我們運行Test.java得出結果是配置成功的。
我把xml這一段注釋掉呢?
根據no注入模型的官網解釋,大家應該知道這是無法自動配置的,也就是null。
bytype方式配置
GoudanService.java
package services;
public class GoudanService {
GouService gouService; public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
}
}
運行Test.java的result
我們發現bytype模型注入,與no方式注入想比不需要了bean里配置property的ref,spring容器會自動根據GouService的類型去找bean,結果找到了類型為:services.GouService的bean,所以也是可以配置成功的。
重點:bytype就是如果屬性類型與bean的class類型相同那么可以自動配置,否則配置錯誤。看下面圖
byname方式配置
GoudanService.java
package services;
public class GoudanService {
GouService gouService; GouService gouBean; public GouService getGouBean() {
return gouBean;
} public void setGouBean(GouService gouBean) {
this.gouBean = gouBean;
} public void setGouService(GouService gouService) {
this.gouService = gouService;
} public GouService getGouService() {
return gouService;
}}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
// System.out.println(cc.getBean(GoudanService.class).getGouService());
System.out.println(cc.getBean(GoudanService.class).getGouBean());
}
}
運行Test.java的result
我們發現byname模型注入,與no方式注入想比不需要了bean里配置property的ref,spring容器會自動根據GouService定義屬性名稱去找bean的名稱,結果找到了id名稱為:gouBean的bean,所以也是可以配置成功的。
byname就是如果屬性名稱與bean的id名稱相同那么可以自動配置,否則配置錯誤。
construct方式配置
GoudanService.java
package services;
public class GoudanService {
GouService gouService;
GouService gouBean; //構造方法1
GoudanService(GouService gouBean){ this.gouBean=gouBean; }// //構造方法2
// GoudanService(GouService gouService){
// this.gouService=gouService;
// }
// //構造方法3
// GoudanService(GouService gouService,GouService gouBean){
// this.gouService=gouService;
// this.gouBean=gouBean;
// }
public GouService getGouBean() {
return gouBean;
}
public GouService getGouService() {
return gouService;
}
// public void setGouBean(GouService gouBean) {
// this.gouBean = gouBean;
// }
// public void setGouService(GouService gouService) {
// this.gouService = gouService;
// }
}
web.xml
<bean id="goudanBean" class="services.GoudanService">
</bean>
<bean id="gouBean" class="services.GouService">
</bean>
Test.java
package test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import services.GoudanService;
public class Test {
public static void main(String[] args) {
// AnnotationConfigApplicationContext ac =
// new AnnotationConfigApplicationContext(Appconfig.class);
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("web.xml");
System.out.println(cc.getBean(GoudanService.class).getGouService());
System.out.println(cc.getBean(GoudanService.class).getGouBean());
}
}
分別運行構造方法1,2,3三次,注釋掉其他兩種構造方法
運行Test.java的result
構造方法1
構造方法2
構造方法3
我們發現construct模型注入,它既可以通過name注入也可以通過type注入。
Annotaton-based configuration(注解注入方式)
@Autowired
在這里,很多人網上說@Autowired是通過bytype查找,但其實這種說法有些許的不嚴謹。
1.自動注入模型是基于xml的bean注入方式。
2.bytype模型是只要通過類型查找,如果找不到,或者找到兩個相同的類型bean就會報錯
3.而@Autowired是通過類型去找,找不到還會通過名稱去找
@Resource
而@Resource是通過byname查找,這種說法和@Autowired相似也是不嚴謹的。
byname模型是只要通過名稱查找,如果找不到報錯而@Resource是通過名稱去找,找不到還會通過類型去找,不單單只限于通過name去查找。
區別
- @Autowired type --> name --> error
spring包中的AutowiredAnnotationBeanPostProcessor.java中的一個方法實現解析的 - @Resource name --> type --> error
javax中的 commonAnnotationBeanPostProcessor.java中的一個方法實現解析的
來源:https://blog.csdn.net/qq_40994080/article/details/108090104?utm_medium=distribute.pc_category.none-task-blog-hot-2.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-hot-2.nonecase&request_id=






