<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
上節在談論Bean的範例化過程時,在說明範例化後階段時只是粗略地看了一下populateBean
,並未展開分析。本節接著populateBean
開始分析物件賦值階段的事情。
populateBean其實主要做了以下幾件事:
InstantiationAwareBeanPostProcessor
屬性賦值前回撥protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //省略無關程式碼 // 1、 Bean範例化後回撥,來決定是否進行屬性賦值 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、對屬性進行自動裝配 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屬性賦值前回撥 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; } } } //省略無關程式碼 if (pvs != null) { //屬性的賦值 applyPropertyValues(beanName, mbd, bw, pvs); } }
PropertyValues 對bd中屬性的封裝,可以理解為bd中屬性鍵值均由其儲存,其常用實現類為MutablePropertyValues,在BeanDefinition的概述及使用 有介紹其使用,可點選檢視
//這裡的bd是已經執行過合併BeanDefinition操作了 //如果bd存在屬性 則獲取 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); //獲取bd的自動注入模式 //注入模式有四種: //1.建構函式注入 2、按照名稱注入 3、按照型別注入 4、不注入(預設,依然可能會被註解驅動注入) 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; }
下面我們分別來大致看下autowireByName
及autowireByType
熟悉下實現原理
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)) { //根據名稱獲取其bean物件 Object bean = getBean(propertyName); //以鍵值方法賦值到pvs pvs.add(propertyName, bean); // 這裡是維護dependentBeanMap、dependenciesForBeanMap兩個集合, // 這裡不再展開 在說到LifecycleProcessor時再展開 registerDependentBean(propertyName, beanName); //省略紀錄檔輸出 } else { //省略紀錄檔輸出 } } }
autowireByType
按型別注入稍顯複雜些,但流程上與按名稱注入類似
protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { //型別轉換器 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) { // 這裡是維護dependentBeanMap、dependenciesForBeanMap兩個集合, // 這裡不再展開 在說到LifecycleProcessor時再展開 registerDependentBean(autowiredBeanName, beanName); //省略紀錄檔輸出 } autowiredBeanNames.clear(); } } catch (BeansException ex) { //省略異常資訊 } }
接下來我們進入到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) { //實際執行解析依賴的邏輯程式碼 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(); //獲取依賴型別的預設值,如@Value註解 可提供預設值 Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { //如果預設值是String型別 if (value instanceof String) { //從組態檔中解析出指定key的資料 String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } //型別轉換器 用於轉換型別,如組態檔中宣告的是字串型別的數位,而java中使用Integer接收,則型別轉換器就派上用場了 TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } //解析出型別是Stream、Map、陣列、Collection等集合型別的依賴。解析的思路很類似 即去IoC容器中 查詢集合類實際泛型對應的Bean Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } //這裡主要是查詢單範例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) { //找出標註了@Primary的那個Bean名稱,作為查詢出的Bean autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { //如果沒有@Primary註解標註,那麼丟擲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
方法還是很強大的,無論是單一型別物件還是集合型別物件,無論是Optional型別還是延遲載入ObjectFactory型別 其均可以解析出來。
//boolean值 判斷有沒有InstantiationAwareBeanPostProcessor存在 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); // 這是 是否依賴檢查的標記 不是我們此次的重點 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未被重寫 則執行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; } } }
這裡針對一個小案例說明下postProcessPropertyValues
和postProcessProperties
的使用
需求:將注入的user物件中name屬性由wojiushiwo修改為abc
實體物件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", "我是附加屬性"); // 當前 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); } }
輸出結果:
User(name=abcd, age=20)
if (pvs != null) { //將從前面步驟得到的pvs 賦值到beanWrapper中以實現屬性賦值,這部分具體原始碼這裡不展開了 applyPropertyValues(beanName, mbd, bw, pvs); }
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45