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

Spring源碼解析 Bean屬性填充

 更新時(shí)間:2022年07月07日 09:36:56   作者:? 碼農(nóng)參上??  
這篇文章主要介紹了Spring源碼解析 Bean屬性填充,文章圍繞主題展開想詳細(xì)的內(nèi)容詳情,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

前言

上一篇文章中,我們分析了Spring中Bean的實(shí)例化過程,在結(jié)尾我們知道了雖然bean的實(shí)例化完成了,但是其中的屬性還沒有被注入,今天我們就接著來分析屬性是如何被注入的。

屬性填充

實(shí)例化完成后,回到上面第3條的doCreateBean方法中,看一下用BeanWrapper產(chǎn)生的原生對(duì)象,里面dao這個(gè)屬性還是null值。

回歸一下之前的代碼,接下來要調(diào)用populateBean方法進(jìn)行屬性的填充:

Object exposedObject = bean;
try {
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
}

看一下populateBean中的核心代碼:

for (BeanPostProcessor bp : getBeanPostProcessors()) {
  if (bp instanceof InstantiationAwareBeanPostProcessor) {
    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    if (pvs == null) {
      return;
    }
  }
}

這里通過getBeanPostProcessors方法獲得當(dāng)前注冊(cè)的所有后置處理器,如果屬于InstantiationAwareBeanPostProcessor類型,則調(diào)用它的postProcessPropertyValues方法。通過遍歷,可以知道當(dāng)前spring中存在7個(gè)后置處理器:

我們主要來看一下AutowiredAnnotationBeanPostProcessor,因?yàn)樗?fù)責(zé)對(duì)添加了 @Autowired@Value等注解的屬性進(jìn)行依賴的填充。進(jìn)入它的postProcessPropertyValues方法:

public PropertyValues postProcessPropertyValues(
  PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
  InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
  try {
    metadata.inject(bean, beanName, pvs);
  }
 //異常處理代碼省略...
  return pvs;
}

這里的InjectionMetadata可以理解為要注入的屬性的元數(shù)據(jù),在它里面維護(hù)了一個(gè)Collection,來存放所有需要注入的bean:

private final Collection<InjectedElement> injectedElements;

進(jìn)入findAutowiringMetadata方法:

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
 String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
 InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
  //省略非重要代碼...
 return metadata;
}

在執(zhí)行完這一步后,就把需要填充的屬性放進(jìn)了剛才提到的injectedElements中:

接下來,繼續(xù)執(zhí)行InjectionMetadatainject方法,在其中遍歷所有需要注入的屬性的列表,遍歷調(diào)用AutowiredAnnotationBeanPostProcessor的inject方法:

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      Field field = (Field) this.member;
      Object value;
      if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      }
      else {
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {//用beanFactory解決依賴
          value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
   //后面代碼省略...

這里創(chuàng)建了一個(gè)DependencyDescriptor,用來維護(hù)注入屬性與它的容器類containingClass的關(guān)系,里面最重要的就是存放了注入屬性的類型、名稱,以及containingClass的類型等信息。

調(diào)用resolveDependency方法,其中沒有做什么實(shí)質(zhì)性的工作,繼續(xù)調(diào)用了doResolveDependency方法:

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
  try {
    Object shortcut = descriptor.resolveShortcut(this);
    if (shortcut != null) {
      return shortcut;
    }
    //依賴的屬性值的類型
    Class<?> type = descriptor.getDependencyType();
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    if (value != null) {
      if (value instanceof String) {
        String strVal = resolveEmbeddedValue((String) value);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
        value = evaluateBeanDefinitionString(strVal, bd);
      }
      TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
      return (descriptor.getField() != null ?
          converter.convertIfNecessary(value, type, descriptor.getField()) :
          converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
    }

    Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    if (multipleBeans != null) {
      return multipleBeans;
    }
    //把匹配的值和類型拿出來,放到一個(gè)map中
    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;
    //如果有超過一個(gè)匹配的,可能會(huì)有錯(cuò)誤
    if (matchingBeans.size() > 1) {
      autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
      if (autowiredBeanName == null) {
        if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
          return descriptor.resolveNotUnique(type, matchingBeans);
        }
        else {
          return null;
        }
      }
      instanceCandidate = matchingBeans.get(autowiredBeanName);
    }
    else {
      Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
      autowiredBeanName = entry.getKey();
      instanceCandidate = entry.getValue();
    }

    if (autowiredBeanNames != null) {
      //把找到的bean的名字放到set中
      autowiredBeanNames.add(autowiredBeanName);
    }
    if (instanceCandidate instanceof Class) {
      // 實(shí)際獲取注入的bean
      instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    }
    Object result = instanceCandidate;
    if (result instanceof NullBean) {
      if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
      }
      result = null;
    }
    if (!ClassUtils.isAssignableValue(type, result)) {
      throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
    }
    return result;
  }
  finally {
    ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
  }
}

通過findAutowireCandidates方法,獲取與注入屬性匹配的值和類型,放到一個(gè)Map當(dāng)中,再通過它的beanName,調(diào)用resolveCandidate方法,實(shí)際獲取注入的bean實(shí)例。這一操作底層調(diào)用的也是BeanFactory的getBean方法。

回到inject方法,使用反射將注入的bean實(shí)例賦值給屬性:

ReflectionUtils.makeAccessible(field);
field.set(bean, value);

在執(zhí)行完populateBean方法后,依賴的屬性已經(jīng)被注入成功了。

執(zhí)行回調(diào)方法及后置處理器

在bean實(shí)例化完成后,執(zhí)行各種回調(diào)和后置管理器方法:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  if (System.getSecurityManager() != null) {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      invokeAwareMethods(beanName, bean);
      return null;
    }, getAccessControlContext());
  }
  else {
    //若bean實(shí)現(xiàn)了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口,執(zhí)行回調(diào)方法
    invokeAwareMethods(beanName, bean);
  }

  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
    //執(zhí)行所有后置處理器的before方法
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }

  try {
    //執(zhí)行bean生命周期回調(diào)中的init-method
    //若bean實(shí)現(xiàn)了InitializingBean接口,執(zhí)行afterPropertiesSet方法
    invokeInitMethods(beanName, wrappedBean, mbd);
  }
  catch (Throwable ex) {
    throw new BeanCreationException(
        (mbd != null ? mbd.getResourceDescription() : null),
        beanName, "Invocation of init method failed", ex);
  }
  if (mbd == null || !mbd.isSynthetic()) {
    //執(zhí)行所有后置處理器的after方法
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }

  return wrappedBean;
}

具體執(zhí)行內(nèi)容:

  • 1、若bean實(shí)現(xiàn)了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口,執(zhí)行回調(diào)方法
  • 2、執(zhí)行所有后置處理器的postProcessBeforeInitialization方法
  • 3、執(zhí)行bean生命周期回調(diào)中的init-method,若bean實(shí)現(xiàn)了InitializingBean接口,執(zhí)行afterPropertiesSet方法
  • 4、執(zhí)行所有后置處理器的postProcessAfterInitialization方法

在這一步完成后,bean的實(shí)例化過程全部結(jié)束。最后執(zhí)行一下refresh方法中的finishRefresh方法,進(jìn)行廣播事件等操作。到這,一個(gè)完整的AnnotationConfigApplicationContext初始化就完成了。

到此這篇關(guān)于Spring源碼解析 Bean屬性填充的文章就介紹到這了,更多相關(guān)Spring Bean屬性填充內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

  • Java Method類及invoke方法原理解析

    Java Method類及invoke方法原理解析

    這篇文章主要介紹了Java Method類及invoke方法原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • java開發(fā)的工廠方法模式及抽象工廠驗(yàn)證示例

    java開發(fā)的工廠方法模式及抽象工廠驗(yàn)證示例

    這篇文章主要為大家介紹了java開發(fā)中的工廠方法模式以及抽象工廠的驗(yàn)證示例,有需要的朋友可以借鑒參考下希望能夠有所幫助祝大家多多進(jìn)步
    2021-10-10
  • Java中的代理模式詳解及實(shí)例代碼

    Java中的代理模式詳解及實(shí)例代碼

    這篇文章主要介紹了Java中的代理模式詳解及實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下
    2017-02-02
  • SpringBoot 文件或圖片上傳與下載功能的實(shí)現(xiàn)

    SpringBoot 文件或圖片上傳與下載功能的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot 文件或圖片上傳與下載功能的實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • SpringBoot創(chuàng)建WebService方法詳解

    SpringBoot創(chuàng)建WebService方法詳解

    這篇文章主要介紹了SpringBoot如何創(chuàng)建WebService,文中有詳細(xì)的實(shí)現(xiàn)步驟以及示例代碼,對(duì)學(xué)習(xí)或工作有一定的幫助,需要的朋友跟著小編一起來學(xué)習(xí)吧
    2023-05-05
  • Spring依賴注入和控制反轉(zhuǎn)詳情

    Spring依賴注入和控制反轉(zhuǎn)詳情

    這篇文章主要介紹了Spring依賴注入和控制反轉(zhuǎn)詳情,控制反轉(zhuǎn)是面向?qū)ο缶幊讨惺褂玫男g(shù)語,通過該術(shù)語,對(duì)象或?qū)ο蠹目刂茩?quán)被賦予框架或由框架提供的容器。下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié)

    JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié)

    本篇文章主要介紹了JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼

    SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼

    本篇文章主要介紹了SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Java生成UUID的常用方式示例代碼

    Java生成UUID的常用方式示例代碼

    UUID保證對(duì)在同一時(shí)空中的所有機(jī)器都是唯一的,通常平臺(tái)會(huì)提供生成的API,按照開放軟件基金會(huì)(OSF)制定的標(biāo)準(zhǔn)計(jì)算,用到了以太網(wǎng)卡地址、納秒級(jí)時(shí)間、芯片ID碼和許多可能的數(shù)字,下面這篇文章主要給大家介紹了關(guān)于Java生成UUID的常用方式,需要的朋友可以參考下
    2023-05-05
  • 最新評(píng)論