Bean的自動(dòng)注入及循環(huán)依賴問題
一、spring中的各種注入方式
對于是spring的注入前置知識、@Autowired、@Resource等的知識可以看其他文章,這里就不多說了
我們對Bean的注入,一般有下面幾種方式:
1)、通過@Autowired、@Resource作用在屬性上
2)、通過@Autowired、@Resource作用在方法上
3)、通過提供set方法+改變注入模型為自動(dòng)注入
4)、通過BeanDefinition方式完成屬性注入
我們先說前三種方式:
我們用下面的測試類來檢驗(yàn):
1、測試注解作用在屬性上:
@Component
public class AnnotationAutowiredFiledBeanTest {
}2、測試注解作用在方法上:
@Component
public class AnnotationAutowiredMethodBeanTest {
}3、測試通過提供set方法+改變注入模型為自動(dòng)注入
@Component
public class AutowiredInjectByTypeMethodBeanTest {
}修改為注入模型類:
/**
* 用來設(shè)置SpringBeanInfoTest類的屬性注入為自動(dòng)注入模式
*
* */
@Component
public class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");
a.setAutowireMode(2);
//a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());
}
}4、各種方式的注入類:
@Component("a")
public class SpringBeanInfoTest {
//@Autowired作用在屬性上進(jìn)行注入
@Autowired
AnnotationAutowiredFiledBeanTest autowiredFiledBeanTest;
//@Autowired作用在方法上進(jìn)行注入
@Autowired
public void setAnnotationAutowiredMethodBeanTest(AnnotationAutowiredMethodBeanTest annotationAutowiredMethodBeanTest){
System.out.println("AnnotationAutowiredMethodBeanTest=[{}]"+annotationAutowiredMethodBeanTest);
}
//使用自動(dòng)注入(使用byType的模式)
public void setAutowiredInjectByTypeMethodBeanTest(AutowiredInjectByTypeMethodBeanTest autowiredInjectByTypeMethodBeanTest){
System.out.println("AutowiredInjectByTypeMethodBeanTest=[{}]"+autowiredInjectByTypeMethodBeanTest);
}
//用來打印@Autowired作用在屬性上進(jìn)行注入是否成功
public void printf(){
System.out.println("autowiredFiledBeanTest=[{}]"+autowiredFiledBeanTest);
}
}5、啟動(dòng)測試類:
配置類:
@Configuration
@ComponentScan("com.spring.demo.introspect")
public class App {
}啟動(dòng)類:
public class ApplicationTest {
@Test
public void testSpringInject() throws NoSuchFieldException, IntrospectionException {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext();
context.register(App.class);
context.refresh();
context.getBean(SpringBeanInfoTest.class).printf();
}
}此時(shí)我們在UpdateBeanInfoBeanFactoryPostProcessor類中設(shè)置了SpringBeanInfoTest類的屬性注入為自動(dòng)注入(2,默認(rèn)為0)。我們運(yùn)行下看看注入情況:
此時(shí)發(fā)現(xiàn)三種情況都能進(jìn)行注入

此時(shí)我們修改注入模型為默認(rèn)的手動(dòng)注入。
/**
* 用來設(shè)置SpringBeanInfoTest類的屬性注入為自動(dòng)注入模式
*
* */
@Component
public class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");
//a.setAutowireMode(2);
//a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());
}
}結(jié)果打印

此時(shí)發(fā)現(xiàn)第三種方式無法注入了。
那么此時(shí)我們再來測試下第四種方式(通過BeanDefinition方式)
我們知道java內(nèi)省機(jī)制最后都是講解析出來的屬性等轉(zhuǎn)換為一個(gè)BeanInfo對象,然后所有屬性等信息存在一個(gè)PropertyDescriptor數(shù)組中,而spring中在BeanDefinition中定義了一個(gè)MutablePropertyValues對象(propertyValues)中的一個(gè)List用來定義描述這個(gè)類的屬性等,那么我們要往SpringBeanInfoTest中注入一個(gè)屬性,此時(shí)就可以往這個(gè)List中存進(jìn)我們要注入的對象即可。
(其實(shí)四種方式都是往propertyValues的List中添加屬性內(nèi)容,最后會對這個(gè)list進(jìn)行統(tǒng)一的處理。只是前三種通過不同方式獲取到屬性內(nèi)容,然后放進(jìn)list,而第四種則是直接add進(jìn)行)
我們先編寫一個(gè)測試類(這里不用@Component):
public class BeanDefinitionPropertyValuesBeanTest {
}此時(shí)在UpdateBeanInfoBeanFactoryPostProcessor 類中進(jìn)行BeanDefinition方式的注入:
/**
* 用來設(shè)置SpringBeanInfoTest類的屬性注入為自動(dòng)注入模式
*
* */
@Component
public class UpdateBeanInfoBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
AbstractBeanDefinition a = (AbstractBeanDefinition) beanFactory.getBeanDefinition("a");
a.getPropertyValues().add("beanDefinitionPropertyValuesBeanTest",new BeanDefinitionPropertyValuesBeanTest());
}
}這里由于是手動(dòng)的修改BeanDefinition對象,所以其注入模型并不會影響到這個(gè)是否生效。
然后在SpringBeanInfoTest中添加注入方法:
@Component("a")
public class SpringBeanInfoTest {
//@Autowired作用在屬性上進(jìn)行注入
@Autowired
AnnotationAutowiredFiledBeanTest autowiredFiledBeanTest;
//@Autowired作用在方法上進(jìn)行注入
@Autowired
public void setAnnotationAutowiredMethodBeanTest(AnnotationAutowiredMethodBeanTest annotationAutowiredMethodBeanTest){
System.out.println("AnnotationAutowiredMethodBeanTest=[{}]"+annotationAutowiredMethodBeanTest);
}
//使用自動(dòng)注入(使用byType的模式)
public void setAutowiredInjectByTypeMethodBeanTest(AutowiredInjectByTypeMethodBeanTest autowiredInjectByTypeMethodBeanTest){
System.out.println("AutowiredInjectByTypeMethodBeanTest=[{}]"+autowiredInjectByTypeMethodBeanTest);
}
//添加使用BeanDefinition方式進(jìn)行屬性注入
public void setBeanDefinitionPropertyValuesBeanTest(BeanDefinitionPropertyValuesBeanTest beanDefinitionPropertyValuesBeanTest){
System.out.println("BeanDefinitionPropertyValuesBeanTest=[{}]"+beanDefinitionPropertyValuesBeanTest);
}
//用來打印@Autowired作用在屬性上進(jìn)行注入是否成功
public void printf(){
System.out.println("autowiredFiledBeanTest=[{}]"+autowiredFiledBeanTest);
}
}我們可以來看看是否生效:

可以看是可以進(jìn)行注入的。
下面我們可以先簡單的對這四種情況做個(gè)總結(jié),后續(xù)再進(jìn)行源碼分析驗(yàn)證猜想:
1)、在一個(gè)屬性上面加一個(gè)@Autowired注解
使用反射機(jī)制進(jìn)行注入,可以看@Autowired源碼,偽代碼大概如下:
Class clazz = null;
Field autowiredFiledBeanTest = clazz.getDeclaredField("autowiredFiledBeanTest");
autowiredFiledBeanTest.setAccessible(true);
autowiredFiledBeanTest.set(this,getBean(AnnotationAutowiredFiledBeanTest.class));2)、在一個(gè)方法上面加一個(gè)@Autowired注解
2.1如果注入模型是1、2 (自動(dòng)注入),那么spring底層采用的是java的自省機(jī)制發(fā)現(xiàn)setter方法然后調(diào)用執(zhí)行
* 也就是說方法上面的@Autowierd注解無用,直接走內(nèi)省機(jī)制進(jìn)行注入而不是通過解析@Autowierd進(jìn)行注入
2.2如果注入模型為0(默認(rèn)值,手動(dòng)注入) 那么則是和在屬性上面加注解差不多,底層查找所有加了@Autowired注解的方法,然后反射調(diào)用method.invoke()
3)、提供一個(gè)setter方法,繼而把該bean的注入模型改成1、2 自動(dòng)注入
* 3.1 注入模型是自動(dòng)注入 則是java的內(nèi)省機(jī)制
偽代碼如下:
BeanInfo beanInfo = Introspector.getBeanInfo(SpringBeanInfoTest.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(this,getBean(parma))
}4)、使用BeanDefinition方式進(jìn)行注入
不和注入模型有相關(guān)聯(lián),即所有情況都能生效
------------------------------------------源碼驗(yàn)證
入口:refresh---》
finishBeanFactoryInitialization----》beanFactory.preInstantiateSingletons();---》
getBean---》doGetBean---》createBean-----》doCreateBean----》populateBean
我們進(jìn)入populateBean方法看看:
//先從容器中獲取bean,有則直接返回進(jìn)行注入
//無則調(diào)用createBean創(chuàng)建需要進(jìn)行注入的bean,放進(jìn)單例池,最后再進(jìn)行注入
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
//1、獲取到MutablePropertyValues對象,里面的List<PropertyValue> propertyValueList封裝著一些屬性的定義
//這里現(xiàn)在只能獲取到手動(dòng)使用BeanDefinition動(dòng)態(tài)添加的屬性
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//獲取注入模型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//2、注入模型為1或者2(自動(dòng)注入),通過內(nèi)省機(jī)制獲取所有符合的屬性(包括獲取到使用了@Autowired注解的set),并getbean放進(jìn)propertyValueList中
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
//獲取到符合規(guī)則的屬性(setter)
//然后獲取到該屬性的bean,并加入到MutablePropertyValues中的List中
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
//獲取到符合規(guī)則的屬性(setter)
// 然后獲取到該屬性的bean,并加入到MutablePropertyValues中的List中
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
//所有符合上面的屬性都會加到這里
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
//3、如果注入模型為0,手動(dòng)注入,此時(shí)這里的propertyValueList只會存在我們手動(dòng)使用BeanDefinition add進(jìn)去的。
//那么到這里為止所有set方法都沒被識別到(既不會在applyPropertyValues中執(zhí)行了)
//下面的循環(huán)則是去解析@Autowired作用的屬性、方法(反射機(jī)制)
//注意:如果該屬性已經(jīng)存在propertyValueList,這里則不會對其進(jìn)行解析(即自動(dòng)注入模型下@Autowired作用在方法的被忽略執(zhí)行)
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//獲取到所有BeanPostProcessor
//如果是InstantiationAwareBeanPostProcessor,即處理@Autowired注解、@Resouce注解、@PostConstruct注解的BeanPostProcessor類型,則完成注入等操作
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//完成@Autowired作用在屬性、方法上面的處理(使用反射)
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//完成@Autowired作用在屬性、方法上面的處理
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
//4、處理propertyValueList中的所有還未執(zhí)行的屬性
//遍歷屬性名、對象,內(nèi)省機(jī)制調(diào)用invoke方法執(zhí)行set方法等
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}我們總結(jié)下:
1、先獲取手動(dòng)添加的propertyValueList的(通過BeanDefinition進(jìn)行add的)
2、如果注入模型為自動(dòng)注入,則通過內(nèi)省機(jī)制獲取所有符合的規(guī)則的屬性(包含使用注解、未使用注解的),getBean獲取到bean對象,并加入到propertyValueList中
3、通過反射獲取使用@Autowired注解的屬性,并解析執(zhí)行。這里有幾點(diǎn)需要注意
1)、解析包含@Autowired作用的屬性和方法兩種
2)、如果該屬性存在propertyValueList則不進(jìn)行解析(即當(dāng)注入模型為自動(dòng)注入時(shí),@Autowired作用的方法上的方式在步驟2中使用內(nèi)省機(jī)制進(jìn)行獲取,此時(shí)跳過第三步)
4、對propertyValueList的所有屬性調(diào)用invoke方法執(zhí)行
不同方式在不同注入模型下獲取屬性的方式不同(內(nèi)省機(jī)制、反射機(jī)制)
到此這篇關(guān)于Bean的自動(dòng)注入及循環(huán)依賴問題的文章就介紹到這了,更多相關(guān)Bean的自動(dòng)注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springBoot+mybatis-plus實(shí)現(xiàn)監(jiān)聽mysql數(shù)據(jù)庫的數(shù)據(jù)增刪改
mybatis-plus技術(shù)是簡化了繁瑣的代碼操作,把增刪改查的語句都內(nèi)置了,直接調(diào)用就可以實(shí)現(xiàn)數(shù)據(jù)庫的增刪改查了,這篇文章主要給大家介紹了關(guān)于springBoot+mybatis-plus實(shí)現(xiàn)監(jiān)聽mysql數(shù)據(jù)庫數(shù)據(jù)增刪改的相關(guān)資料,需要的朋友可以參考下2024-01-01
IntelliJ IDEA2023中運(yùn)行Spring Boot找不到VM options進(jìn)
這篇文章主要介紹了IntelliJ IDEA2023中運(yùn)行Spring Boot找不到VM options進(jìn)行端口的修改的問題解決,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
Java詳細(xì)講解不同版本的接口語法和抽象類與接口的區(qū)別
對于面向?qū)ο缶幊虂碚f,抽象是它的一大特征之一,在?Java?中可以通過兩種形式來體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關(guān)于Java入門基礎(chǔ)之抽象類與接口的相關(guān)資料,需要的朋友可以參考下2022-04-04
java實(shí)現(xiàn)微信企業(yè)付款到個(gè)人功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信企業(yè)付款到個(gè)人功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
Java為什么基本數(shù)據(jù)類型不需要進(jìn)行創(chuàng)建對象?
今天小編就為大家分享一篇關(guān)于Java為什么基本數(shù)據(jù)類型不需要進(jìn)行創(chuàng)建對象?,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-04-04

