Spring 中@Autowired、@Resource、@Inject 注解实现原理使用案例详解
目录
- 使用案例
- 注解体系
- 实现原理
- InstantiationAwareBeanPostProcessor 方法调用触发的位置:
- InstantiationAwareBeanPostProcessor 注册的时机:
- CommonAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
- AutowiredAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
- 当有多个类型匹配的 Bean 选择返回一个 Bean 的原则
使用案例
前置条件: 现在有一个 Vehicle
接口,它有两个实现类 Bus
和 Car
,现在还有一个类 VehicleService
需要注入一个 Vehicle
类型的www.devze.com Bean:
public interface Vehicle {} @Component public class Car implements Vehicle {} @Component public class Bus implements Vehicle {}
使用 @Autowired
注解注入 Bean:
@Autowired
注解可以和 @Qualifier
注解一起使用,在有多个符合条件的 Bean 的情况下限制注入特定名称的 Bean:
@Component public class VehicleService { @Autowired @Qualifier("car") //假设这里是想要注入Bean名称为car的这个Bean private Vehicle vehicle; }
使用 @Inject
注解注入 Bean:
@Inject
注解可以和 @Qualifier
或者 @Named
注解一起使用,在有多个符合条件的 Bean 的情况下限制注入特定名称的 Bean:
@Component public class VehicleService { @Inject @Qualifier("car") //假设这里是想要注入Bean名称为car的这个Bean private Vehicle vehicle; @Inject @Named("bus") //假设这里是想要注入Bean名称为bus的这个Bean private Vehicle anotherVehicle; }
使用 @Resource
注解注入 Bean:
@Component public class VehicleService { @Resource(name = "car") private Vehicle vehicle; }
虽然以上三种使用方法都能够实现注入 Bean 的需求,但是它们在底层实现上有什么区别呢?
注解体系
在 Java EE 和 Spring 体系中定义了几套注解:
jsR 250:定义了 @PostConstruct
,@PreDestroy
,@Resource
注解,其中 @Resource
注解默认是按照名称进行注入。
JSR 330:定义了 @Inject
,@Qualifier
, @Named
注解,其中 @Inject
注解默认是按照类型进行注入,可以搭配 @Qualifier
或者@Named
注解实现按照名称注入。
Spring:定义了 @Autowired
,@Qualifier
注解,其中 @Autowired
注解默认是按照类型进行注入,可以搭配 @Qualifier
注解实现按照名称注入。
当前 JSR 250 定义的注解属于 jakarta.annotation-api
,而 JSR 330 定义的注解属于 jakarta.inject-api
。
实现原理
InstantiationAwareBeanPostProcessor 方法调用触发的位置:
Spring 中提供了 InstantiationAwareBeanPostProcessor
接口,它有一个 postProcessProperties()
负责实现对 Bean 的属性进行处理。
Spring 中提供了实现类 CommonAnnotationBeanPostProcessor
负责处理 @Resource
注解;提供了实现类 AutowiredAnnotationBeanPostProcessor
负责处理 @Autowired
注解和 @Inject
注解。
InstantiationAwareBeanPostProcessor
的 postProcessProperties()
方法是在 AbstractAutowireCapableBeanFactory
中的 doCreateBean()
创建 Bean 的方法中触发调用的,在这个方法中的主要实现逻辑是实例化 Bean -> 填充 Bean 属性 -> 初始化 Bean。 代码如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //实例化Bean对象 instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } Object exposedObject = bean; try { //填充Bean属性 populateBean(beanName, mbd, instanceWrapper); //初始化Bean exposedObject = initializeBean(beanName, exposedObject, mbd); } }
在填充 Bean 属性的方法 populateBean()
中实现了对 postProcessProperties()
方法的调用,在该方法实现对注解修饰的需要注入的字段进行赋值,即自动注入。 代码如下:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //省略部分代码 PropertyValues pvs = (mbd.hASPropertyValues() ? mbd.getPropertyValues() : null); if (hasInstantiationAwareBeanPostProcessors()) { if (pvs == null) { pvs = mbd.getPropertyValues(); } //这里获取所有InstantiationAwareBeanPostProcessor接口的实现类 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { //调用postProcessProperties()方法 PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } pvs = pvsToUse; } } }
InstantiationAwareBeanPostProcessor 注册的时机:
既然 InstantiationAwareBeanPostProcessor
是负责处理 Bean 的属性的自动注入的,那么它一定是在业务 Bean 创建之前就已经完成初始化了,这样在业务 Bean 创建的时候才能调用它的实例方法。它的初始化是在 Spring 上下文的基类 AbstractApplicationContext
的 refresh()
方法中完成的。代码如下:
public void refresh() throws BeansException, IllegalStateException { //省略其它代码 //这里注册了InstantiationAwareBeanPostProcessor registerBeanPostProcessors(beanFactory); //省略其它代码 //这里创建所有的单例Bean finishBeanFactoryInitialization(beanFactory); finishRefresh(); }
而在 registerBeanPostProcessors()
方法中又调用了 PostProcessorRegistrationDelegate
的 registerBeanPostProcessors()
方法来完成注册的。代码如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }
在PostProcessorRegistrationDelegate
的 registerBeanPostProcessors()
方法真正实现注册逻辑。代码如下:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { //这里获取到所有实现了BeanPostProcessor接口的Bean名称 //InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor接口 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); //遍历Bean名称调用BeanFactory.getBean()方法触发BeanPostProcessor Bean的创建 //然后根据是否实现了PriorityOrdered接口、Ordered接口和其它分为三大类 //分别将这三大类的BeanPostProcessor实例进行注册 List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //这里调用BeanFactory.getBean()方法触发BeanPostProcessor Bean的创建 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } //首先注册实现了PriorityOrdered接口的BeanPostProcessor sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); //然后触发实现了Ordered接口的BeanPostProcessor Bean的创建并注册 List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); //最后触发其它BeanPostProcessor Bean的创建并注册 List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactophpry, internalPostProcessors); }
CommonAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
首先在 CommonAnnotationBeanPostProcessor
的静态初始化块中初始化了它要处理的注解。代码如下:
static { //这里是为了适配不同版本@Resource注解在不同的包路径下 jakartaResourceType = loadAnnotationType("jakarta.annotation.Resource"); if (jakartaResourceType != null) { resourceAnnotationTypes.add(jakartaResourceType); } //这里是为了适配不同版本@Resource注解在不同的包路径下 javaxResourceType = loadAnnotationType("javax.annotation.Resource"); if (javaxResourceType != null) { resourceAnnotationTypes.add(javaxResourceType); } }
在它的 postProcessProperties()
方法中主要实现逻辑为找到 @Resource
注解修饰的字段 -> 通过反射给字段赋值。代码如下:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { //找@Resource注解修饰的字段 InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); try { //给字段赋值 metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex); } return pvs; }
找 @Resource
注解修饰的字段是在 findResourceMetadata()
方法中实现的,在该方法中又调用了 buildResourceMetadata()
来进行实际的查找,在这个方法中通过反射的方式遍历字段看它是否有 @Resource
注解修饰,如果是的话把它包装为一个 ResourceElement
对象放到列表中。最后基于列表构造一个 InjectionMetadata
对象返回。代码如下:
private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } //这里调用buildResourceMetadata()方法 metadata = buildReso编程urceMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; } private InjectionMetadata buildResourceMetadata(Class<?> clazz) { List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; //省略部分代码 do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); //这里就会遍历每个字段看字段是否有@Resource注解修饰有的话就加入到列表中 ReflectionUtils.doWithLocalFields(targetClass, field -> { //省略部分代码 if (jakartaResourceType != null && field.isAnnotationPresent(jakartaResourceType)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static fields"); } if (!this.ignoredResourceTypes.contains(field.getType().getName())) { currElements.add(new ResourceElement(field, field, null)); } } else if (javaxResourceType != null && field.isAnnotationPresent(javaxResourceType)) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalStateException("@Resource annotation is not supported on static fields"); } if (!this.ignoredResourceTypes.contains(field.getType().getName())) { currElements.add(new LegacyResourceElement(field, field, null)); } } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return InjectionMetadata.forElements(elements, clazz); }
实际触发赋值的操作是在 InjectionMetadata
的 inject()
方法中实现的,在它的方法中又会循环调用 InjectedElement
的 inject()
方法。代码如下:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { element.inject(target, beanName, pvs); } } }
在 InjectedElement
的 inject()
方法中通过反射的方式将找到的 Bean 赋值给字段。代码如下:
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { if (!shouldInject(pvs)) { return; } if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); //这里通过反射的方式设置值,设置的值就是根据Bean名称获取到的Bean field.set(target, getResourceToInject(target, requestingBeanName)); } else { //省略其它代码 } }
在 ResourceElement
的 getResourceToInject()
方法中实现了查找逻辑:如果 BeanFactory
中包含这个 Bean 名称对应的 Bean 则直接根据名称查找,否则会根据类型进行匹配,这个就是常说的 @Resource
注解默认是按照名称进行匹配的,名称匹配不到的情况下再按照类型进行匹配。代码如下:
protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { //省略代码 // Regular resource autowiring if (this.resourceFactory == null) { throw new NoSuchBeanDefinitionException(element.lookupType, "No resource factory configured - specify the 'resourceFactory' property"); } return autowireResource(this.resourceFactory, element, requestingBeanName); } protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { Object resource; Set<String> autowiredBeanNames; String name = element.name; if (factory instanceof AutowireCapableBeanFactory autowireCapableBeanFactory) { //如果根据www.devze.comBean名称找不到Bean且允许按照类型匹配的情况下走第一个分支 if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { autowiredBeanNames = new LinkedHashSet<>(); resource = autowireCapableBeanFactory.resolveDependency( element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null); if (resource == null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); } } else { //如果根据名称找得到Bean则直接根据名称获取Bean resource = autowireCapableBeanFactory.resolveBeanByName(name, element.getDependencyDescriptor()); autowiredBeanNames = Collections.singleton(name); } } else { //省略代码 } //省略代码 return resource; }
按照类型匹配的逻辑是在 DefaultListableBeanFactory
的 doResolveDependency()
方法中实现的,在该方法中会根据类型找到所有是当前类型的 Bean,然后构造一个 Map,key 是 Bean 的名称,value 是对应的 Bean 对象,如果找到的 Bean 个数大于 1 则会选择一个最符合条件的返回(选择的依据后面会讲到),如果等于 1 则直接返回这个 Bean。代码如下:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Sethttp://www.devze.com<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { //省略代码 //这里根据类型找到所有的Bean,然后Bean的名称作为key,Bean作为Value Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // Raise exception if nothing found for required injection point if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //如果根据类型找到多个Bean则需要选择一个合适的Bean返回 if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) { // Raise exception if no clear match found for required injection point return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { //如果只有一个Bean则直接返回这个Bean Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } // Step 6: validate single result if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName); } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
AutowiredAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
首先在构造函数中初始化了需要处理的注解包括 @Autowired
和 @Inject
注解。代码如下:
public AutowiredAnnotationBeanPostProcessor() { //添加要处理@Autowired注解 this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); ClassLoader classLoader = AutowiredAnnotationBeanPostProcessor.class.getClassLoader(); try { //这里是为了适配不同版本@Inject注解在不同的包路径下 this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("jakarta.inject.Inject", classLoader)); } catch (ClassNotFoundException ex) { // jakarta.inject API not available - simply skip. } try { //这里是为了适配不同版本@Inject注解在不同的包路径下 this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", classLoader)); } catch (ClassNotFoundException ex) { // javax.inject API not available - simply skip. } }
在它的 postProcessProperties()
方法中主要实现逻辑为找到 @Autowired
或者 @Inject
注解修饰的字段 -> 通过反射给字段赋值。代码如下:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; }
找@Autowired
或者 @Inject
注解修饰的字段是在 findAutowiringMetadata()
方法中实现的,在该方法中又调用了 buildAutowiringMetadata()
来进行实际的查找,在这个方法中通过反射的方式遍历字段看它是否有 @Autowired
或者 @Inject
注解修饰,如果是的话把它包装为一个AutowiredFieldElement
对象放到列表中。最后基于列表构造一个 InjectionMetadata
对象返回。代码如下:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; } private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) { if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } final List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<InjectionMetadata.InjectedElement> fieldElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> { //这里找到是否有@Autowired或者@Inject注解修饰 MergedAnnotation<?> ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { return; } boolean required = determineRequiredStatus(ann); fieldElements.add(new AutowiredFieldElement(field, required)); } }); } }
实际触发赋值的操作是在 InjectionMetadata
的 inject()
方法中实现的,在它的方法中又会循环调用 AutowiredFieldElement
的 inject()
方法。代码如下:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { element.inject(target, beanName, pvs); } } }
在 InjectedElement
的 inject()
方法中通过反射的方式将找到的 Bean 赋值给字段。代码如下:
@Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member; Object value; if (this.cached) { //省略代码 } else { //找到对应的Bean value = resolveFieldValue(field, bean, beanName); } if (value != null) { ReflectionUtils.makeAccessible(field); //通过反射的方式赋值 field.set(bean, value); } } @Nullable private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<>(2); TypeConverter typeConverter = beanFactory.getTypeConverter(); Object value; try { //调用beanFactory的resolveDependency()方法 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } return value; }
然后会调用到 DefaultListableBeanFactory
的 doResolveDependency()
方法,和上面 @Resource
注解根据名称找不到 Bean 需要根据类型进行匹配的调用的是一个方法,只是它会多一个分支。在这个分支里面判断 Bean 名称对应的 Bean 是否存在,如果存在则直接返回,如果不存在才会按照类型去匹配,这里实际上还是先按照名称匹配的,名称匹配不上再走的类型匹配的逻辑。代码如下:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { //省略代码 //如果是@Autowired注解或者@Inject注解会先走到下面这个分支 //在这个分支里面也会先判断对应Bean名称的Bean是否存在,如果存在 //则直接获取返回,如果不存在才会按照类型去匹配 if (descriptor.usesStandardBeanLookup()) { String dependencyName = descriptor.getDependencyName(); if (dependencyName == null || !containsBean(dependencyName)) { String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor); dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null); } if (dependencyName != null) { dependencyName = canonicalName(dependencyName); // dependency name can be alias of target name if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) && !isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type) && !isSelfReference(beanName, dependencyName)) { if (autowiredBeanNames != null) { autowiredBeanNames.add(dependencyName); } Object dependencyBean = getBean(dependencyName); return resolveInstance(dependencyBean, descriptor, type, dependencyName); } } } //这里根据类型找到所有的Bean,然后Bean的名称作为key,Bean作为Value Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // Raise exception if nothing found for required injection point if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; //如果根据类型找到多个Bean则需要选择一个合适的Bean返回 if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) { // Raise exception if no clear match found for required injection point return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { //如果只有一个Bean则直接返回这个Bean Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } // Step 6: validate single result if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName); } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
当有多个类型匹配的 Bean 选择返回一个 Bean 的原则
当根据类型找到多个 Bean 时需要根据一些规则返回一个Bean。常见的可以通过 @Qualifer
限定名称或者通过 @Primary
来表示优先注入。在DefaultListableBeanFactor
的 determineAutowireCandidate()
方法中就实现了这些逻辑:
首先遍历找到的所有符合类型的 Bean,然后看是否有 @Primary
注解修饰,如果有的话,则优先返回有该 Bean;
否则再次尝试根据字段的名称匹配看是否有匹配的 Bean,如果有则返回;
否则尝试获取 @Qualifier
注解定义的名称(对于 @Named
注解来说它本身上面也有 @Qualifer
注解修饰),然后看是否有名称匹配的 Bean,如果有则返回;
否则遍历 Bean 看是否有 @Priority
注解修饰,如果有则找最高优先级的 Bean 返回,值越小优先级越高;
否则看 resolvableDependencies
是否有注册对应的实例,如果有则返回,它的使用场景一般是有用户自己的 new 的对象可以注册到这里面,然后在一个 Spring 管理的 Bean 中可以把它注入进来。代码如下:
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<?> requiredType = descriptor.getDependencyType(); //首先处理@Primary注解,如果某个Bean有@Primary注解修饰则优先返回它 String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); if (primaryCandidate != null) { return primaryCandidate; } //否则再次根据字段的名称进行匹配,看找到的Bean里面有没有和字段名称相同的Bean,有的话则优先返回 String dependencyName = descriptor.getDependencyName(); if (dependencyName != null) { for (String beanName : candidates.keySet()) { if (matchesBeanName(beanName, dependencyName)) { return beanName; } } } //否则尝试获取@Qualifier注解定义的名称,看找打的Bean里面有没有和该名称相同的Bean,有的话则优先返回 String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor); if (suggestedName != null) { for (String beanName : candidates.keySet()) { if (matchesBeanName(beanName, suggestedName)) { return beanName; } } } //否则看找到的Bean是否有@Priority注解修饰,有的话取优先级最高的返回即值最小的 String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (priorityCandidate != null) { return priorityCandidate; } //否则自定义注册的非Spring管理生命周期的对象中是否有匹配,resolvableDependencies里面可以放 //一些对象,这些对象不是由Spring创建的而是用户自己创建放入的且需要在一个Spring的Bean中注入它 for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateName = entry.getKey(); Object beanInstance = entry.getValue(); if (beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) { return candidateName; } } return null; }
@Named
注解定义中使用了 @Qualifer
注解修饰。代码如下:
@Qualifier // 这里使用了@Qualifer注解修饰 @Documented @Retention(RUNTIME) public @interface Named { String value() default ""; }
到此这篇关于Spring 中@Autowired,@Resource,@Inject 注解实现原理的文章就介绍到这了,更多相关Spring 中@Autowired,@Resource,@Inject 注解实现原理内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论