Spring四种注解

Spring主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:

@Component:可以用于注册所有bean

@Repository:主要用于注册dao层的bean

@Controller:主要用于注册控制层的bean

@Service:主要用于注册服务层的bean

 

描述依赖关系主要有两种:

@Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。

@Resource

@Qualifier("userDaoMyBatis")

private IUserDao userDao;

public UserService(){

}

@Autowired:spring注解,默认是以byType的方式去匹配类型相同的bean,如果只匹配到一个,那么就直接注入该bean,无论要注入的bean的name是什么;如果匹配到多个,就会调用 DefaultListableBeanFactory 的 determineAutowireCandidate 方法来决定具体注入哪个bean。determineAutowireCandidate 方法的内容如下:

// candidateBeans 为上一步通过类型匹配到的多个bean,该 Map 中至少有两个元素。

protected String determineAutowireCandidate(Map candidateBeans, DependencyDescriptor descriptor) {
   
//  requiredType 为匹配到的接口的类型
   
Class requiredType = descriptor.getDependencyType();
   
// 1. 先找 Bean 上有@Primary 注解的,有则直接返回
   
String primaryCandidate = this.determinePrimaryCandidate(candidateBeans, requiredType);
   
if (primaryCandidate != null) {
       
return primaryCandidate;
    }
else {
       
// 2.再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回
       
String priorityCandidate = this.determineHighestPriorityCandidate(candidateBeans, requiredType);
       
if (priorityCandidate != null) {
           
return priorityCandidate;
        }
else {
            Iterator var6 = candidateBeans.entrySet().iterator();
            String candidateBeanName;
            Object beanInstance;
           
do {
                
if (!var6.hasNext()) {
                   
return null;
                }
               
// 3. 再找 bean 的名称匹配的
               
Entry entry = (Entry)var6.next();
                candidateBeanName = (String)entry.getKey();
                beanInstance = entry.getValue();
            }
while(!this.resolvableDependencies.values().contains(beanInstance) && !this.matchesBeanName(candidateBeanName, descriptor.getDependencyName()));
           
return candidateBeanName;
        }
    }
}

determineAutowireCandidate 方法的逻辑是:

先找 Bean 上有@Primary 注解的,有则直接返回 bean 的 name。

再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回 bean 的 name。

最后再以名称匹配(ByName)的方式去查找相匹配的 bean。

可以简单的理解为先以 ByType 的方式去匹配,如果匹配到了多个再以 ByName 的方式去匹配,找到了对应的 bean 就去注入,没找到就抛出异常。

还有一点要注意:如果使用了 @Qualifier 注解,那么当自动装配匹配到多个 bean 的时候就不会进入 determineAutowireCandidate 方法(亲测),而是直接查找与 @Qualifer 指定的 bean name 相同的 bean 去注入,找到了就直接注入,没有找到则抛出异常。

tips:大家如果认真思考可能会发现 ByName 的注入方式和 @Qualifier 有点类似,都是在自动装配匹配到多个 bean 的时候,指定一个具体的 bean,那它们有什么不同呢?

ByName 的方式需要遍历,@Qualifier 直接一次定位。在匹配到多个 bean 的情况下,使用 @Qualifier 来指明具体装配的 bean 效率会更高一下。

你可能感兴趣的:(JAVA)