本篇文章,咱們來一塊兒瞭解一下 Spring 是如何將配置文件中的屬性值填充到 bean 對象中的。我在前面幾篇文章中介紹過 Spring 建立 bean 的流程,即 Spring 先經過反射建立一個原始的 bean 對象,而後再向這個原始的 bean 對象中填充屬性。對於填充屬性這個過程,簡單點來講,JavaBean 的每一個屬性一般都有 getter/setter 方法,咱們能夠直接調用 setter 方法將屬性值設置進去。固然,這樣作仍是太簡單了,填充屬性的過程當中還有許多事情要作。好比在 Spring 配置中,全部屬性值都是以字符串的形式進行配置的,咱們在將這些屬性值賦值給對象的成員變量時,要根據變量類型進行相應的類型轉換。對於一些集合類的配置,好比
、
關於屬性填充的一些知識,本章先介紹這裏。接下來,咱們深刻到源碼中,從源碼中瞭解屬性填充的整個過程。java
本節,咱們先來看一下填充屬性的方法,即 populateBean。該方法並不複雜,但它所調用的一些方法比較複雜。不過好在咱們這裏只須要知道這些方法都有什麼用就好了,暫時不用糾結細節。好了,下面看源碼吧。mysql
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { // 獲取屬性列表 PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) { if (!pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { return; } } boolean continueWithPropertyPopulation = true; /* * 在屬性被填充前,給 InstantiationAwareBeanPostProcessor 類型的後置處理器一個修改 * bean 狀態的機會。關於這段後置引用,官方的解釋是:讓用戶能夠自定義屬性注入。好比用戶實現一 * 個 InstantiationAwareBeanPostProcessor 類型的後置處理器,並經過 * postProcessAfterInstantiation 方法向 bean 的成員變量注入自定義的信息。固然,若是無 * 特殊需求,直接使用配置中的信息注入便可。另外,Spring 並不建議你們直接實現 * InstantiationAwareBeanPostProcessor 接口,若是想實現這種類型的後置處理器,更建議 * 經過繼承 InstantiationAwareBeanPostProcessorAdapter 抽象類實現自定義後置處理器。 */ if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } /* * 若是上面設置 continueWithPropertyPopulation = false,代表用戶可能已經本身填充了 * bean 的屬性,不須要 Spring 幫忙填充了。此時直接返回便可 */ if (!continueWithPropertyPopulation) { return; } // 根據名稱或類型注入依賴 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // 經過屬性名稱注入依賴 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // 經過屬性類型注入依賴 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); /* * 這裏又是一種後置處理,用於在 Spring 填充屬性到 bean 對象前,對屬性的值進行相應的處理, * 好比能夠修改某些屬性的值。這時注入到 bean 中的值就不是配置文件中的內容了, * 而是通過後置處理器修改後的內容 */ if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 對屬性進行後置處理 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } // 應用屬性值到 bean 對象中 applyPropertyValues(beanName, mbd, bw, pvs); }
上面的源碼註釋的比較詳細了,下面咱們來總結一下這個方法的執行流程。以下:spring
注意第3步,也就是根據名稱或類型解析相關依賴(autowire)。該邏輯只會解析依賴,並不會將解析出的依賴當即注入到 bean 對象中。全部的屬性值是在 applyPropertyValues 方法中統一被注入到 bean 對象中的。sql
在下面的章節中,我將會對 populateBean 方法中比較重要的幾個方法調用進行分析,也就是第3步和第5步中的三個方法。好了,本節先到這裏。數組
本節來分析一下 autowireByName 方法的代碼,其實這個方法根據方法名,你們應該知道它有什麼用了。因此我也就不囉嗦了,我們直奔主題,直接分析源碼:mvc
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { /* * 獲取非簡單類型屬性的名稱,且該屬性未被配置在配置文件中。這裏從反面解釋一下什麼是"非簡單類型" * 屬性,咱們先來看看 Spring 認爲的"簡單類型"屬性有哪些,以下: * 1. CharSequence 接口的實現類,好比 String * 2. Enum * 3. Date * 4. URI/URL * 5. Number 的繼承類,好比 Integer/Long * 6. byte/short/int... 等基本類型 * 7. Locale * 8. 以上全部類型的數組形式,好比 String[]、Date[]、int[] 等等 * * 除了要求非簡單類型的屬性外,還要求屬性未在配置文件中配置過,也就是 pvs.contains(pd.getName()) = false。 */ String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { // 檢測是否存在與 propertyName 相關的 bean 或 BeanDefinition。若存在,則調用 BeanFactory.getBean 方法獲取 bean 實例 if (containsBean(propertyName)) { // 從容器中獲取相應的 bean 實例 Object bean = getBean(propertyName); // 將解析出的 bean 存入到屬性值列表(pvs)中 pvs.add(propertyName, bean); registerDependentBean(propertyName, beanName); if (logger.isDebugEnabled()) { logger.debug("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); } } else { if (logger.isTraceEnabled()) { logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found"); } } } }
autowireByName 方法的邏輯比較簡單,該方法首先獲取非簡單類型屬性的名稱,而後再根據名稱到容器中獲取相應的 bean 實例,最後再將獲取到的 bean 添加到屬性列表中便可。既然這個方法比較簡單,那我也就很少說了,繼續下面的分析。app
本節咱們來分析一下 autowireByName 的孿生兄弟 autowireByType,相較於 autowireByName,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<String>(4); // 獲取非簡單類型的屬性 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { try { PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); // 若是屬性類型爲 Object,則忽略,不作解析 if (Object.class != pd.getPropertyType()) { /* * 獲取 setter 方法(write method)的參數信息,好比參數在參數列表中的 * 位置,參數類型,以及該參數所歸屬的方法等信息 */ MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); // 建立依賴描述對象 DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); /* * 下面的方法用於解析依賴。過程比較複雜,先把這裏當作一個黑盒,咱們只要知道這 * 個方法能夠幫咱們解析出合適的依賴便可。 */ Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument != null) { // 將解析出的 bean 存入到屬性值列表(pvs)中 pvs.add(propertyName, autowiredArgument); } for (String autowiredBeanName : autowiredBeanNames) { registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) { logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); } } }
如上所示,autowireByType 的代碼自己並不複雜。和 autowireByName 同樣,autowireByType 首先也是獲取非簡單類型屬性的名稱。而後再根據屬性名獲取屬性描述符,並由屬性描述符獲取方法參數對象 MethodParameter,隨後再根據 MethodParameter 對象獲取依賴描述符對象,整個過程爲 beanName → PropertyDescriptor → MethodParameter → DependencyDescriptor
。在獲取到依賴描述符對象後,再根據依賴描述符解析出合適的依賴。最後將解析出的結果存入屬性列表 pvs 中便可。ide
關於 autowireByType 方法中出現的幾種描述符對象,你們本身去看一下他們的實現吧,我就不分析了。接下來,咱們來分析一下解析依賴的方法 resolveDependency。以下:
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (javaUtilOptionalClass == descriptor.getDependencyType()) { return new OptionalDependencyFactory().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 Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName); } else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { // 解析依賴 result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } } public Object doResolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { // 該方法最終調用了 beanFactory.getBean(String, Class),從容器中獲取依賴 Object shortcut = descriptor.resolveShortcut(this); // 若是容器中存在所需依賴,這裏進行斷路操做,提早結束依賴解析邏輯 if (shortcut != null) { return shortcut; } Class<?> type = descriptor.getDependencyType(); // 處理 @value 註解 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())); } // 解析數組、list、map 等類型的依賴 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } /* * 按類型查找候選列表,若是某個類型已經被實例化,則返回相應的實例。 * 好比下面的配置: * * <bean name="mongoDao" class="xyz.coolblog.autowire.MongoDao" primary="true"/> * <bean name="service" class="xyz.coolblog.autowire.Service" autowire="byType"/> * <bean name="mysqlDao" class="xyz.coolblog.autowire.MySqlDao"/> * * MongoDao 和 MySqlDao 均實現自 Dao 接口,Service 對象(不是接口)中有一個 Dao * 類型的屬性。如今根據類型自動注入 Dao 的實現類。這裏有兩個候選 bean,一個是 * mongoDao,另外一個是 mysqlDao,其中 mongoDao 在 service 以前實例化, * mysqlDao 在 service 以後實例化。此時 findAutowireCandidates 方法會返回以下的結果: * * matchingBeans = [ <mongoDao, Object@MongoDao>, <mysqlDao, Class@MySqlDao> ] * * 注意 mysqlDao 還未實例化,因此返回的是 MySqlDao.class。 * * findAutowireCandidates 這個方法邏輯比較複雜,我簡單說一下它的工做流程吧,以下: * 1. 從 BeanFactory 中獲取某種類型 bean 的名稱,好比上面的配置中 * mongoDao 和 mysqlDao 均實現了 Dao 接口,因此他們是同一種類型的 bean。 * 2. 遍歷上一步獲得的名稱列表,並判斷 bean 名稱對應的 bean 是不是合適的候選項, * 若合適則添加到候選列表中,並在最後返回候選列表 * * findAutowireCandidates 比較複雜,我並未徹底搞懂,就不深刻分析了。見諒 */ Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { // 拋出 NoSuchBeanDefinitionException 異常 raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; if (matchingBeans.size() > 1) { /* * matchingBeans.size() > 1,則代表存在多個可注入的候選項,這裏判斷使用哪個 * 候選項。好比下面的配置: * * <bean name="mongoDao" class="xyz.coolblog.autowire.MongoDao" primary="true"/> * <bean name="mysqlDao" class="xyz.coolblog.autowire.MySqlDao"/> * * mongoDao 的配置中存在 primary 屬性,因此 mongoDao 會被選爲最終的候選項。如 * 果兩個 bean 配置都沒有 primary 屬性,則須要根據優先級選擇候選項。優先級這一塊 * 的邏輯沒細看,很少說了。 */ autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { // 拋出 NoUniqueBeanDefinitionException 異常 return descriptor.resolveNotUnique(type, matchingBeans); } else { return null; } } // 根據解析出的 autowiredBeanName,獲取相應的候選項 instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // 只有一個候選項,直接取出來便可 Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } // 返回候選項實例,若是實例是 Class 類型,則調用 beanFactory.getBean(String, Class) 獲取相應的 bean。不然直接返回便可 return (instanceCandidate instanceof Class ? descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate); } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
由上面的代碼能夠看出,doResolveDependency 這個方法仍是挺複雜的。這裏我就不繼續分析 doResolveDependency 所調用的方法了,對於這些方法,我也是似懂非懂。好了,本節的最後咱們來總結一下 doResolveDependency 的執行流程吧,以下:
好了,本節的內容先到這裏。若是有分析錯的地方,歡迎你們指出來。
通過了上面的流程,如今終於能夠將屬性值注入到 bean 對象中了。固然,這裏還不能當即將屬性值注入到對象中,由於在 Spring 配置文件中屬性值都是以 String 類型進行配置的,因此 Spring 框架須要對 String 類型進行轉換。除此以外,對於 ref 屬性,這裏還須要根據 ref 屬性值解析依賴。還有一些其餘操做,這裏就很少說了,更多的信息咱們一塊兒在源碼探尋。
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs == null || pvs.isEmpty()) { return; } if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } MutablePropertyValues mpvs = null; List<PropertyValue> original; if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; // 若是屬性列表 pvs 被轉換過,則直接返回便可 if (mpvs.isConverted()) { try { bw.setPropertyValues(mpvs); return; } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size()); boolean resolveNecessary = false; // 遍歷屬性列表 for (PropertyValue pv : original) { // 若是屬性值被轉換過,則就不須要再次轉換 if (pv.isConverted()) { deepCopy.add(pv); } else { String propertyName = pv.getName(); Object originalValue = pv.getValue(); /* * 解析屬性值。舉例說明,先看下面的配置: * * <bean id="macbook" class="MacBookPro"> * <property name="manufacturer" value="Apple"/> * <property name="width" value="280"/> * <property name="cpu" ref="cpu"/> * <property name="interface"> * <list> * <value>USB</value> * <value>HDMI</value> * <value>Thunderbolt</value> * </list> * </property> * </bean> * * 上面是一款電腦的配置信息,每一個 property 配置通過下面的方法解析後,返回以下結果: * propertyName = "manufacturer", resolvedValue = "Apple" * propertyName = "width", resolvedValue = "280" * propertyName = "cpu", resolvedValue = "CPU@1234" 注:resolvedValue 是一個對象 * propertyName = "interface", resolvedValue = ["USB", "HDMI", "Thunderbolt"] * * 如上所示,resolveValueIfNecessary 會將 ref 解析爲具體的對象,將 <list> * 標籤轉換爲 List 對象等。對於 int 類型的配置,這裏並未作轉換,因此 * width = "280",仍是字符串。除了解析上面幾種類型,該方法還會解析 <set/>、 * <map/>、<array/> 等集合配置 */ Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); Object convertedValue = resolvedValue; /* * convertible 表示屬性值是否可轉換,由兩個條件合成而來。第一個條件不難理解,解釋 * 一下第二個條件。第二個條件用於檢測 propertyName 是不是 nested 或者 indexed, * 直接舉例說明吧: * * public class Room { * private Door door = new Door(); * } * * room 對象裏面包含了 door 對象,若是咱們想向 door 對象中注入屬性值,則能夠這樣配置: * * <bean id="room" class="xyz.coolblog.Room"> * <property name="door.width" value="123"/> * </bean> * * isNestedOrIndexedProperty 會根據 propertyName 中是否包含 . 或 [ 返回 * true 和 false。包含則返回 true,不然返回 false。關於 nested 類型的屬性,我 * 沒在實踐中用過,因此不知道上面舉的例子是否是合理。若不合理,歡迎指正,也請多多指教。 * 關於 nested 類型的屬性,你們還能夠參考 Spring 的官方文檔: * https://docs.spring.io/spring/docs/4.3.17.RELEASE/spring-framework-reference/htmlsingle/#beans-beans-conventions */ boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); // 對於通常的屬性,convertible 一般爲 true if (convertible) { // 對屬性值的類型進行轉換,好比將 String 類型的屬性值 "123" 轉爲 Integer 類型的 123 convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } /* * 若是 originalValue 是經過 autowireByType 或 autowireByName 解析而來, * 那麼此處條件成立,即 (resolvedValue == originalValue) = true */ if (resolvedValue == originalValue) { if (convertible) { // 將 convertedValue 設置到 pv 中,後續再次建立同一個 bean 時,就無需再次進行轉換了 pv.setConvertedValue(convertedValue); } deepCopy.add(pv); } /* * 若是原始值 originalValue 是 TypedStringValue,且轉換後的值 * convertedValue 不是 Collection 或數組類型,則將轉換後的值存入到 pv 中。 */ else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); } else { resolveNecessary = true; deepCopy.add(new PropertyValue(pv, convertedValue)); } } } if (mpvs != null && !resolveNecessary) { mpvs.setConverted(); } try { // 將全部的屬性值設置到 bean 實例中 bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } }
以上就是 applyPropertyValues 方法的源碼,配合着我寫的註釋,應該能夠理解這個方法的流程。這個方法也調用了不少其餘的方法,若是你們跟下去的話,會發現這些方法的調用棧也是很深的,比較複雜。這裏說一下 bw.setPropertyValues 這個方法,若是你們跟到這個方法的調用棧的最底部,會發現這個方法是經過調用對象的 setter 方法進行屬性設置的。這裏貼一下簡化後的代碼:
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { // 省略部分代碼 private class BeanPropertyHandler extends PropertyHandler { @Override public void setValue(final Object object, Object valueToApply) throws Exception { // 獲取 writeMethod,也就是 setter 方法 final Method writeMethod = this.pd.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) { writeMethod.setAccessible(true); } final Object value = valueToApply; // 調用 setter 方法,getWrappedInstance() 返回的是 bean 對象 writeMethod.invoke(getWrappedInstance(), value); } } }
好了,本節的最後來總結一下 applyPropertyValues 方法的執行流程吧,以下:
本文對 populateBean 方法及其所調用的 autowireByName、autowireByType 和 applyPropertyValues 作了較爲詳細的分析,不知道你們看完後感受如何。我說一下個人感覺吧,從我看 Spring IOC 部分的源碼到如今寫了5篇關於 IOC 部分的源碼分析文章,整體感受 Spring 的源碼仍是很複雜的,調用層次很深。若是想對源碼有一個比較好的理解,須要很多的時間去分析,調試源碼。總的來講,不容易。固然,個人水平有限。若是你們本身去閱讀源碼,可能會以爲也沒這麼難啊。
好了,其餘的就很少說了。若是本文中有分析錯的地方,歡迎你們指正。最後感謝你們的閱讀。
更新時間 | 標題 |
---|---|
2018-05-30 | Spring IOC 容器源碼分析系列文章導讀 |
2018-06-01 | Spring IOC 容器源碼分析 - 獲取單例 bean |
2018-06-04 | Spring IOC 容器源碼分析 - 建立單例 bean 的過程 |
2018-06-06 | Spring IOC 容器源碼分析 - 建立原始 bean 對象 |
2018-06-08 | Spring IOC 容器源碼分析 - 循環依賴的解決辦法 |
2018-06-11 | Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對象 |
2018-06-11 | Spring IOC 容器源碼分析 - 餘下的初始化工做 |
更新時間 | 標題 |
---|---|
2018-06-17 | Spring AOP 源碼分析系列文章導讀 |
2018-06-20 | Spring AOP 源碼分析 - 篩選合適的通知器 |
2018-06-20 | Spring AOP 源碼分析 - 建立代理對象 |
2018-06-22 | Spring AOP 源碼分析 - 攔截器鏈的執行過程 |
更新時間 | 標題 |
---|---|
2018-06-29 | Spring MVC 原理探祕 - 一個請求的旅行過程 |
2018-06-30 | Spring MVC 原理探祕 - 容器的建立過程 |
本文在知識共享許可協議 4.0 下發布,轉載需在明顯位置處註明出處
做者:田小波
本文同步發佈在個人我的博客:http://www.tianxiaobo.com
本做品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。