spring源码 |
您所在的位置:网站首页 › autowire和resoure区别 › spring源码 |
上篇博客说了自动注入模型的使用,这篇笔记打算记录下自动注入模型中,autowireMode为0的情况,也就是我们经常用到的@Autowired、@Resource注解的原理 首先对于这两个注解,都是由后置处理器来完成解析的,解析的时机是一样的,在第六个后置处理器执行的时候;但是是由不同的后置处理器来完成解析的 @Autowired注解: org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues@Resource注解: org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessPropertyValues 前言1、这两个注解,都是在第六个后置处理器执行的时候,进行解析的,但是在第三个处理器 org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition执行的时候,会先解析一下当前bean中有哪些属性要进行注入,在第六个后置处理器执行的时候,就无须进行解析,直接从map中获取要注入的属性即可 2、这两个注解虽然是由不同的后置处理器处理的,但是处理的思想、步骤大致都是一样的: 会先尝试获取bean中添加了该注解的方法(method)和属性(field)找到之后,会根据实现类的优先级、或者是name等从容器中或者beanDefinitionMap中找到对应的属性通过filed.set()完成属性的注入3、这里有几个点要先行说明: 对于@Resource注解,会根据要注入属性的name,从单实例池中获取bean,完成属性注入对于@Autowired注解,我们通常说是现根据类型注入,如果找到多个或者没有找到,再根据name进行注入;这里要说明的是:spring在解析@Autowired注解的时候,并不是直接从单实例池中查找bean,而是先从beanDefinitionMap中,根据type查找,如果找到多个,再根据name从单实例池中查找,只有找到确定要注入哪个类,才会从单实例池中找到对应的bean,完成注入当然,和@Autowired注解配合使用的注解有好几个,在下面会一一解析 @Autowired
第一个注解使用在field上,在根据类型从beanDefinitionMap中找到bean之后,会判断哪个beanName是否是合格的;如果要注入的bean有多个实现类,会优先注入@Qualifier注解指定的实现类 第二个直接是在类上使用的,在未添加@Qualifier注解的场景下,如果有多个实现类,会判断哪个实现类上添加了@Primary注解,添加了,就注入该实现类 第三个注解也是加载类上,如果既没有添加@Qualifer、也没有添加@Priority注解,那么,会判断哪个实现类的优先级比较高,值越小,优先级越高 这是 org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency的部分代码 /** * @Autowired注解源码 三 * 查找要注入的bean,按照type来查找,如果匹配到一个,就获取到这个实例,然后返回,返回之后,会调用field.set();注入进去 * 如果找到了多个,那就先判断哪个实现类有@primary注解,如果都没有注解,那就判断priority的优先级 * * 这个方法中,对Qualifier注解进行了处理;如果一个接口有多个实现类,但是没有加@Qualifier注解,那么就会返回多个 * * 如果@Qualifier指定的value在spring容器中没有,这里返回的map集合就是空 * */ Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { // 如果匹配到的要注入的bean是null,就报错 raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; if (matchingBeans.size() > 1) { /** * 如果根据类型,匹配到有多个bean,那就判断@Primary注解和@Priority注解; * 所以:可以得出一个结论: * 当一个接口有多个实现类的时候,添加了@Qualifier注解,同时在一个类上添加了@Primary注解,那么会注入@Qualifier注解对应的bean * * 在下面的这个推断方法中: * 1.会先判断@Primary注解 * 2.再判断@Priority注解声明的优先级 * 3.如果两个注解都没有,那就根据controller中注入的service的name和matchingBeans中的beanName进行匹配 * 如果匹配上,就注入匹配上的beanName对应的beanClass * 这里需要注意的是:根据name查询的时候,会先根据type从beanDefinitionMap中查询到符合类型的beanDefinitionNames * 然后从beanDefinitionNames中依次匹配,是否和name一致 */ autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(type, matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } /** * 如果能找到一个,那就根据name获取到对应的instance实例,然后再field.set(); */ instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { /** * 根据获取到的beanName和type从容器中查找。如果没有找到,就创建 * 这里才是真正的从单实例池中获取对象,如果对象没有,就创建 */ instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); }在注释中,详细注释了哪行代码解析了哪个注解,我想着重看下 determineAutowireCandidate这个方法 /** * 如果根据type获取到有多个符合的bean,那就来这个方法中,推断出其中的一个 * @param candidates:推断出来的多个bean * @param descriptor:要注入的属性对应的类型,如果是接口,那这里就是接口的类型 * @return */ @Nullable protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) { Class requiredType = descriptor.getDependencyType(); /** * 判断哪个bean有@Primary注解,返回注解对应的beanName */ String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); if (primaryCandidate != null) { return primaryCandidate; } /** * 如果都没有添加@Primary注解,那就判断bean是否有添加@Priority注解,注解值越小,优先级越高;返回优先级高的beanName */ String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (priorityCandidate != null) { return priorityCandidate; } // Fallback /** * 这里的descriptor中保存的是注入的bean对应的名称(在controller注入service,这里就是controller中的service属性名) * 判断 从容器中拿出来的beanName是否和controller中的service属性名一致,如果一致,就注入一致的这个 * 这也就是在controller注入service的时候,如果service有多个实现类,那么,如果注入的service属性名和实现类的beanName一致,也可以注入成功的原因 * * class Controller{ * @Autowired * Service service01 * } * 如果service有多个实现类,其实注入的是service01,就是这里判断的 * * 这里我觉得,也是我们平常所说的,如果根据type找到多个,或者没有找到,就根据name来注入,这里就是根据name来注入的这一步 * candidates:是根据类型从beanDefinitionMap中获取到的符合类型的beanDefinitionNames * descriptor.getDependencyName():是@Autowired注解属性注入的属性name */ for (Map.Entry entry : candidates.entrySet()) { String candidateName = entry.getKey(); Object beanInstance = entry.getValue(); if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } } return null; }通过这两段代码,我觉得可以说明一个问题: 对于@Autowired注解,spring在处理的时候:会先解析@Qualifer注解,然后解析@Primary注解,然后再解析@Priority注解如果解析之后,匹配的bean还是有多个,那就根据name来查找,需要注意的是这里的查找都是基于从beanDefinitionMap中找到的符合注入条件的bean;只有在确认要注入的是哪个实现类之后,才会从单实例池中获取实例化之后的bean这里有一个点再补充一下,我前面一直在说的这个点:所有的查找都是基于从beanDefinitionMap中查找到符合注入条件的bean:下面这段代码可以证实这个观点: 这里的代码,我就不再追进去了,因为这里的底层,可以看到是遍历beanDefinitionNames这个集合,依次根据beanDefinitionName获取到beanDefinition,然后判断beanDefinition是否是非抽象类,是否是非懒加载的、是否是单实例的,是否是type类型的等等,如果满足,就把当前beanName返回 @Resource
所以:对于@Resource注解,就是根据在bean中设置的name,从单实例池中查找,如果找到就注入,没找到,就是null 总结@Resource注解没什么可说的,就是根据name从单实例池中,获取能匹配上的beanDefinition 对于@Autowired注解 首先会根据type,从beanDefinitionMap中获取到所有符合该类型的beanDefinition对应的beanName然后判断对应的@Qualifier注解,优先注入该注解指定的bean,如果在该注解指定了bean,但是没有找到,那就返回null如果没有添加@Qualifer注解,但是找到了多个实现类,那就判断是否有添加@Primary注解,优先注入添加了该注解的bean;如果多个类添加了该注解,spring会报错,因为spring也不知道要注入哪个如果没有添加@Primary注解,就处理@Priority注解,该注解是声明优先级的,值越小,优先级越高如果这三个注解都没有添加,那就根据name,判断从beanDefinitionMap中查找的符合注入类型的所有beanName中,是否有和field对应的name一样的,有,就注入该bean,没有就根据@Autowired注解的required是true还是false,来决定是抛出异常还是返回null如果找到、确定了注入的bean,就会从单实例池中获取beanName对应的完成实例化的bean对象,然后注入最后一点,需要说明的是:@Autowired注解和@Resource注解都是通过field.set()完成属性填充的 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |