先回顾一下上一节讲到默认名称空间的解析,默认标签分为4中:import
、alias
、bean
、beans
本节将对bean标签的解析、修饰、注册进行讲解
当前阶段对应是流程图的 DOM树 -> beanDefinition -> beanDefinitionHolder -> register
// DefaultBeanDefinitionDocumentReader.java
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析import标签
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 解析alias标签
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 解析bean标签
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 解析beans标签,解析该标签实际是递归调用doRegisterBeanDefinitions,前面提到的parent
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
DOM树 -> beanDefinition
处理bean标签
processBeanDefinition
方法分成了3个步骤,1.解析并生成beanDefinition; 2.修饰beanDefinition; 3.注册beanDefinition
// DefaultBeanDefinitionDocumentReader.java
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/**
* 1.解析并生产BeanDefinitionHolder
* BeanDefinitionHolder跟beanDefinition没有本质区别,只不过更方便获取beanName、aliases
* BeanDefinitionHolder = beanName + aliases + beanDefinition
*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/**
* 2.字面意思是如果需要的话修饰beanDefinition,实际是为了处理默认标签下包含的自定义标签
* 因此可以看到ele参数一样需要被传递进去,而不是单纯的操作bdHolder
* <bean id="car" class="Car">
* <mybean:user username="chaitou">
* </bean>
*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 3.注册的核心逻辑,getReaderContext().getRegistry()中保存着所有注册过的beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
1. 解析并生成beanDefinition
①提取id,name,aliases
②剩下的所有属性解析交给parseBeanDefinitionElement处理,并把属性封装到GenericBeanDefinition实例中
③如果没有beanName,用默认规则生成一个
④将name,aliases,beanDefinition封装成beanDefinitionHolder并返回
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 1. 解析ID
String id = ele.getAttribute(ID_ATTRIBUTE);
// 解析name
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 解析别名
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
// 如果没有Id,则用第一个别名代替
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
// 通过usedNames判断beanName跟Aliases有没有被其他bean使用,如果被占用则报错,未被引用则将当前beanName添加到userNames中,用于后续判断
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 2. 解析各种属性及标签,并分装到GenericBeanDefinition实例中
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 3. 如果检测到beanName为空,则使用默认规则生产一个beanName
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
// 别名数组
String[] aliasesArray = StringUtils.toStringArray(aliases);
// 4. 返回beanDefinitionHolder,实际仅仅比beanDefinition多带了beanName,aliases属性,没有什么太大区别,方便获取
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
继续跟进第二点parseBeanDefinitionElement
// BeanDefinitionParserDelegate.java
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
// 标识当前bean正在解析状态
this.parseState.push(new BeanEntry(beanName));
// 解析class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建BeanDefinition,实际创建GenericBeanDefinition,BeanDefinition的集大成者,就是该会的方法都会的那种
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析元数据
parseMetaElements(ele, bd);
// 解析lookup-method属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析构造函数参数
parseConstructorArgElements(ele, bd);
// 解析property元素
parsePropertyElements(ele, bd);
// 解析qualifier元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
parseBeanDefinitionAttributes
基本上都是千篇一律的硬编码的解析,这里就不看了。
我们阅读下beanDefinition
的创建,以及挑一个解析lookup-method
属性(parseLookupOverrideSubElements
)
// BeanDefinitionParserDelegate.java
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
// BeanDefinition的一站式服务类,也就是集齐所有实现AbstractBeanDefinition的功能
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;
}
// BeanDefinitionParserDelegate.java
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
/**
* 解析<lookup-method> 标签
* 假设标签为<lookup-method name="getBean" bean="cat">
*/
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
Element ele = (Element) node;
// 解析name属性,即getBean
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
// 解析bean属性,即cat
String beanRef = ele.getAttribute(BEAN_ELEMENT);
// bean跟name将唯一定位一个方法的返回值将被哪一个bean替换
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
overrides.addOverride(override);
}
}
}
2. 修饰beanDefinition
/**
* 2.字面意思是如果需要的话修饰beanDefinition,实际是为了处理默认标签下包含的自定义标签
* 因此可以看到ele参数一样需要被传递进去,而不是单纯的操作bdHolder
* <bean id="car" class="Car">
* <mybean:user username="chaitou">
* </bean>
*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
解析bean的代码实在太多了,已经不知道执行到哪里,重新拉回来,目前执行到步骤2。当代码执行到这里,原始的beanDefinition
已经被创建出来了,但是他并不完美,当bean里面又嵌套了自定义标签时,默认名称空间的delegate是无法解析的,所以还需要一步装饰bdHolder,用来解析自定义标签
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
// 便利所有属性,如果有需要的话装饰属性
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// Decorate based on custom nested elements.
// 便利所有元素,如果有需要的话装饰元素
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取名称空间
String namespaceUri = getNamespaceURI(node);
// 默认名称空间的节点已经解析过,只有自定义名称空间才需要进行装饰
// 默认名称空间怎么判断?等于"http://www.springframework.org/schema/beans"就是默认名称空间
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 获取处理器,自定义名称空间需要自己override对应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
// 存在对应的处理器
if (handler != null) {
// 使用自定义处理器的decorate进行修饰,decorate同样是留给用户override的
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
3. 注册BeanDefinition
BeanDefinition
被封装成BeanDefinitionHolder
后,又经过修饰以后,已经成为了一个究极完美体的beanDefintion
了,他已经可以百分百定义一个bean
了。接下去需要做的事情就是将这些究极体的beanDefiniton
一起丢到一个Map
中,好让第二阶段getBean
时能够快速准确的创建出用户需要的bean
该部分的关键在2个Map:
beanDefinitionMap
: 用于保存所有的beanDefinition(key = beanName,value = beanDefinition)aliasMap
: 用于保存别名(key = alias,value = beanName)
假设有一个beanDefinition beanName = "myBean" alias = "IBean"
(以下是伪代码,只是为了举例说明)
当我们需要通过alias = "IBean"
查找该beanDefinition
时,spring会beanName = aliasMap.get("IBean")
,再用beanDefinition = beanDefinitionMap.get(beanName)
获取到对应的beanDefinition
// 3.注册的核心逻辑,getReaderContext().getRegistry()中保存着所有注册过的beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
// BeanDefinitionReaderUtils.java
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 注册key = beanName, value = beanDefinition
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// 注册别名key = alias, value = beanName
// 方便通过别名找到beanName,再通过beanName找到对于的beanDefinition
String[] aliases = definitionHolder.getAliases();//- 注册别名
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
- 注册
beanDefinition
其实注册的操作很简单,关键语句就2句:
// 注册,实际就是加入map中,这就是代码的核心
this.beanDefinitionMap.put(beanName, beanDefinition);
// 该list保存着所有已经注册的的beanName
this.beanDefinitionNames.add(beanName);
但是spring还是做了大量的工作:
① 做注册前校验
② 如果beanName已经存在,判断是否能覆盖,当然还做了很多日志log
③ 如果不存在直接注册
// DefaultListableBeanFactory.java
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 {
// 注册前做一次校验,主要针对methodOverrides,检测看看是否存在这个方法或是否有冲突
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 获取看看当前beanName是不是已经存在,不存在的直接注册,存在的看看允不允许覆盖
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 检测当前beanName是否已经存在
if (existingDefinition != null) {
// 已经存在,又不允许覆盖则跑出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
...
}
// 覆盖
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 检测当前程序处于那个阶段,解析注册阶段?还是已经有Bean被初始化创建阶段?
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
/**
* 这段代码是4.2之后才出现的
* 注释的意思是:程序已经有bean被实例化,也就是已经过了启动注册阶段,为了list的稳定迭代,无论如何不允许修改beanDefinitionNames集合
*
* 由于ArrayList是线程不安全的,使用ArrayList.put方法需要完成2个步骤
* 1.插入 2.修改size的值
* 为了保证线程安全,spring使用updatedDefinitions来更新
*
* 如果不这么做会造成什么后果暂时未查到相关文档,待补充 TODO
*/
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;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
// 仍然处在spring启动注册阶段,即未有bean被实例化
// 注册,实际就是加入map中,这就是代码的核心
this.beanDefinitionMap.put(beanName, beanDefinition);
// 该list保存着所有已经注册的的beanName
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置所有beanName对应的缓存(当然只有单例情况才会缓存)
resetBeanDefinition(beanName);
}
}
- 注册别名
核心代码也是就一句
// 注册别名 key = alias , value = beanName
this.aliasMap.put(alias, name);
// SimpleAliasRegistry
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时,删除别名
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
String registeredName = this.aliasMap.get(alias);
// 注册明已经存在
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
if (!allowAliasOverriding()) {
// 不允许覆盖则抛出异常
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// 别名的循环检测,例如A->B,再来一个A->C->B是不被允许的
checkForAliasCircle(name, alias);
// 注册别名 key = alias , value = beanName
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
至此已经完成了spring的第一阶段的阅读,也就是启动注册阶段。第二阶段便是拿着beanDefinition
的定义,按着定义上的要求,生产出用户所需要的bean