@Autowired 是通过类型查找还是通过属性名查找?
前面笔者对@Autowired 的一些重难点做了深入的了解,并对一些关键源码做了深入分析,本节将对@Autowired 的注入方式做详细介绍。
还是先从案例分析看起:一个User接口
public interface User {
}
两个User实现类
@Component
public class User2 implements User{
}
@Component
public class User1 implements User {
}
然后再写一个注入类
@Component
public class UserTest {
@Autowired
private User user;
@PostConstruct
public void init(){
System.out.println(user);
}
}
最后测试类和配置类:
import com.MyImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan("com")
/*@EnableAspectJAutoProxy*/
/*@Import(MyImportBeanDefinitionRegistrar.class)*/
public class AppConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext=
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
然后执行:
十二月 16, 2020 10:29:50 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userTest': Unsatisfied dependency expressed through field 'user'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.User' available: expected single matching bean but found 2: user1,user2
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userTest': Unsatisfied dependency expressed through field 'user'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.User' available: expected single matching bean but found 2: user1,user2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:603)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:381)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1428)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:319)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:848)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:892)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:556)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:100)
at Test.main(Test.java:21)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.User' available: expected single matching bean but found 2: user1,user2
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:221)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1234)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1176)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:600)
... 14 more
可以看到错误,找不到唯一的User实现类,这里的错误很容易想明白,因为我们实现了两个User类,这里Spring会无法识别具体的那个类作为实现类
,因此就会出现异常,当然这也可以解决,我们可以使用@qualifier注解进行分组,让这个类有唯一表示,这样就能解决冲突,当然我们这里并不是为了解决这个问题,而是想知道@Autowired 到底是通过类型查找还是通过属性名查找?这里笔者先给出答案,先通过类型查找,如果找到了多个实现了在通过名字去对比。下面我们通过源码来证明。
我们直接定位到AutowiredAnnotationBeanPostProcessor这个类,看过笔者前面的文章都知道这个类是干什么的,如果不知道请读者自行查漏补缺
然后我们继续跟踪
一直跟踪
再跟踪
看到这个doResolveDependency方法,点进去
注意看这两个数据,这就是我们在UserTest这个类注入的User属性,此时已经获取了这个类属性,我们继续往下看
还是这个doResolveDependency,我们看到的是Spring是先获取了User接口的所有实现类,我们继续往下看,
相信看到这里,读者一定明白了Spring的注入逻辑了吧,希望看完这篇文章让大家对Spring的源码有更深入的认识。