欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?中@Autowired、@Resource、@Inject?注解實現(xiàn)原理使用案例詳解

 更新時間:2025年04月25日 08:49:06   作者:javadaydayup  
這篇文章主要介紹了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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼

    以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼

    這篇文章主要介紹了以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • java8 集合 多字段 分組 統(tǒng)計個數(shù)代碼

    java8 集合 多字段 分組 統(tǒng)計個數(shù)代碼

    這篇文章主要介紹了java8 集合 多字段 分組 統(tǒng)計個數(shù)代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • JAVA比較兩張圖片相似度的方法

    JAVA比較兩張圖片相似度的方法

    這篇文章主要介紹了JAVA比較兩張圖片相似度的方法,涉及java針對圖片像素操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • IDEA導(dǎo)入Springboot項目,注解和pom文件不識別的解決

    IDEA導(dǎo)入Springboot項目,注解和pom文件不識別的解決

    這篇文章主要介紹了IDEA導(dǎo)入Springboot項目,注解和pom文件不識別的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 深入了解MyBatis參數(shù)

    深入了解MyBatis參數(shù)

    今天小編就為大家分享一篇關(guān)于深入了解MyBatis參數(shù),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java實現(xiàn)LeetCode(報數(shù))

    Java實現(xiàn)LeetCode(報數(shù))

    這篇文章主要介紹了Java實現(xiàn)LeetCode(報數(shù)),本文通過使用java實現(xiàn)leetcode的報數(shù)題目和實現(xiàn)思路分析,需要的朋友可以參考下
    2021-06-06
  • ssm 使用token校驗登錄的實現(xiàn)

    ssm 使用token校驗登錄的實現(xiàn)

    這篇文章主要介紹了ssm 使用token校驗登錄的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • SpringMVC?HttpMessageConverter報文信息轉(zhuǎn)換器

    SpringMVC?HttpMessageConverter報文信息轉(zhuǎn)換器

    這篇文章主要為大家介紹了SpringMVC?HttpMessageConverter報文信息轉(zhuǎn)換器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Java實現(xiàn)八種排序算法詳細代碼舉例

    Java實現(xiàn)八種排序算法詳細代碼舉例

    排序問題一直是程序員工作與面試的重點,今天特意整理研究下與大家共勉!這篇文章主要介紹了Java實現(xiàn)八種排序算法的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-10-10
  • Java Agent 動態(tài)修改字節(jié)碼詳情

    Java Agent 動態(tài)修改字節(jié)碼詳情

    這篇文章主要介紹了Java Agent動態(tài)修改字節(jié)碼的相關(guān)資料,需要的朋友可以參考下面文章具體的內(nèi)容
    2021-09-09

最新評論