點選上方“Java技術驛站”,選擇“置頂公眾號”。
有內涵、有價值的文章第一時間送達!
精品專欄
前面歷經千辛萬苦終於到達解析 bean 標簽步驟來了,解析 bean 標簽的過程其實就是構造一個 BeanDefinition 物件的過程,
元素標簽擁有的配置屬性,BeanDefinition 均提供了相應的屬性,與之一一對應。所以我們有必要對 BeanDefinition 有一個整體的認識。
BeanDefinition
BeanDefinition 是一個介面,它描述了一個 Bean 實體,包括屬性值、構造方法值和繼承自它的類的更多資訊。它繼承 AttributeAccessor 和 BeanMetadataElement 介面。兩個介面定義如下:
-
AttributeAccessor :定義了與其它物件的(元資料)進行連線和訪問的約定,即對屬性的修改,包括獲取、設定、刪除。
-
BeanMetadataElement:Bean 元物件持有的配置元素可以透過
getSource()
方法來獲取。
BeanDefinition 整個結構如下圖:
我們常用的三個實現類有:ChildBeanDefinition、GenericBeanDefinition、RootBeanDefinition,三者都繼承 AbstractBeanDefinition。如果配置檔案中定義了父
和 子
,則父
用 RootBeanDefinition表示,子
用 ChildBeanDefinition 表示,而沒有父
的就使用RootBeanDefinition 表示。GenericBeanDefinition 為一站式服務類。AbstractBeanDefinition對三個子類共同的類資訊進行抽象。
解析 Bean 標簽
在 BeanDefinitionParserDelegate.parseBeanDefinitionElement()
中完成 Bean 的解析,傳回的是一個已經完成對
標簽解析的 BeanDefinition 實體。在該方法內部,首先呼叫 createBeanDefinition()
方法建立一個用於承載屬性的 GenericBeanDefinition 實體,如下:
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
委託 BeanDefinitionReaderUtils 建立,如下:
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
該方法主要是設定 parentName 、className、classLoader。
建立完 GenericBeanDefinition 實體後,再呼叫 parseBeanDefinitionAttributes()
,該方法將建立好的 GenericBeanDefinition 實體當做引數,對 Bean 標簽的所有屬性進行解析,如下:
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析 scope 標簽
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
// 解析 abstract 標簽
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 解析 lazy-init 標簽
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// 解析 autowire 標簽
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// 解析 depends-on 標簽
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// 解析 autowire-candidate 標簽
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
// 解析 primay 標簽
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
// 解析 init-method 標簽
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
bd.setInitMethodName(initMethodName);
}
else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 解析 destroy-mothod 標簽
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
// 解析 factory-method 標簽
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
從上面程式碼我們可以清晰地看到對 Bean 標簽屬性的解析,這些屬性我們在工作中都或多或少用到過。
完成 Bean 標簽基本屬性解析後,會依次呼叫 parseMetaElements()
、 parseLookupOverrideSubElements()
、 parseReplacedMethodSubElements()
對子元素 meta、lookup-method、replace-method 完成解析。下篇博文將會對這三個子元素進行詳細說明。
【死磕 Spring】----- IOC 之 獲取 Document 物件
【死磕 Spring】----- IOC 之 註冊 BeanDefinition
【死磕 Spring】----- IOC 之 Spring 統一資源載入策略
【死磕 Spring】----- IOC 之深入理解 Spring IoC
END