自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

@Autowired 到底是怎么把變量注入進(jìn)來的?

開發(fā) 前端
isCandidateClass 方法實際上就是判斷當(dāng)前類在類、屬性、方法等層面上是否存在上述三個注解,如果存在,則就是候選類,否則就不是候選類。如果不是候選類則返回一個空的 InjectionMetadata 對象,否則就繼續(xù)后面的流程。

在 Spring 容器中,當(dāng)我們想給某一個屬性注入值的時候,有多種不同的方式,例如可以通過構(gòu)造器注入、可以通過 set 方法注入,也可以使用 @Autowired、@Inject、@Resource 等注解注入。

今天松哥就來和小伙伴們聊一聊,@Autowired 到底是如何把數(shù)據(jù)注入進(jìn)來的。

@Service
public class AService {
    @Autowired
    BService bService;
}

1. Bean 的創(chuàng)建

這個問題我們就得從 Bean 的創(chuàng)建開始了,本文主要是和小伙伴們聊 @Autowired,所以 Bean 的創(chuàng)建我就不從第一步開始了,咱們直接來看關(guān)鍵的方法,那就是 AbstractAutowireCapableBeanFactory#doCreateBean 方法:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException {
    //....
 Object exposedObject = bean;
 try {
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
 //...
 return exposedObject;
}

在這個方法中,首先會創(chuàng)建原始的 Bean 對象,創(chuàng)建出來之后,會調(diào)用一個 populateBean 方法,這個方法就是給 Bean 的各個屬性賦值的方法,標(biāo)注了 @Autowired 注解的屬性被自動賦值也是在這個方法中完成的。

2. populateBean

populateBean 方法內(nèi)容比較多,我們來看一些關(guān)鍵的地方:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
 // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
 // state of the bean before properties are set. This can be used, for example,
 // to support styles of field injection.
 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
   if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    return;
   }
  }
 }
 //...
 if (hasInstantiationAwareBeanPostProcessors()) {
  if (pvs == null) {
   pvs = mbd.getPropertyValues();
  }
  for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
   PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
   if (pvsToUse == null) {
    return;
   }
   pvs = pvsToUse;
  }
 }
 boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
 if (needsDepCheck) {
  PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
  checkDependencies(beanName, mbd, filteredPds, pvs);
 }
 if (pvs != null) {
  applyPropertyValues(beanName, mbd, bw, pvs);
 }
}

這里松哥貼出來的是部分關(guān)鍵代碼。

首先來看上面有一個 if,這個 if 主要是判斷是否需要后置處理器進(jìn)行處理,如果不需要,那么就直接 return 掉了,默認(rèn)情況下,這里并不會 return 掉,而是會繼續(xù)走后面的流程,因為 postProcessAfterInstantiation 方法默認(rèn)返回 true。

接下來第二個 if 就是比較關(guān)鍵的一個地方了,在這里會遍歷所有相關(guān)的后置處理器,嘗試通過這些處理器去獲取到需要的 value。

負(fù)責(zé)處理 @Autowired 注解的后置處理器是 AutowiredAnnotationBeanPostProcessor,所以現(xiàn)在,我們就來到 AutowiredAnnotationBeanPostProcessor#postProcessProperties 方法了。

3. postProcessProperties

@Override
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;
}

這個方法其實就兩步,第一步 findAutowiringMetadata,第二步 inject,就這兩件事。分別來看。

3.1 findAutowiringMetadata

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;
}

這個方法會先嘗試從緩存中獲取 metadata,如果能夠從緩存中獲取到,那就直接返回,緩存中沒有的話,那么最終會調(diào)用到 buildAutowiringMetadata 方法,去重新構(gòu)建 metadata,并將構(gòu)建結(jié)果存入到緩存中,以備下一次使用。

那么我們來看下 metadata 到底是如何構(gòu)建出來的。

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
 if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
  return InjectionMetadata.EMPTY;
 }
 List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
 Class<?> targetClass = clazz;
 do {
  final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
  ReflectionUtils.doWithLocalFields(targetClass, field -> {
   MergedAnnotation<?> ann = findAutowiredAnnotation(field);
   if (ann != null) {
    if (Modifier.isStatic(field.getModifiers())) {
     if (logger.isInfoEnabled()) {
      logger.info("Autowired annotation is not supported on static fields: " + field);
     }
     return;
    }
    boolean required = determineRequiredStatus(ann);
    currElements.add(new AutowiredFieldElement(field, required));
   }
  });
  ReflectionUtils.doWithLocalMethods(targetClass, method -> {
   Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
   if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    return;
   }
   MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
   if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    if (Modifier.isStatic(method.getModifiers())) {
     if (logger.isInfoEnabled()) {
      logger.info("Autowired annotation is not supported on static methods: " + method);
     }
     return;
    }
    if (method.getParameterCount() == 0) {
     if (logger.isInfoEnabled()) {
      logger.info("Autowired annotation should only be used on methods with parameters: " +
        method);
     }
    }
    boolean required = determineRequiredStatus(ann);
    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
    currElements.add(new AutowiredMethodElement(method, required, pd));
   }
  });
  elements.addAll(0, currElements);
  targetClass = targetClass.getSuperclass();
 }
 while (targetClass != null && targetClass != Object.class);
 return InjectionMetadata.forElements(elements, clazz);
}

這個方法比較長,我來和大家說一下核心邏輯。

首先會調(diào)用 isCandidateClass 方法判斷當(dāng)前類是否為一個候選類,判斷的依據(jù)就是 autowiredAnnotationTypes 變量的值,這個變量在該類的構(gòu)造方法中進(jìn)行了初始化,大家來看下這個構(gòu)造方法:

public AutowiredAnnotationBeanPostProcessor() {
 this.autowiredAnnotationTypes.add(Autowired.class);
 this.autowiredAnnotationTypes.add(Value.class);
 try {
  this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
    ClassUtils.forName("jakarta.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
  logger.trace("'jakarta.inject.Inject' annotation found and supported for autowiring");
 }
 catch (ClassNotFoundException ex) {
  // jakarta.inject API not available - simply skip.
 }
 try {
  this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
    ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
  logger.trace("'javax.inject.Inject' annotation found and supported for autowiring");
 }
 catch (ClassNotFoundException ex) {
  // javax.inject API not available - simply skip.
 }
}

小伙伴們看到,autowiredAnnotationTypes 集合中有兩個注解是固定的:@Autowired 和 @Value,另外就是如果項目引入了 JSR-330 依賴,則 @Inject 注解也會被加入進(jìn)來,以前 @Inject 存在于 javax 包中,現(xiàn)在最新版 @Inject 注解存在于 jakarta 包中,這里把兩種情況都列出來了。

所以,isCandidateClass 方法實際上就是判斷當(dāng)前類在類、屬性、方法等層面上是否存在上述三個注解,如果存在,則就是候選類,否則就不是候選類。如果不是候選類則返回一個空的 InjectionMetadata 對象,否則就繼續(xù)后面的流程。

后面的流程,首先是一個 do{}while() 結(jié)構(gòu),通過這個循環(huán)把當(dāng)前類以及當(dāng)前類的父類中的滿足條件的注解都找出來。具體的找法就是首先調(diào)用 ReflectionUtils.doWithLocalFields 方法,這個方法會遍歷當(dāng)前類的所有屬性,找到那些包含了 autowiredAnnotationTypes 中定義的注解的屬性,并將之封裝為 AutowiredFieldElement 對象,然后存入到集合中,接下來就是調(diào)用 ReflectionUtils.doWithLocalMethods,這個是找到當(dāng)前類中包含了上述三個注解的方法,然后把找到的滿足條件的方法封裝為 AutowiredMethodElement 然后存入到集合中。

另外大家需要注意,無論是 AutowiredFieldElement 還是 AutowiredMethodElement,都是 InjectionMetadata.InjectedElement 的子類。

這就是 findAutowiringMetadata 方法所做的事情,整體上來看,就是查找到添加了 @Autowired 或者 @Value 或者 @Inject 注解的屬性或者方法,并將之存入到集合中。

3.2 inject

接下來就該調(diào)用 metadata.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,然后挨個調(diào)用其 inject 方法進(jìn)行屬性注入。以本文一開始的 demo 為例,@Autowired 注解加在屬性上面,所以我們這里實際上調(diào)用的是 AutowiredFieldElement#inject 方法:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
 Field field = (Field) this.member;
 Object value;
 if (this.cached) {
  try {
   value = resolvedCachedArgument(beanName, this.cachedFieldValue);
  }
  catch (NoSuchBeanDefinitionException ex) {
   // Unexpected removal of target bean for cached argument -> re-resolve
   value = resolveFieldValue(field, bean, beanName);
  }
 }
 else {
  value = resolveFieldValue(field, bean, beanName);
 }
 if (value != null) {
  ReflectionUtils.makeAccessible(field);
  field.set(bean, value);
 }
}

這段代碼首先會調(diào)用 resolvedCachedArgument 方法嘗試從緩存中獲取想要的對象,如果緩存中存在,則可以直接使用,如果緩存中沒有,則調(diào)用 resolveFieldValue 方法去獲取。獲取到之后,通過反射調(diào)用 set 方法進(jìn)行賦值就可以了。所以關(guān)鍵步驟又來到了 resolveFieldValue 方法中。

用緩存的好處就是,獲取到對象存入到緩存之后,如果相同的 Bean 在多個類中注入,那么只有第一次需要去加載,以后就直接用緩存中的數(shù)據(jù)即可。

@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
 //...
 Object value;
 try {
  value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
 }
    //...
 return value;
}

這個方法的核心其實就是通過 beanFactory.resolveDependency 方法獲取到想要的 Bean 對象,我們直接來看這個核心方法,由于 BeanFactory 是一個接口,所以這個方法的實現(xiàn)實際上是在 DefaultListableBeanFactory#resolveDependency:

@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
 descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
 if (Optional.class == descriptor.getDependencyType()) {
  return createOptionalDependency(descriptor, requestingBeanName);
 }
 else if (ObjectFactory.class == descriptor.getDependencyType() ||
   ObjectProvider.class == descriptor.getDependencyType()) {
  return new DependencyObjectProvider(descriptor, requestingBeanName);
 }
 else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
  return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
 }
 else {
  Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
    descriptor, requestingBeanName);
  if (result == null) {
   result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  }
  return result;
 }
}

這里一共是四個分支,處理四種不同的情況,分別是 Optional、ObjectFactory、JSR-330 以及其他情況,很明顯,文章開頭的案例應(yīng)該屬于第四種情況,我們繼續(xù)來看 doResolveDependency 方法。

3.3 doResolveDependency

這個方法也是比較長,我列出來了一些關(guān)鍵的部分:

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
        //...
  Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
  if (multipleBeans != null) {
   return multipleBeans;
  }
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  if (matchingBeans.isEmpty()) {
   if (isRequired(descriptor)) {
    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
   }
   return null;
  }
  String autowiredBeanName;
  Object instanceCandidate;
  if (matchingBeans.size() > 1) {
   autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
   if (autowiredBeanName == null) {
    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
     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 {
   // We have exactly one match.
   Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
   autowiredBeanName = entry.getKey();
   instanceCandidate = entry.getValue();
  }
  Object result = instanceCandidate;
  return result;
 }
 finally {
  ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
 }
}

首先是調(diào)用 resolveMultipleBeans 方法去查找多個 Bean,這是因為我們在注入的時候,可以注入數(shù)組、集合和 Map,例如像下面這樣:

@Service
public class AService {
    @Autowired
    BService bService;
    @Autowired
    BService[] bServices;
    @Autowired
    List<BService> bServiceList;
    @Autowired
    Map<String, BService> bServiceMap;
}

具體查找方法如下:

@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
 Class<?> type = descriptor.getDependencyType();
 if (descriptor instanceof StreamDependencyDescriptor streamDependencyDescriptor) {
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  //...
  return stream;
 }
 else if (type.isArray()) {
  Class<?> componentType = type.getComponentType();
  ResolvableType resolvableType = descriptor.getResolvableType();
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
    new MultiElementDescriptor(descriptor));
  return result;
 }
 else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
  Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
    new MultiElementDescriptor(descriptor));
  return result;
 }
 else if (Map.class == type) {
  ResolvableType mapType = descriptor.getResolvableType().asMap();
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
    new MultiElementDescriptor(descriptor));
  return matchingBeans;
 }
 else {
  return null;
 }
}

這里會首先判斷你的數(shù)據(jù)類型,針對 Stream、數(shù)組、集合 以及 Map 分別處理,處理代碼都很好懂,以集合為例,首先獲取到集合中的泛型,然后調(diào)用 findAutowireCandidates 方法根據(jù)泛型去查找到 Bean,處理一下返回就行了,其他幾種數(shù)據(jù)類型也都差不多。

至于 findAutowireCandidates 方法的邏輯,我們就不去細(xì)看了,我大概和小伙伴們說一下,就是先根據(jù) Bean 的類型,調(diào)用 BeanFactoryUtils.beanNamesForTypeIncludingAncestors 方法去當(dāng)前容器連同父容器中,查找到所有滿足條件的 Bean,處理之后返回。

接下來回到本小節(jié)一開始的源碼中,處理完集合之后,接下來也是調(diào)用 findAutowireCandidates 方法去查找滿足條件的 Bean,但是這個方法查找出來的 Bean 可能有多個,如果存在多個,則要通過 @Primary 注解或者其他優(yōu)先級順序,去確定到底使用哪一個(執(zhí)行 determineAutowireCandidate 方法),如果查找到一個 Bean,那就把找到的 Bean 返回即可。

這就是 @Autowired 一個完整的解析過程。

4. 時序圖

最后,結(jié)合如下時序圖,我再和小伙伴們梳理一下上面的過程。

圖片圖片

  1. 在創(chuàng)建 Bean 的時候,原始 Bean 創(chuàng)建出來之后,會調(diào)用 populateBean 方法進(jìn)行 Bean 的屬性填充。
  2. 接下來調(diào)用 postProcessAfterInstantiation 方法去判斷是否需要執(zhí)行后置處理器,如果不需要,就直接返回了。
  3. 調(diào)用 postProcessProperties 方法,去觸發(fā)各種后置處理器的執(zhí)行。

圖片圖片

  1. 在第 3 步的方法中,調(diào)用 findAutowiringMetadata,這個方法又會進(jìn)一步觸發(fā) buildAutorwiringMetadata 方法,去找到包含了 @Autowired、@Value 以及 @Inject 注解的屬性或者方法,并將之封裝為 InjectedElement 返回。
  2. 調(diào)用 InjectedElement#inject 方法進(jìn)行屬性注入。

圖片圖片

  1. 接下來執(zhí)行 resolvedCachedArgument 方法嘗試從緩存中找到需要的 Bean 對象。
  2. 如果緩存中不存在,則調(diào)用 resolveFieldValue 方法去容器中找到 Bean。
  3. 最后調(diào)用 makeAccessible 和 set 方法完成屬性的賦值。

整體上的流程就是這樣,細(xì)節(jié)小伙伴們參考第二小節(jié)內(nèi)容。

本文轉(zhuǎn)載自微信公眾號「江南一點雨 」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系江南一點雨公眾號。

責(zé)任編輯:武曉燕 來源: 江南一點雨
相關(guān)推薦

2024-03-15 08:06:58

MySQLJOIN命令

2024-05-11 09:41:45

線程安全代碼

2020-12-28 08:18:55

安全代碼線程

2019-05-28 13:50:27

MySQL幻讀數(shù)據(jù)庫

2019-12-18 18:31:10

黑客醫(yī)療保險軟件

2016-11-17 22:18:31

id串行化服務(wù)器

2022-01-07 07:59:14

Go語言Go Error

2022-01-14 17:01:44

GoError結(jié)構(gòu)

2024-02-22 08:00:00

SoraOpenAI

2022-08-08 08:00:00

人工智能機(jī)器學(xué)習(xí)計算機(jī)應(yīng)用

2021-01-08 09:48:18

Pythonname變量

2018-02-24 23:19:31

iOSbug蘋果

2023-10-12 08:54:20

Spring事務(wù)設(shè)置

2022-04-15 08:54:39

PythonAsync代碼

2024-12-09 09:55:25

2022-05-24 17:00:41

區(qū)塊鏈IT比特幣

2015-04-21 09:20:40

SwfitObject—C

2018-09-30 15:05:01

Linux用戶組命令

2022-04-10 19:26:07

TypeScript類型語法

2015-10-09 11:01:07

iPhone原創(chuàng)鎖定
點贊
收藏

51CTO技術(shù)棧公眾號