当前位置:网站首页>@Autowired annotation --required a single bean, but 2 were found causes and solutions

@Autowired annotation --required a single bean, but 2 were found causes and solutions

2022-08-10 19:57:00 qq_43479892

优质资源分享

学习路线指引(点击解锁)知识定位人群定位
🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统.
Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

@Autowired注解是springOne of the core tool used to support the dependency injection,But we will meet more or lessrequired a single bean, but 2 were found(2可能是其他数字)的问题,Next, we from the Angle of the source to see why this problem,And what is the solution to the problem?

首先我们写一个demoReplicate our this problem.First of all, we have an abstract classAbstractAutowiredDemo,两个实现类AutowiredDemo1,AutowiredDemo2.然后我们在AutowiredDemoController中通过@Autowired依赖注入AbstractAutowiredDemo.

@RestController
public class AutowiredDemoController {

    @Autowired
    private AbstractAutowiredDemo abstractAutowiredDemo;
}

@Component
public abstract class AbstractAutowiredDemo {
    public abstract String print();
}

@Component
public class AutowiredDemo2 extends AbstractAutowiredDemo {
    @Override
    public String print() {
        return "AutowiredDemo2";
    }
}

@Component
public class AutowiredDemo1 extends AbstractAutowiredDemo {
    @Override
    public String print() {
        return "AutowiredDemo1";
    }
}

At this time we start the project will appear the following error,找到了两个,And lists the find is in fact the two abstract class implementation class.
image-20220810000447577

接下来,We look at from the perspective of source,springIs how to find the dependence and inject.

With the view [email protected] method,我们全局搜索Autowired,Find a calledAutowiredAnnotationBeanPostProcessor,根据命名AutowiredAnnotationXXXWe can probably know this class is used to deal with [email protected]的.
image-20220810000728964

进入AutowiredAnnotationBeanPostProcessor,We can know from the annotation class - this class can handle [email protected],@ValueAnd if support [email protected],Here we only focus [email protected]就行了,Other will see later,And in no arguments constructor sets to support these type.
image-20220810001541749

然后开始进入正题,We begin to see,spring是如何处理,How to find the dependence and inject,But why is our main task is the above mistakes,Such a purposeful look,Despite what other details,To relatively easy to.

Here can look at the source code is a skill,之前的ComponentScanAnnotationParser很简单,里面只有一个parse方法,We know it,但是在AutowiredAnnotationBeanPostProcessor这个里面,这么多方法,我们应该看什么呢?First of all we want is processing annotation method,Should be provided out of the way,So should be apubilic方法,(We at ordinary times when coding should be also the habit,To providepublicMethods should be put in front,protect,peivateThis to the back,Because the smaller scope universality is lower,Use the smaller the probability).But in front of a fewpublic方法都是在set属性值,所以排除掉,Then followed by two name is withbean定义有关的,一个是合并,One is the reset,Can temporarily away from,Then followed a decision which one to use the constructor of,It should be findbeanAnd then when instantiated with,Then there is a rear handle properties,而我们的@AutowiredIs the annotations on the property field,Here we see a step,看看方法的实现,有Injection of autowired dependencies字样,And according to the name check metadata,The process of the injection again,Guess is that this method.
image-20220810004056377

Then emphatically to seeAutowiredAnnotationBeanPostProcessor.postProcessProperties这个方法.

首先第一行,The method name is injection of metadata in finding.

进入方法AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata,We can see this code is to judgecache中是否已经有了,And whether need to refresh(The refresh is type is empty or notclazz,Can point in view),不需要直接返回,Need to start lock(Lock and then conducted a check,双重校验,小知识点,To avoid in the process of lock,已经put进去),And then to build metadatabuildAutowiringMetadata
image-20220810005136309

进入方法AutowiredAnnotationBeanPostProcessor.buildAutowiringMetadata,See the first judgment,Do you remember just began to speak,This class handles the annotation type,Here is in the judgment,我们的@AutowiredIs certainly in the,And then in the middle ado…while循环,The current class, and its parent class is annotated fields,方法放入elements中,最终返回一个InjectionMetadata对象,And set up itstargetClass为clazz,injectedElements为elements.Now we need to be equivalent to dependency injection metadata found.
image-20220810005331865

Then start injection process,我们回到postProcessProperties方法,Check the injection method.

进入InjectionMetadata.inject方法,We found in the metadata is used here,我们不管checkedElements,至少我们的injectedElements肯定是有的,In the previous step to find the metadata,我们已经set进去了,Next, we will continue to go down.
image-20220810005907075

As we continue to enterinject方法的时候,There's a phrase we found the comments on,this和getResourceToInjectAll need to override this method,So this method is not we need injection method of realize.
image-20220810010337954

Click the down arrow on the left,We can find two implementation methods,根据命名,一个处理field的,一个处理method的,Obviously we need here is processingfield的.
image-20220810010522762

进入AutowiredFieldElement.inject方法,We see him first to determine whether the cache,Our hypothesis is the first time in here,没有缓存(Cache is certainly before loading in),So we should goelse分支.
image-20220810010654020

进入AutowiredFieldElement.inject.resolveFieldValue方法,我们可以看到,Beginning is doing some preparation,可以忽略,The last is cached in will look up to,我们也可以不看,重点就是try中的内容,解决依赖.
image-20220810011205339

进入方法AutowireCapableBeanFactory.resolveDependency,We need to find its implementation method,Click the down arrow on the left,You can see two implementation methods,According to the same name,The red box is obviously used to deal withbean的.
image-20220810011441575

进入DefaultListableBeanFactory.resolveDependency方法,大概扫一眼,The front is in the judgmentdescriptor.getDependencyType()This value is the type of the class,Apparently our own definition of class,Is not this type,So we directly to the lastelse,elseIn the first sentence is if you are lazy loading,Is not loaded before,So the real logic in here.(In fact, we is to find a solution to rely on,而springMethod named are see article knowledge meaning,So we could start with positioning directly to the following,Found wrong again,This is to look at the source code when a train of thought)
image-20220810011720013

进入DefaultListableBeanFactory.doResolveDependency方法,Here is the real find rely on the core of the,接下来我们仔细分析一下.
image-20220810015324952

Step1:通过descriptor.resolveShortcut(this)返回shortcut,We order into this method view annotations can be found,This is used to do some resolution in advance,一般是spring自用的,If we no special Settings,一般不会用到,所以这个shortcut应该为null,方法不会返回.
Step2:通过getAutowireCandidateResolver().getSuggestedValue(descriptor)返回value,Point method view into,According to the comments to see,This is a default value for a given depend on the advice of,Should deal with [email protected]所以这里value为null,方法不返回.
Step3:通过resolveMultipleBeans返回multipleBeans,You can see inside is in the judgment of our current search depend on the type of what conditions is in line with the(stream或者集合类型,所以这个叫multi),而我们当前的typeIs the abstract class we define,所以这里multipleBeans也为null,方法不返回.
Step4:通过findAutowireCandidates返回matchingBeans(Actually see the method name,就是处理Autowired注解,To find the candidate),Point method view into.

进入方法DefaultListableBeanFactory.findAutowireCandidates,First of all, the first line, we can see in finding candidates name.
image-20220810015803016

进入方法BeanFactoryUtils.beanNamesForTypeIncludingAncestors,We can see here and call a method,通过type获取beanNames,Point into the annotation can see here will get the current types ofbean的名称(Excludes abstract class,No longer deep inside,Can point into the),包括子类,Actually see here should probably guess,We through the above abstract classAbstractAutowiredDemoGot a subclass of it,So error is a subclass insideAutowiredDemo1和AutowiredDemo2.Middle section could then find out more,But here we don't care,Now we return directly,此时String[]Should contain two elements.
image-20220810015929343

回到方法DefaultListableBeanFactory.findAutowireCandidates,我们可以发现,result中至少有两个元素,下面的forAre inside to continueadd,We no longer see here,继续往外走.
image-20220810020829395

回到方法DefaultListableBeanFactory.doResolveDependency,matchingBeansAt least two elements in the,Will enter the following aif,而在ifIn the first code is in deciding which candidate selectionbean,There is also a point we solve the problem of.
image-20220810021015084

进入DefaultListableBeanFactory.determineAutowireCandidateWhether will find it to find the Settingsprimary,priority,Have no word cycle,See if already loaded or is currently,The ultimate goal is to determine a candidate as di,But we have this case,Apparently decided not to.
image-20220810021843921

After returning to outside method,因为@Aurowired的required默认就是为true,So will enter theif,Returns a find is not the only exception.
image-20220810021930341

总结

@AutowiredAnnotation fields find and dependent process can be summarized as:Find need field di,通过classType search can be injected class(包括子类),Decided to inject class,注入.

So to solve the problem of articles began to appear,有两个办法:
1.In the search to evade,Is specified when the injectedDemo1还是Demo2
image-20220810022926244

2.In the class decided to inject around,通过注解@Primary或者@Priority
image-20220810023004824

原网站

版权声明
本文为[qq_43479892]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/222/202208101904548812.html