使用案例
前置條件: 現在有一個 Vehicle
接口,它有兩個實現類 Bus
和 Car
,現在還有一個類 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") //假設這里是想要注入Bean名稱為car的這個Beanprivate Vehicle vehicle;
}
使用 @Inject
注解注入 Bean:
@Inject
注解可以和 @Qualifier
或者 @Named
注解一起使用,在有多個符合條件的 Bean 的情況下限制注入特定名稱的 Bean:
@Component
public class VehicleService {@Inject@Qualifier("car") //假設這里是想要注入Bean名稱為car的這個Beanprivate Vehicle vehicle;@Inject@Named("bus") //假設這里是想要注入Bean名稱為bus的這個Beanprivate 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);//初始化BeanexposedObject = 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 {//省略其它代碼//這里注冊了InstantiationAwareBeanPostProcessorregisterBeanPostProcessors(beanFactory);//省略其它代碼//這里創建所有的單例BeanfinishBeanFactoryInitialization(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接口的BeanPostProcessorsortPostProcessors(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(beanFactory, 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 = 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);
}
實際觸發賦值的操作是在 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名稱獲取到的Beanfield.set(target, getResourceToInject(target, requestingBeanName));} else {//省略其它代碼}
}
在 ResourceElement
的 getResourceToInject()
方法中實現了查找邏輯:如果 BeanFactory
中包含這個 Bean 名稱對應的 Bean 則直接根據名稱查找,否則會根據類型進行匹配,這個就是常說的 @Resource
注解默認是按照名稱進行匹配的,名稱匹配不到的情況下再按照類型進行匹配。代碼如下:
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)throws NoSuchBeanDefinitionException {//省略代碼// Regular resource autowiringif (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) {//如果根據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 { //如果根據名稱找得到Bean則直接根據名稱獲取Beanresource = 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 Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {//省略代碼//這里根據類型找到所有的Bean,然后Bean的名稱作為key,Bean作為ValueMap<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {// Step 4c (fallback): custom Collection / Map declarations for collecting multiple beansmultipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// Raise exception if nothing found for required injection pointif (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 pointreturn 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則直接返回這個BeanMap.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}// Step 6: validate single resultif (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 {//找到對應的Beanvalue = 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 nameif (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作為ValueMap<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {// Step 4c (fallback): custom Collection / Map declarations for collecting multiple beansmultipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// Raise exception if nothing found for required injection pointif (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 pointreturn 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則直接返回這個BeanMap.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}// Step 6: validate single resultif (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 "";
}