亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring Bean生命周期之屬性賦值階段詳解

 更新時間:2022年03月04日 15:33:40   作者:碼農(nóng)的進(jìn)階之路  
這篇文章主要為大家詳細(xì)介紹了Spring Bean生命周期之屬性賦值階段,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

前言

上節(jié)在談?wù)揃ean的實(shí)例化過程時,在說明實(shí)例化后階段時只是粗略地看了一下populateBean,并未展開分析。本節(jié)接著populateBean開始分析對象賦值階段的事情。

populateBean其實(shí)主要做了以下幾件事:

  • Bean實(shí)例化后回調(diào),來決定是否進(jìn)行屬性賦值 (上節(jié)分析過了)
  • 對屬性進(jìn)行自動裝配
  • InstantiationAwareBeanPostProcessor屬性賦值前回調(diào)
  • 屬性的真正賦值
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		//省略無關(guān)代碼
		// 1、 Bean實(shí)例化后回調(diào),來決定是否進(jìn)行屬性賦值 
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
        //2、對屬性進(jìn)行自動裝配
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		//3、InstantiationAwareBeanPostProcessor屬性賦值前回調(diào)
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		//省略無關(guān)代碼
		if (pvs != null) {
		  //屬性的賦值
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

屬性自動裝配

PropertyValues 對bd中屬性的封裝,可以理解為bd中屬性鍵值均由其保存,其常用實(shí)現(xiàn)類為MutablePropertyValues,在BeanDefinition的概述及使用 有介紹其使用,可點(diǎn)擊查看

        //這里的bd是已經(jīng)執(zhí)行過合并BeanDefinition操作了
        //如果bd存在屬性 則獲取
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//獲取bd的自動注入模式 
		//注入模式有四種:
		//1.構(gòu)造函數(shù)注入 2、按照名稱注入 3、按照類型注入 4、不注入(默認(rèn),依然可能會被注解驅(qū)動注入)
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		//如果是按名稱注入或類型注入時
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			//按名稱注入
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			    //按類型注入,基本上這種比較常用
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

下面我們分別來大致看下autowireByNameautowireByType 熟悉下實(shí)現(xiàn)原理

autowireByName

protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
		//獲取屬性名稱
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍歷屬性名稱
		for (String propertyName : propertyNames) {
		    //如果屬性名稱已在beanDefinitionMap中,說明其是bd 并已被注冊待IoC容器
			if (containsBean(propertyName)) {
			    //根據(jù)名稱獲取其bean對象
				Object bean = getBean(propertyName);
				//以鍵值方法賦值到pvs
				pvs.add(propertyName, bean);
				// 這里是維護(hù)dependentBeanMap、dependenciesForBeanMap兩個集合,
				// 這里不再展開 在說到LifecycleProcessor時再展開
				registerDependentBean(propertyName, beanName);
				//省略日志輸出
			}
			else {
				//省略日志輸出
			}
		}
	}

autowireByType

按類型注入稍顯復(fù)雜些,但流程上與按名稱注入類似

protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
		//類型轉(zhuǎn)換器
		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}
		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		//依然是獲取屬性名稱
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍歷屬性名稱
		for (String propertyName : propertyNames) {
			try {
			    //獲取屬性描述對象
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				//不對Object類型做注入,因此這里判斷條件如下
				if (Object.class != pd.getPropertyType()) {
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//解析依賴
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
					//以鍵值方法賦值到pvs
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
					 // 這里是維護(hù)dependentBeanMap、dependenciesForBeanMap兩個集合,
				     // 這里不再展開 在說到LifecycleProcessor時再展開
						registerDependentBean(autowiredBeanName, beanName);
						//省略日志輸出
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				//省略異常信息
		}
	}

接下來我們進(jìn)入到resolveDependency,大致分析下解析依賴的主要流程

DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    //如果依賴類型是Optional
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
  //如果依賴類型是ObjectFactory或ObjectProvider
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
   //如果依賴類型是Inject
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
        //實(shí)際執(zhí)行解析依賴的邏輯代碼  
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}
	@Nullable
	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();
      //獲取依賴類型的默認(rèn)值,如@Value注解 可提供默認(rèn)值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
        //如果默認(rèn)值是String類型
				if (value instanceof String) {
          //從配置文件中解析出指定key的數(shù)據(jù)
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
        //類型轉(zhuǎn)換器 用于轉(zhuǎn)換類型,如配置文件中聲明的是字符串類型的數(shù)字,而java中使用Integer接收,則類型轉(zhuǎn)換器就派上用場了
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
			//解析出類型是Stream、Map、數(shù)組、Collection等集合類型的依賴。解析的思路很類似 即去IoC容器中 查找集合類實(shí)際泛型對應(yīng)的Bean
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//這里主要是查找單實(shí)例Bean的,如果某個類型的Bean有多個,這里會被全部查找出來,因此使用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;
      //如果查找出的Bean有多個,
			if (matchingBeans.size() > 1) {
        //找出標(biāo)注了@Primary的那個Bean名稱,作為查找出的Bean
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
            //如果沒有@Primary注解標(biāo)注,那么拋出NoUniqueBeanDefinitionException
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
        //如果查找出的Bean只有1個 那么說明找到了。
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				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);
		}
	}

可以看出resolveDependency方法還是很強(qiáng)大的,無論是單一類型對象還是集合類型對象,無論是Optional類型還是延遲加載ObjectFactory類型 其均可以解析出來。

屬性賦值前回調(diào)

         //boolean值 判斷有沒有InstantiationAwareBeanPostProcessor存在
         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
         // 這是 是否依賴檢查的標(biāo)記 不是我們此次的重點(diǎn)
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		PropertyDescriptor[] filteredPds = null;
		//IoC容器中如果存在InstantiationAwareBeanPostProcessor
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			//遍歷BeanPostProcessor,找到InstantiationAwareBeanPostProcessor類型
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//postProcessProperties、postProcessPropertyValues兩個方法含義類似。如果postProcessProperties未被重寫 則執(zhí)行postProcessPropertyValues方法
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}

這里針對一個小案例說明下postProcessPropertyValuespostProcessProperties的使用

需求:將注入的user對象中name屬性由wojiushiwo修改為abc

實(shí)體對象User

@Data
@ToString
public class User {
    private String name;
    private Integer age;
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
public class MyInstantiationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if(ObjectUtils.nullSafeEquals("user",beanName) && User.class.equals(bean.getClass())){
            final MutablePropertyValues propertyValues;
            if(pvs instanceof MutablePropertyValues){
                propertyValues= (MutablePropertyValues) pvs;
            }else{
                propertyValues=new MutablePropertyValues();
            }
            if(propertyValues.contains("name")){
                propertyValues.removePropertyValue("name");
                propertyValues.addPropertyValue("name","abcd");
            }
            return propertyValues;
        }
        return null;
    }
}
public class BeanPostProcessDemo {
    public static void main(String[] args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("name", "wojiushiwo");
        beanDefinitionBuilder.addPropertyValue("age", 20);
        // 獲取 AbstractBeanDefinition
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // 附加屬性(
        beanDefinition.setAttribute("name", "我是附加屬性");
        // 當(dāng)前 BeanDefinition 來自哪里(輔助作用)
        beanDefinition.setSource(BeanPostProcessDemo.class);
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.addBeanPostProcessor(new MyInstantiationBeanPostProcessor());
        // 注冊 User 的 BeanDefinition
        beanFactory.registerBeanDefinition("user", beanDefinition);
        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }
}

輸出結(jié)果:

User(name=abcd, age=20)

屬性的真正賦值

    if (pvs != null) {
            //將從前面步驟得到的pvs 賦值到beanWrapper中以實(shí)現(xiàn)屬性賦值,這部分具體源碼這里不展開了
			applyPropertyValues(beanName, mbd, bw, pvs);
		}

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • 在Java代碼中解析html,獲取其中的值方法

    在Java代碼中解析html,獲取其中的值方法

    今天小編就為大家分享一篇在Java代碼中解析html,獲取其中的值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Spring boot集成Kafka消息中間件代碼實(shí)例

    Spring boot集成Kafka消息中間件代碼實(shí)例

    這篇文章主要介紹了Spring boot集成Kafka消息中間件代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • 淺談Java反射與代理

    淺談Java反射與代理

    下面小編就為大家?guī)硪黄獪\談Java反射與代理。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • SpringBoot使用Spark過程詳解

    SpringBoot使用Spark過程詳解

    這篇文章主要介紹SpringBoot使用Spark的方法的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望能幫助大家解決問題
    2023-02-02
  • Java環(huán)境變量配置教程

    Java環(huán)境變量配置教程

    這篇文章主要介紹了Java環(huán)境變量配置教程,簡單介紹了java的環(huán)境變量設(shè)置方法,感興趣的小伙伴們可以參考一下
    2016-06-06
  • SpringBoot中的ApplicationListener事件監(jiān)聽器使用詳解

    SpringBoot中的ApplicationListener事件監(jiān)聽器使用詳解

    這篇文章主要介紹了SpringBoot中的ApplicationListener事件監(jiān)聽器使用詳解,ApplicationListener是應(yīng)用程序的事件監(jiān)聽器,繼承自java.util.EventListener標(biāo)準(zhǔn)接口,采用觀察者設(shè)計模式,需要的朋友可以參考下
    2023-11-11
  • 淺談Java finally語句到底是在return之前還是之后執(zhí)行(必看篇)

    淺談Java finally語句到底是在return之前還是之后執(zhí)行(必看篇)

    下面小編就為大家?guī)硪黄獪\談Java finally語句到底是在return之前還是之后執(zhí)行(必看篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • java數(shù)組中的異常類型整理

    java數(shù)組中的異常類型整理

    在本篇文章里小編給各位分享的是一篇關(guān)于java數(shù)組中的異常類型整理內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-02-02
  • JAVA中通過自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法

    JAVA中通過自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的方法

    java 自定義注解驗(yàn)證可自己添加所需要的注解,下面這篇文章主要給大家介紹了關(guān)于JAVA中通過自定義注解進(jìn)行數(shù)據(jù)驗(yàn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Java利用redis zset實(shí)現(xiàn)延時任務(wù)詳解

    Java利用redis zset實(shí)現(xiàn)延時任務(wù)詳解

    zset作為redis的有序集合數(shù)據(jù)結(jié)構(gòu)存在,排序的依據(jù)就是score。本文就將利用zset score這個排序的這個特性,來實(shí)現(xiàn)延時任務(wù),感興趣的可以了解一下
    2022-08-08

最新評論