上一篇文章講到了標簽在 parseDefaultElement 方法中進行解析,本篇文章將講解這部分內容 bean 標簽解析 查看 processBeanDefinition 方法,針對各個操作作具體分析: protected void processBeanDefinition(Element e ...
上一篇文章講到了標簽在 parseDefaultElement 方法中進行解析,本篇文章將講解這部分內容
bean 標簽解析
查看 processBeanDefinition 方法,針對各個操作作具體分析:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 1.解析 BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
1. 解析 BeanDefinition
首先從元素解析及信息提取開始,進入 parseBeanDefinitionElement 方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 1.1 解析id屬性
String id = ele.getAttribute("id");
// 1.2 解析name屬性
String nameAttr = ele.getAttribute("name");
List<String> aliases = new ArrayList();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
this.checkNameUniqueness(beanName, aliases, ele);
}
// 2. 解析其他屬性
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
// 3. 如果不存在beanName就根據Spring提供的命名規則為當前bean生成對應的beanName
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 4. 封裝到 BeanDefinitionHolder 的實例
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}
該方法完成的主要工作包括以下內容:
- 提取元素中的 id 以及 name 屬性
- 進一步解析其他屬性並統一封裝至 GenericBeanDefinition 類型的實例中
- 如果檢測到 bean 沒有指定 beanName,那麼使用預設規則為此 Bean 生成 beanName
- 將獲取到的信息封裝到 BeanDefinitionHolder 的實例中
進一步查看步驟二對標簽的其他屬性的解析過程:
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 解析class屬性
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
// 解析parent屬性
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
try {
// 創建用於承載屬性的AbstractBeanDefinition類型的GenericBeanDefinition實例
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
// 硬編碼解析預設bean的各種屬性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 提取description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
// 解析元數據
this.parseMetaElements(ele, bd);
// 解析lookup-method屬性
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method屬性
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析構造函數參數
this.parseConstructorArgElements(ele, bd);
// 解析property子元素
this.parsePropertyElements(ele, bd);
// 解析qualifier子元素
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
AbstractBeanDefinition var7 = bd;
return var7;
} catch (ClassNotFoundException var13) {
this.error("Bean class [" + className + "] not found", ele, var13);
} catch (NoClassDefFoundError var14) {
this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
} catch (Throwable var15) {
this.error("Unexpected failure during bean definition parsing", ele, var15);
} finally {
this.parseState.pop();
}
return null;
}
接下來,我們繼續一些複雜標簽屬性的解析:
1.1 創建用於屬性承載的 BeanDefinition
BeanDefinition 是一個介面,在 Spring 中存在三種實現:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,三種實現類均繼承了 AbstractBeanDefinition
BeanDefinition 是配置文件 <bean> 元素標簽在容器中的內部表示形式,<bean> 標簽擁有 class、scope、lazy-init 等配置屬性,BeanDefinition 就提供了對應的 beanClass、scope、lazyInit 屬性
由此可見,要解析屬性首先要創建用於承載屬性的實例,也就是創建 GenericBeanDefinition 類型的實例,createBeanDefinition 方法的作用就是實現此功能
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) {
// 如果classLoader不為空,則使用傳入的classLoader載入對象
// 否則就只是記錄className
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
} else {
bd.setBeanClassName(className);
}
}
return bd;
}
2. 解析各種屬性
當我們創建了 bean 信息的承載實例後,便可以進行 bean 信息的各種屬性解析了,parseBeanDefinitionAttributes 方法是對 element 所有元素屬性進行解析:
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析scope屬性
if (ele.hasAttribute("singleton")) {
this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute("scope")) {
bd.setScope(ele.getAttribute("scope"));
} else if (containingBean != null) {
bd.setScope(containingBean.getScope());
}
// 解析singleton屬性
if (ele.hasAttribute("abstract")) {
bd.setAbstract("true".equals(ele.getAttribute("abstract")));
}
// 解析lazy-init屬性
String lazyInit = ele.getAttribute("lazy-init");
if (this.isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
// 若沒有設置或設置成其他字元都會被設置為false
bd.setLazyInit("true".equals(lazyInit));
String autowire = ele.getAttribute("autowire");
bd.setAutowireMode(this.getAutowireMode(autowire));
String autowireCandidate;
if (ele.hasAttribute("depends-on")) {
autowireCandidate = ele.getAttribute("depends-on");
bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
}
// 解析autowire屬性
autowireCandidate = ele.getAttribute("autowire-candidate");
String destroyMethodName;
if (this.isDefaultValue(autowireCandidate)) {
destroyMethodName = this.defaults.getAutowireCandidates();
if (destroyMethodName != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
} else {
bd.setAutowireCandidate("true".equals(autowireCandidate));
}
// 解析primary屬性
if (ele.hasAttribute("primary")) {
bd.setPrimary("true".equals(ele.getAttribute("primary")));
}
// 解析init-method屬性
if (ele.hasAttribute("init-method")) {
destroyMethodName = ele.getAttribute("init-method");
bd.setInitMethodName(destroyMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 解析destroy-method屬性
if (ele.hasAttribute("destroy-method")) {
destroyMethodName = ele.getAttribute("destroy-method");
bd.setDestroyMethodName(destroyMethodName);
} else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
// 解析factory-method屬性
if (ele.hasAttribute("factory-method")) {
bd.setFactoryMethodName(ele.getAttribute("factory-method"));
}
// 解析factory-bean屬性
if (ele.hasAttribute("factory-bean")) {
bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
}
return bd;
}
註冊解析的 BeanDefinition
得到 BeanDefinition 後,剩下的工作就是註冊了,也就是 processBeanDefinition 方法中的
registerBeanDefinition 方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 註冊解析的 BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 使用beanName做唯一標識註冊
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 註冊所有的別名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
解析的 beanDefinition 都會被註冊到 BeanDefinitionRegistry 類型的實例 registry 中,而對於 beanDefinition 的註冊分成兩個部分:通過 beanName 註冊以及通過別名註冊
1. 通過 beanName 註冊
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 註冊前的最後一次校驗
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var8) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
}
}
// 處理beanName已經註冊的情況
BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 如果對應BeanName已經註冊且在配置中配置了bean不允許被覆蓋,則拋出異常
if (!this.isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (!beanDefinition.equals(existingDefinition)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// 檢查工廠是否處於bean創建階段
if (this.hasBeanCreationStarted()) {
// 因為beanDefinitionMap是全局變數,會存在併發訪問的情況
synchronized(this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
this.removeManualSingletonName(beanName);
}
} else {
// 註冊beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 記錄beanName
this.beanDefinitionNames.add(beanName);
this.removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition == null && !this.containsSingleton(beanName)) {
if (this.isConfigurationFrozen()) {
this.clearByTypeCache();
}
} else {
this.resetBeanDefinition(beanName);
}
}
在對於 bean 的註冊處理方式上,主要進行了幾個步驟:
- 對 AbstractBeanDefinition 校驗
- 加入 map 緩存
- 清楚解析之前留下的對應的 beanName 的緩存
2. 通過別名註冊 BeanDefinition
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized(this.aliasMap) {
// 如果beanName和alias相同的話不記錄alias,並刪除對應的alias
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
} else {
String registeredName = (String)this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
return;
}
if (!this.allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'");
}
}
// 檢查是否存在迴圈指向,如A->B,A->C->B
this.checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
註冊 alias 的步驟如下:
- alias 與 beanName 相同情況處理
- alias 迴圈檢查
- 註冊 alias