Spring IOC 容器提供了兩種管理Bean依賴關系的方式:
- 顯式管理:通過BeanDefinition的屬性值和構造方法實作Bean依賴關系管理,
- autowiring: Spring IOC 容器的依賴自動裝配功能,不需要對Bean屬性的依賴關系做顯式的宣告,只需要在配置好 autowiring 屬性,IOC 容器會自動使用反射查找屬性的型別和名稱,然后基于屬性的型別或者名稱來自動匹配容器中管理的Bean,從而自動地完成依賴注入,
通過對 autowiring 自動裝配特性的理解,我們知道容器對Bean的自動裝配發生在容器對Bean依賴注入的程序中,
在前面幾篇對 Spring IOC 容器的依賴注入程序原始碼分析中,我們已經知道了容器對Bean實體物件的屬性注入的處理發生在 AbstractAutoWireCapableBeanFactory 類中的 populateBean()方法中,我們通程序式流程分析autowiring的實作原理:
1.AbstractAutoWireCapableBeanFactory 對Bean實體進行屬性依賴注入
應用第一次通過getBean()方法(配置了 lazy-init預實體化屬性的除外)向IOC 容器索取 Bean時,容器創建 Bean 實體物件,并且對 Bean 實體物件進行屬性依賴注入 ,AbstractAutoWireCapableBeanFactory 的 populateBean()方法就是實作 Bean 屬性依賴注入的功能,其主要原始碼如下:
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;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set.
// This can be used, for example,to support styles of field injection.
boolean continueWithPropertyPopulation = true;
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;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// 獲取容器在決議Bean定義資源時為BeanDefiniton中設定的屬性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 對依賴注入處理,首先處理autowiring自動裝配的依賴注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME
|| mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根據Bean名稱進行autowiring自動裝配處理
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 根據Bean型別進行autowiring自動裝配處理
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 對非autowiring的屬性進行依賴注入處理
...
2.Spring IOC容器根據Bean名稱或者型別進行autowiring自動依賴注入
// 根據型別對屬性進行自動依賴注入
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);
// 對Bean物件中非簡單屬性(不是簡單繼承的物件,如8中原始型別,字符URL等都是簡單屬性)進行處理
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
// 獲取指定屬性名稱的屬性描述器
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
// 不對Object型別的屬性進行autowiring自動依賴注入
if (Object.class != pd.getPropertyType()) {
// 獲取屬性的setter方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
// 檢查指定型別是否可以被轉換為目標物件的型別
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
// 創建一個要被注入的依賴描述
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 根據容器的Bean定義決議依賴關系,回傳所有要被注入的Bean物件
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 為屬性賦值所參考的物件
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 指定名稱屬性注冊依賴Bean名稱,進行屬性依賴注入
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);
}
}
}
通過上面的原始碼分析,我們可以看出來通過屬性名進行自動依賴注入的相對比通過屬性型別進行自動依賴注入要稍微簡單一些,但是真正實作屬性注入的是DefaultSingletonBeanRegistry 類的 registerDependentBean() 方法,
3.DefaultSingletonBeanRegistry 的registerDependentBean()方法對屬性注入
// 為指定的Bean注入依賴的Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
// A quick check for an existing entry upfront, avoiding synchronization...
// 處理Bean名稱,將別名轉換為規范的Bean名稱
String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
return;
}
// No entry yet -> fully synchronized manipulation of the dependentBeans Set
// 多執行緒同步,保證容器內資料的一致性
// 先從容器中:bean名稱-->全部依賴Bean名稱集合找查找給定名稱Bean的依賴Bean
synchronized (this.dependentBeanMap) {
// 獲取給定名稱Bean的所有依賴Bean名稱
dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
// 為Bean設定依賴Bean資訊
dependentBeans = new LinkedHashSet<>(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
// 向容器中:bean名稱-->全部依賴Bean名稱集合添加Bean的依賴資訊
// 即,將Bean所依賴的Bean添加到容器的集合中
dependentBeans.add(dependentBeanName);
}
// 從容器中:bean名稱-->指定名稱Bean的依賴Bean集合找查找給定名稱Bean的依賴Bean
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet<>(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
// 向容器中:bean名稱-->指定Bean的依賴Bean名稱集合添加Bean的依賴資訊
// 即,將Bean所依賴的Bean添加到容器的集合中
dependenciesForBean.add(canonicalName);
}
}
通過對autowiring的原始碼分析,我們可以看出,autowiring的實作程序:
- 對Bean的屬性代呼叫getBean()方法,完成依賴Bean的初始化和依賴注入,
- 將依賴Bean的屬性參考設定到被依賴的Bean屬性上,
- 將依賴Bean的名稱和被依賴Bean的名稱存盤在IOC 容器的集合中,
SpringIOC 容器的 autowiring 屬性自動依賴注入是一個很方便的特性,可以簡化開發時的配置,但是凡是都有兩面性,自動屬性依賴注入也有不足,
首先,Bean的依賴關系在 組態檔中無法很清楚地看出來,對于維護造成一定困難,其次,由于自動依賴注入是 Spring容器自動執行的,容器是不會智能判斷的,如果配置不當,將會帶來無法預料的后果,所以自動依賴注入特性在使用時還是綜合考慮,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/262078.html
標籤:其他
