❝其實生活中的坑,都是本身挖的,迷茫也是。願咱們心裏堅決並且不失熱愛,期待與你的共同進步。java
❞
上一篇文章中,經過 createBeanInstance()
方法,最終獲得了 BeanWrapper
對象。再獲得這個對象以後,在Spring中,對於依賴 關係的處理,是經過 BeanWrapper
來完成的。web
這裏首先作一個區分,由於在以前的很長一段時間內,我都錯誤的覺得 @Autowired
就是自動裝配。這也就引起了我一直錯誤的任務Spring的自動 裝配首先是 byType
而後是 byName
的。經過這段時間對於源碼的閱讀,我才意識到這個錯誤。緩存
當涉及到自動裝配Bean的依賴關係時,Spring提供了4種自動裝配策略。app
public interface AutowireCapableBeanFactory{
//無需自動裝配 int AUTOWIRE_NO = 0; //按名稱自動裝配bean屬性 int AUTOWIRE_BY_NAME = 1; //按類型自動裝配bean屬性 int AUTOWIRE_BY_TYPE = 2; //按構造器自動裝配 int AUTOWIRE_CONSTRUCTOR = 3; //過期方法,Spring3.0以後再也不支持 @Deprecated int AUTOWIRE_AUTODETECT = 4; ... } 複製代碼
在 xml
中定義 Bean
的時候,能夠經過以下的方式指定自動裝配的類型。編輯器
<bean id="demoServiceOne" class="DemoServiceOne" autowire="byName"/>
複製代碼
<bean id="userService" class="UserService" autowire="byType"/>
複製代碼
<bean id="user" class="User" autowire="constructor"></bean>
複製代碼
若是使用了根據類型來自動裝配,那麼在IOC容器中只能有一個這樣的類型,不然就會報錯!函數
@Autowired
註解,它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做。Spring是經過 @Autowired
來實現自動裝配的。 固然,Spring還支持其餘的方式來實現自動裝配,如:「JSR-330的@Inject註解」、「JSR-250的@Resource註解」。源碼分析
經過註解的方式來自動裝配 Bean
的屬性,它容許更細粒度的自動裝配,咱們能夠選擇性的標註某一個屬性來對其應用自動裝配。post
在這篇文章中,我將詳細的分析,在一個對象中經過 @Autowired
注入或 @Resource
注入屬性的處理過程。這裏我仍是採起使用情形,而後畫出簡要 流程圖,最後再是源碼分析的方式來介紹本文所要涉及的知識點。flex
「情形一」:經過 @Autowired
註解對象的方式ui
@Service
public class DemoServiceTwo { @Autowired DemoServiceThree demoServiceThree; } 複製代碼
「情形二」:經過 @Autowired
註解構造器的方式
@Service
public class DemoServiceTwo { DemoServiceOne demoServiceOne; @Autowired public DemoServiceTwo(DemoServiceOne demoServiceOne){ this.demoServiceOne = demoServiceOne; } } 複製代碼
「情形三」:經過 @Resource
註解對象的方式
@Service
public class DemoServiceTwo { @Resource DemoServiceOne demoServiceOne; } 複製代碼
「情形四」:經過 @Autowired
註解方法的方式
@Service
public class DemoServiceTwo { DemoServiceOne demoServiceOne; @Autowired public void prepare(DemoServiceOne demoServiceOne){ this.demoServiceOne = demoServiceOne; } } 複製代碼
上述的四種方式是咱們在平常開發中常常用到的注入對象的方式。這四種方式,在 Spring 對應不一樣的處理邏輯。
上圖中描述了前面 「2.1」 中所介紹的四種情形的處理,其中藍色線條所表示的是 @Resource
註解的處理過程。
紅色線條表示 @Autowired
註解的處理過程,與之對應的有拆分紅三種子狀況
AutowiredFieldElement
表示註解屬性的狀況
AutowiredMethodElement
表示註解方法的狀況
經過上述流程圖,我從中找到了如下幾點。經過已下幾點咱們也能夠區分 @Resource
和 @Autowired
。
兩種註解的處理方式都是經過後置處理器來完成處理的,getBeanPostProcessors()
在咱們不作任何擴展的狀況下,Spring 中只有五個。若有忘記請查看:「容器初始化先發五虎」;
對於 @Resource
的處理是經過 CommonAnnotationBeanPostProcessor
來完成的。
對於 @Autowired
的處理是經過 AutowiredAnnotationBeanPostProcessor
來處理的。
對於 @Autowired
註解構造器的方式,獲取到被註解元素爲 null
則直接返回。完成 populateBean()
的過程。
對於剩下的情形,處理思路一致,都是先獲取到被注入的對象,而後將維護對象屬性之間的關係。
重點突出一下 getBean()
這裏仍是咱們熟悉的 getBean()
...
field.set()
維護對象之間的依賴關係。
源碼分析首當其衝的就是方法入口,在對象的包裝 BeanWrapper
建立完成以後,populateBean()
來處理對象之間的依賴關係:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. // 沒有任何屬性須要填充 return; } } if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; /** * InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation() 方法的應用 * 能夠控制程序是否進行屬性填充 */ if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } /** * 取得BeanDefinition 中設置的 Property值, * 這些property來自對BeanDefinition的解析, * 具體的過程能夠參看對載入個解析BeanDefinition的分析 * 這裏是Spring 內部設置的屬性值,通常不會設置 */ PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); /** * 處理自動裝配,xml的方式可能會有配置自動裝配類型的狀況 * 或者經過 setAutowireMode() 的方式設置自動裝配的模式 */ int resolvedAutowireMode = mbd.getResolvedAutowireMode(); // Spring 默認 既不是 byType 也不是 byName, 默認是null // 這裏之因此作這個判斷是由於某種特殊的場景下,會修改到自動注入的模型,因此須要作判斷 if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); /** * byName 處理 * 經過反射從當前Bean中獲得須要注入的屬性名, * 而後使用這個屬性名向容器申請與之同名的Bean, * 這樣實際又觸發了另外一個Bean生成和依賴注入的過程 */ if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // byType 處理 if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } // 後置處理器已經初始化 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); // 須要檢查依賴 boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); 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 (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } if (pvs != null) { // 對屬性進行注入 applyPropertyValues(beanName, mbd, bw, pvs); } } 複製代碼
經過源碼實現能夠看出「自動裝配」與「註解注入」的處理是有差異的。其中自動裝配時經過屬性判斷來完成。註解注入是經過「後置處理器」來完成的。
不一樣的後置處理器的postProcessProperties()
方法對應的是不一樣的處理邏輯。
首先,經過 findAutowiringMetadata()
方法獲取被注入的元數據。以上述:「情形一」,爲例:
而後,在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()) { // 循環被注入的元素,調用 inject 方法 for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } // 調用注入方法 element.inject(target, beanName, pvs); } } } 複製代碼
在這個方法中首先會檢查注入的對象,這裏須要指出,在 @Autowired
註解構造器的方式下,最終獲得的 elementsToIterate
是空。
對於@Autowired
註解的其餘使用方式,最終都會調用 element.inject(target, beanName, pvs);
能夠看出,這裏區分了註解方法與註解屬性這兩種方式,在本文中,將以註解 屬性的方式爲例繼續展開分析。
在 AutowiredFieldElement
中類中的最終經過 beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)
返回注入的對象,而後經過 field.set(bean, value);
的方式來維護對象與屬性之間的關係。
接下來將分析 resolveDependency()
方法,經過該方法能夠發現,最終調用的是 doResolveDependency()
。看到了 doXXXX()
的方法,就又到了 Spring 慣用的套路了,這裏這方法就是真正作事的方式。下面就來看看在 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; } /** * 根據類型獲取,@Autowired 默認根據type */ 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()); try { /** 經過轉換器將Bean的值轉換爲對應的type類型*/ return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... 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; } /** * 根據屬性類型找到beanFactory中全部類型匹配的Bean * 返回值的結構爲: * key:匹配的BeanName; * value:beanName 對應的實例化後的bean 經過 getBean(beanName)返回 */ Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { /** * 若是 autowire 的 require 屬性爲true * 找到的匹配項爲空 則 拋出異常 */ if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; // 根據類型匹配到的數量大於 1個 if (matchingBeans.size() > 1) { // 肯定自動注入的beanName autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { 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(); } 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); } } 複製代碼
分析上述代碼,能夠發現其中主要作了以下的幾件事:
①:獲取注入對象的類型;
②:解析過程當中對 @value
註解支持;
③:經過 findAutowireCandidates()
方法,根據屬性類型找到 BeanFactory
中全部類型匹配的 Bean
。存放在 Map
中返回。在該方法中,會根據給定的類型獲取全部 Bean
的名稱做爲 Map
中的 key
。
對類型匹配的 Bean
作相應的判斷,若是大於 1 個,則經過 determineAutowireCandidate()
方法來肯定注入 Bean
的名稱。
@Primary
註解的對象來肯定,若是有則返回;
@Priority
註解的對象,若是有則返回。
若是等於 1 個,在返回 Map
中的 key
就是 beanName
;
經過上述的描述發現 @Autowired
註解屬性的方式先經過 byType
的方式獲取對應類型的對象;當對應類型的對象大於 1 個時,經過 byName
的方式來肯定。
④:最後 descriptor.resolveCandidate(autowiredBeanName, type, this);
經過 beanFactory.getBean(beanName);
獲取注入的對象。
在經過 beanFactory.resolveDependency()
方法得到依賴的對象以後,經過 registerDependentBeans()
方法來維護對象之間的依賴關係。
private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) {
if (beanName != null) { for (String autowiredBeanName : autowiredBeanNames) { if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); } if (logger.isTraceEnabled()) { logger.trace("Autowiring by type from bean name '" + beanName + "' to bean named '" + autowiredBeanName + "'"); } } } } 複製代碼
上述代碼中 for
循環全部 @Autowired
注入的屬性的名稱。判斷容器中包含 BeanName
而後調用 this.beanFactory.registerDependentBean(autowiredBeanName, beanName)
。Spring
經過下述的方法來維護了對象之間的依賴關係。
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName); /** * dependentBeanMap中存儲的是目前已經註冊的依賴這個bean的全部bean, * 這裏從這個集合中獲取目前全部已經註冊的依賴beanName的bean集合, * 而後看這個集合中是否包含dependentBeanName,便是否已經註冊, * 若是包含則表示已經註冊,則直接返回; * 不然,將bean依賴關係添加到兩個map緩存即完成註冊. */ synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } } 複製代碼
上述的代碼中,有兩個 Map
。這裏首先對這兩個 Map
稍加解釋:
/** 指定的bean與目前已經註冊的依賴這個指定的bean的全部依賴關係的緩存(我依賴的)*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** 指定bean與目前已經註冊的建立這個bean所需依賴的全部bean的依賴關係的緩存(依賴個人) */ private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); 複製代碼
在上述的方法中,就是經過上述兩個 Map
維護了對象間依賴與被依賴的關係,詳細看下圖 當前的 Bean
是 demoServiceTwo
注入的對象是 demoServiceThree
。結合這個能夠對上面的 Map
有一個更直觀的理解。
最後提醒一點,這兩個 Map
中保存容器中全部對象之間的關係,直到容器被銷燬的時候刪除掉。
前面介紹過,經過 @Autowired
註解構造器的方式,在 populateBean()
方法中,經過後置處理器來處理時,獲取到的被注入的元素爲空,所以直接返回。也就是說這裏並無維護對象之間的依賴關係。可是對象和屬性之間的依賴關係,在經過構造器實例化對象的時候已經依賴好了。我本身的理解就是 java
對象和對象屬性之間的關係已經有了。
本文主要介紹了 Spring 中對象之間依賴關係的處理流程。經過流程圖的方式,粗略的看了一下 @Resource
和 @Autowired
註解處理的過程。
本文詳細介紹了 @Autowired
註解屬性的處理過程、java
對象與屬性關係的維護以及 Spring
對象之間的依賴關係的維護。
簡單介紹了 @Autowired
註解構造器的處理構成。
關於 @Resource
註解與 @Autowired
註解方法的處理過程,後面有機會在詳細分析。
本文使用 mdnice 排版