回顾
前面两节已经看完了对一个Bean标签的解析了,至此一个完整的GenericBeanDefinition就诞生了,完成了从XML文档到GenericBeanDefinition的转换,现在XML的所有配置,我们都可以从GenericBeanDefinition中找到对应的配置
但其实,GenericBeanDefinition只是一个子类而已,大多数的实现细节还是在AbstractBeanDefinition里面,就好像前面看到的,对于标签对应的实体类存储,存储容器都是在AbstractBeanDefinition里面的
下面就来看看AbstractBeanDefinition的功能吧
AbstractBeanDefinition
BeanDefinition重点在于其成员变量,大多数的方法都是对成员变量进行操作的,下面就来看下AbstractBeanDefinition的成员变量
//bean的作用范围,对应属性为bean标签的scope
public static final String SCOPE_DEFAULT = "";
//bean是否自动注入
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
//bean自动注入的方式为byName
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
//bean自动注入的方式为byType
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
//bean通过构造器进行自动注入
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
/**
* Constant that indicates determining an appropriate autowire strategy
* through introspection of the bean class.
* @see #setAutowireMode
* @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
* use annotation-based autowiring for clearer demarcation of autowiring needs.
*/
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
/**
* Constant that indicates no dependency check at all.
* @see #setDependencyCheck
*/
public static final int DEPENDENCY_CHECK_NONE = 0;
/**
* Constant that indicates dependency checking for object references.
* @see #setDependencyCheck
*/
public static final int DEPENDENCY_CHECK_OBJECTS = 1;
/**
* Constant that indicates dependency checking for "simple" properties.
* @see #setDependencyCheck
* @see org.springframework.beans.BeanUtils#isSimpleProperty
*/
public static final int DEPENDENCY_CHECK_SIMPLE = 2;
/**
* Constant that indicates dependency checking for all properties
* (object references as well as "simple" properties).
* @see #setDependencyCheck
*/
public static final int DEPENDENCY_CHECK_ALL = 3;
/**
* Constant that indicates the container should attempt to infer the
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
* explicit specification of a method name. The value {@value} is specifically
* designed to include characters otherwise illegal in a method name, ensuring
* no possibility of collisions with legitimately named methods having the same
* name.
* <p>Currently, the method names detected during destroy method inference
* are "close" and "shutdown", if present on the specific bean class.
*/
public static final String INFER_METHOD = "(inferred)";
@Nullable
private volatile Object beanClass;
//bean的作用范围
@Nullable
private String scope = SCOPE_DEFAULT;
//bean是不是一个抽象bean,对应属性abstract
private boolean abstractFlag = false;
//bean是不是延迟加载,对应属性lazy-init
@Nullable
private Boolean lazyInit;
//bean的自动注入模式,对应autowire
private int autowireMode = AUTOWIRE_NO;
//依赖进行检查(3.0放弃了该功能)
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
//实例化该bean是否需要先实例化其他一些bean,对应bean的depend-on属性
@Nullable
private String[] dependsOn;
//该bean是否考虑被当为候选bean,只有被当为候选bean,才能被注入
private boolean autowireCandidate = true;
//当出现多个bean当候选者时,该属性为true会被优先考虑当候选者
private boolean primary = false;
//存取Qualifier标签对象
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
//
@Nullable
private Supplier<?> instanceSupplier;
//允许访问非公开的构造器和方法,后面反射需要用到
private boolean nonPublicAccessAllowed = true;
//是否以宽松模式去解析构造函数
private boolean lenientConstructorResolution = true;
//bean工厂的名字
@Nullable
private String factoryBeanName;
//bean工厂的方法名字
@Nullable
private String factoryMethodName;
//记录construct-arg标签对象的,即构造函数给的参数
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//记录property标签的
@Nullable
private MutablePropertyValues propertyValues;
//记录lookup-method、replaced-method标签的
private MethodOverrides methodOverrides = new MethodOverrides();
//初始化bean的方法,对应bean的init-method,即创建bean时就会调用
@Nullable
private String initMethodName;
//销毁Bean的方法,即bean的生命周期过了之后会调用的方法
@Nullable
private String destroyMethodName;
//是否执行init-method
private boolean enforceInitMethod = true;
//是否执行destiry-method
private boolean enforceDestroyMethod = true;
//标明该bean是用户定义的,还是程序本身定义的
private boolean synthetic = false;
//
private int role = BeanDefinition.ROLE_APPLICATION;
//bean的描述信息
@Nullable
private String description;
//bean的资源来源,也就是XML文件
@Nullable
private Resource resource;
下一步:对创建的BeanDefinition进行修饰
现在我们已经解析完XML,并且产生了BeanDefinition对象了,但这一大串的逻辑仅仅只是转换成功而已,还没有进行注册了,现在返回BeanDefinitionDocumentReader的processBeanDefinition里面
我们仅仅只是完成了bgHolder的创建,但还没有进行下面的修饰和注册了
从代码上可以看到,XML转换成BeanDefinition是由delegate(BeanDefinitionParserDelegate)去实现,然后对新建的BeanDefinition进行修饰,同样也是交给了delegate去做,而注册BeanDefinition的逻辑是交由BeanDefinitionReaderUtils去实现
为什么要进行修饰呢?下面来看一个场景
<bean id="test" class="test.Myclass">
<mybean:user username="abc"/>
</bean>
可以看到,这一段Bean的XML配置使用了自定义类型的解析
拓展:对于bean的解析分为两种类型
- 一种是默认类型的解析
- 另一种是自定义类型的解析
而上面的正是为自定义类型解析,前面已经基本上对bean标签做了默认的解析,但对于自定义类型的解析,要在哪里做呢?
这一切的逻辑都在下一行的代码执行的方法,decorateBeanDefinitionIfRequired
源码如下
注意这里,有一个参数为null了!
第三个参数其实是父类的bean,当对某个嵌套配置进行分析时,这里是需要传递父类的BeanDefinition的
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 记录解析了默认标签的bean
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
// 获取bean标签的所有属性
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.
//获取bean标签的所有子标签
NodeList children = ele.getChildNodes();
//遍历所有子标签
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
//如果当前的子标签
//并且如果子标签是一个XML标签的子标签
//就进行修饰
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
可以看到,这个方法对标签进行了修饰,分别修饰两个方面,并且修饰的方法是一样的!!!
- 属性
- 子标签
因为修饰方法是一样的,所以就不细分了
修饰子标签与属性
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
//获取标签的命名空间
String namespaceUri = getNamespaceURI(node);
//如果命名空间不为空,并且不是默认的命名空间,才进行下面处理
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
//根据命名空间找到对应的处理器
//命名空间决定了哪些标签能用
//因为可以通过命名空间找到那些标签的处理器
//有处理器才能使用标签
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//判断是否找到处理器
if (handler != null) {
//用处理器进行修饰
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
//修饰的结果不为空,返回结果
if (decorated != null) {
return decorated;
}
}
//如果找不到处理器且命名空间是spring的命名空间
//抛出错误,自定义的标签怎么可能使用sprinf的命名空间!!!
else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
//其他情况,即没有找到处理器,且又不是Spring的命名空间
//抛出错误,没有处理器可以解析XML标签
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;
}
可以对于子标签和属性之所以可以一起处理,是因为对于子标签和属性,命名空间都有对应的处理器去处理,这里我们暂且将进来二点对象默认为子结点(属性与子标签),步骤如下
- 获取子节点的命名空间,如果没有命名空间或者命名空间为默认的命名空间,什么都不做
- 根据命名空间去获取处理器,利用处理器去处理子结点
- 如果获取不到处理器且命名空间为spring的命名空间,抛错,spring的命名空间不支持自定义标签解析!!!
- 如果获取不到处理器且命名空间也不为spring的,抛错,没有对应的命名空间来解析XML
总结一下
- decorateBeanDefinitionIfRequired是对自定义的子标签和属性进行处理的(对于程序默认的标签处理其实是直接略过的),底层修饰的细节为decorateIfRequired方法
- decorateIfRequired这个方法通过子标签的命名空间,去寻找处理器进行下一步解析