Spring?中@Autowired、@Resource、@Inject?注解實現(xiàn)原理使用案例詳解
使用案例
前置條件: 現(xiàn)在有一個 Vehicle
接口,它有兩個實現(xiàn)類 Bus
和 Car
,現(xiàn)在還有一個類 VehicleService
需要注入一個 Vehicle
類型的 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") //假設(shè)這里是想要注入Bean名稱為car的這個Bean private Vehicle vehicle; }
使用 @Inject
注解注入 Bean:
@Inject
注解可以和 @Qualifier
或者 @Named
注解一起使用,在有多個符合條件的 Bean 的情況下限制注入特定名稱的 Bean:
@Component public class VehicleService { @Inject @Qualifier("car") //假設(shè)這里是想要注入Bean名稱為car的這個Bean private Vehicle vehicle; @Inject @Named("bus") //假設(shè)這里是想要注入Bean名稱為bus的這個Bean private Vehicle anotherVehicle; }
使用 @Resource
注解注入 Bean:
@Component public class VehicleService { @Resource(name = "car") private Vehicle vehicle; }
雖然以上三種使用方法都能夠?qū)崿F(xiàn)注入 Bean 的需求,但是它們在底層實現(xiàn)上有什么區(qū)別呢?
注解體系
在 Java EE 和 Spring 體系中定義了幾套注解:
JSR 250:定義了 @PostConstruct
,@PreDestroy
,@Resource
注解,其中 @Resource
注解默認是按照名稱進行注入。
JSR 330:定義了 @Inject
,@Qualifier
, @Named
注解,其中 @Inject
注解默認是按照類型進行注入,可以搭配 @Qualifier
或者@Named
注解實現(xiàn)按照名稱注入。
Spring:定義了 @Autowired
,@Qualifier
注解,其中 @Autowired
注解默認是按照類型進行注入,可以搭配 @Qualifier
注解實現(xiàn)按照名稱注入。
當(dāng)前 JSR 250 定義的注解屬于 jakarta.annotation-api
,而 JSR 330 定義的注解屬于 jakarta.inject-api
。
實現(xiàn)原理
InstantiationAwareBeanPostProcessor 方法調(diào)用觸發(fā)的位置:
Spring 中提供了 InstantiationAwareBeanPostProcessor
接口,它有一個 postProcessProperties()
負責(zé)實現(xiàn)對 Bean 的屬性進行處理。
Spring 中提供了實現(xiàn)類 CommonAnnotationBeanPostProcessor
負責(zé)處理 @Resource
注解;提供了實現(xiàn)類 AutowiredAnnotationBeanPostProcessor
負責(zé)處理 @Autowired
注解和 @Inject
注解。
InstantiationAwareBeanPostProcessor
的 postProcessProperties()
方法是在 AbstractAutowireCapableBeanFactory
中的 doCreateBean()
創(chuàng)建 Bean 的方法中觸發(fā)調(diào)用的,在這個方法中的主要實現(xiàn)邏輯是實例化 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()
中實現(xiàn)了對 postProcessProperties()
方法的調(diào)用,在該方法實現(xiàn)對注解修飾的需要注入的字段進行賦值,即自動注入。 代碼如下:
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接口的實現(xiàn)類 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { //調(diào)用postProcessProperties()方法 PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } pvs = pvsToUse; } } }
InstantiationAwareBeanPostProcessor 注冊的時機:
既然 InstantiationAwareBeanPostProcessor
是負責(zé)處理 Bean 的屬性的自動注入的,那么它一定是在業(yè)務(wù) Bean 創(chuàng)建之前就已經(jīng)完成初始化了,這樣在業(yè)務(wù) Bean 創(chuàng)建的時候才能調(diào)用它的實例方法。它的初始化是在 Spring 上下文的基類 AbstractApplicationContext
的 refresh()
方法中完成的。代碼如下:
public void refresh() throws BeansException, IllegalStateException { //省略其它代碼 //這里注冊了InstantiationAwareBeanPostProcessor registerBeanPostProcessors(beanFactory); //省略其它代碼 //這里創(chuàng)建所有的單例Bean finishBeanFactoryInitialization(beanFactory); finishRefresh(); }
而在 registerBeanPostProcessors()
方法中又調(diào)用了 PostProcessorRegistrationDelegate
的 registerBeanPostProcessors()
方法來完成注冊的。代碼如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }
在PostProcessorRegistrationDelegate
的 registerBeanPostProcessors()
方法真正實現(xiàn)注冊邏輯。代碼如下:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { //這里獲取到所有實現(xiàn)了BeanPostProcessor接口的Bean名稱 //InstantiationAwareBeanPostProcessor接口繼承了BeanPostProcessor接口 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); //遍歷Bean名稱調(diào)用BeanFactory.getBean()方法觸發(fā)BeanPostProcessor Bean的創(chuàng)建 //然后根據(jù)是否實現(xiàn)了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)) { //這里調(diào)用BeanFactory.getBean()方法觸發(fā)BeanPostProcessor Bean的創(chuàng)建 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); } } //首先注冊實現(xiàn)了PriorityOrdered接口的BeanPostProcessor sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); //然后觸發(fā)實現(xiàn)了Ordered接口的BeanPostProcessor Bean的創(chuàng)建并注冊 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); //最后觸發(fā)其它BeanPostProcessor Bean的創(chuàng)建并注冊 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(beanFactory, internalPostProcessors); }
CommonAnnotationBeanPostProcessor 實現(xiàn)邏輯(以修飾字段為例)
首先在 CommonAnnotationBeanPostProcessor
的靜態(tài)初始化塊中初始化了它要處理的注解。代碼如下:
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()
方法中主要實現(xiàn)邏輯為找到 @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()
方法中實現(xiàn)的,在該方法中又調(diào)用了 buildResourceMetadata()
來進行實際的查找,在這個方法中通過反射的方式遍歷字段看它是否有 @Resource
注解修飾,如果是的話把它包裝為一個 ResourceElement
對象放到列表中。最后基于列表構(gòu)造一個 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); } //這里調(diào)用buildResourceMetadata()方法 metadata = buildResourceMetadata(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); }
實際觸發(fā)賦值的操作是在 InjectionMetadata
的 inject()
方法中實現(xiàn)的,在它的方法中又會循環(huán)調(diào)用 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); //這里通過反射的方式設(shè)置值,設(shè)置的值就是根據(jù)Bean名稱獲取到的Bean field.set(target, getResourceToInject(target, requestingBeanName)); } else { //省略其它代碼 } }
在 ResourceElement
的 getResourceToInject()
方法中實現(xiàn)了查找邏輯:如果 BeanFactory
中包含這個 Bean 名稱對應(yīng)的 Bean 則直接根據(jù)名稱查找,否則會根據(jù)類型進行匹配,這個就是常說的 @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) { //如果根據(jù)Bean名稱找不到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 { //如果根據(jù)名稱找得到Bean則直接根據(jù)名稱獲取Bean resource = autowireCapableBeanFactory.resolveBeanByName(name, element.getDependencyDescriptor()); autowiredBeanNames = Collections.singleton(name); } } else { //省略代碼 } //省略代碼 return resource; }
按照類型匹配的邏輯是在 DefaultListableBeanFactory
的 doResolveDependency()
方法中實現(xiàn)的,在該方法中會根據(jù)類型找到所有是當(dāng)前類型的 Bean,然后構(gòu)造一個 Map,key 是 Bean 的名稱,value 是對應(yīng)的 Bean 對象,如果找到的 Bean 個數(shù)大于 1 則會選擇一個最符合條件的返回(選擇的依據(jù)后面會講到),如果等于 1 則直接返回這個 Bean。代碼如下:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { //省略代碼 //這里根據(jù)類型找到所有的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; //如果根據(jù)類型找到多個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 實現(xiàn)邏輯(以修飾字段為例)
首先在構(gòu)造函數(shù)中初始化了需要處理的注解包括 @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()
方法中主要實現(xiàn)邏輯為找到 @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()
方法中實現(xiàn)的,在該方法中又調(diào)用了 buildAutowiringMetadata()
來進行實際的查找,在這個方法中通過反射的方式遍歷字段看它是否有 @Autowired
或者 @Inject
注解修飾,如果是的話把它包裝為一個AutowiredFieldElement
對象放到列表中。最后基于列表構(gòu)造一個 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)); } }); } }
實際觸發(fā)賦值的操作是在 InjectionMetadata
的 inject()
方法中實現(xiàn)的,在它的方法中又會循環(huán)調(diào)用 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 { //找到對應(yīng)的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 { //調(diào)用beanFactory的resolveDependency()方法 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } return value; }
然后會調(diào)用到 DefaultListableBeanFactory
的 doResolveDependency()
方法,和上面 @Resource
注解根據(jù)名稱找不到 Bean 需要根據(jù)類型進行匹配的調(diào)用的是一個方法,只是它會多一個分支。在這個分支里面判斷 Bean 名稱對應(yīng)的 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注解會先走到下面這個分支 //在這個分支里面也會先判斷對應(yīng)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); } } } //這里根據(jù)類型找到所有的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; //如果根據(jù)類型找到多個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); } }
當(dāng)有多個類型匹配的 Bean 選擇返回一個 Bean 的原則
當(dāng)根據(jù)類型找到多個 Bean 時需要根據(jù)一些規(guī)則返回一個Bean。常見的可以通過 @Qualifer
限定名稱或者通過 @Primary
來表示優(yōu)先注入。在DefaultListableBeanFactor
的 determineAutowireCandidate()
方法中就實現(xiàn)了這些邏輯:
首先遍歷找到的所有符合類型的 Bean,然后看是否有 @Primary
注解修飾,如果有的話,則優(yōu)先返回有該 Bean;
否則再次嘗試根據(jù)字段的名稱匹配看是否有匹配的 Bean,如果有則返回;
否則嘗試獲取 @Qualifier
注解定義的名稱(對于 @Named
注解來說它本身上面也有 @Qualifer
注解修飾),然后看是否有名稱匹配的 Bean,如果有則返回;
否則遍歷 Bean 看是否有 @Priority
注解修飾,如果有則找最高優(yōu)先級的 Bean 返回,值越小優(yōu)先級越高;
否則看 resolvableDependencies
是否有注冊對應(yīng)的實例,如果有則返回,它的使用場景一般是有用戶自己的 new 的對象可以注冊到這里面,然后在一個 Spring 管理的 Bean 中可以把它注入進來。代碼如下:
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<?> requiredType = descriptor.getDependencyType(); //首先處理@Primary注解,如果某個Bean有@Primary注解修飾則優(yōu)先返回它 String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); if (primaryCandidate != null) { return primaryCandidate; } //否則再次根據(jù)字段的名稱進行匹配,看找到的Bean里面有沒有和字段名稱相同的Bean,有的話則優(yōu)先返回 String dependencyName = descriptor.getDependencyName(); if (dependencyName != null) { for (String beanName : candidates.keySet()) { if (matchesBeanName(beanName, dependencyName)) { return beanName; } } } //否則嘗試獲取@Qualifier注解定義的名稱,看找打的Bean里面有沒有和該名稱相同的Bean,有的話則優(yōu)先返回 String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor); if (suggestedName != null) { for (String beanName : candidates.keySet()) { if (matchesBeanName(beanName, suggestedName)) { return beanName; } } } //否則看找到的Bean是否有@Priority注解修飾,有的話取優(yōu)先級最高的返回即值最小的 String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (priorityCandidate != null) { return priorityCandidate; } //否則自定義注冊的非Spring管理生命周期的對象中是否有匹配,resolvableDependencies里面可以放 //一些對象,這些對象不是由Spring創(chuàng)建的而是用戶自己創(chuàng)建放入的且需要在一個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 ""; }
到此這篇關(guān)于Spring 中@Autowired,@Resource,@Inject 注解實現(xiàn)原理的文章就介紹到這了,更多相關(guān)Spring 中@Autowired,@Resource,@Inject 注解實現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?中@Autowired、@Resource、@Inject?注解實現(xiàn)原理使用案例詳解
- Spring中@Autowired @Resource @Inject三個注解有什么區(qū)別
- 詳解Spring依賴注入:@Autowired,@Resource和@Inject區(qū)別與實現(xiàn)原理
- SpringBoot注解篇之@Resource與@Autowired的使用區(qū)別
- Spring注解@Autowired和@Resource的區(qū)別詳解
- 一文搞懂Spring中@Autowired和@Resource的區(qū)別
- Spring注解@Resource和@Autowired區(qū)別對比詳解
相關(guān)文章
以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼
這篇文章主要介紹了以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01java8 集合 多字段 分組 統(tǒng)計個數(shù)代碼
這篇文章主要介紹了java8 集合 多字段 分組 統(tǒng)計個數(shù)代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08IDEA導(dǎo)入Springboot項目,注解和pom文件不識別的解決
這篇文章主要介紹了IDEA導(dǎo)入Springboot項目,注解和pom文件不識別的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04SpringMVC?HttpMessageConverter報文信息轉(zhuǎn)換器
這篇文章主要為大家介紹了SpringMVC?HttpMessageConverter報文信息轉(zhuǎn)換器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05Java Agent 動態(tài)修改字節(jié)碼詳情
這篇文章主要介紹了Java Agent動態(tài)修改字節(jié)碼的相關(guān)資料,需要的朋友可以參考下面文章具體的內(nèi)容2021-09-09