一、整体脉络
Spring中每个bean实例,都有一个对应的BeanDefinition实例。这个BeanDefinition实例记录了该bean的各种属性信息,如id、scope等等。先来看一份xml中bean标签的配置
<bean id="person" class="com.kaka.spring.beans.Person">
<property name="age" value="22"/>
</bean>
要把上面的bean标签中的内容,解析为一个BeanDefinition对象,spring做了三个步骤:
- 创建BeanDefinition实例
- 解析bean标签上的属性,并存储到BeanDefinition实例中
- 解析bean标签的子元素,并存储到BeanDefinition实例中
本章主要分析第3个步骤,bean标签有六个子元素:meta、lookup-method、replaced-method、constructor-arg、property、qualifier;本章分析除constructor-arg之外的其他五个子元素,constructor-arg子元素较为复杂,后面会单独写一篇文章解析。
二、相关类、方法
- org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions:解析xml的入口,该方法循环解析beans标签的各个子元素,如bean、import等
- org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition:处理beanDefinition的整体过程,包含bean标签的解析、注册、通知监听器等。
- org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition):解析bean标签中的属性和子元素
三、源码分析
解析bean标签的整体过程,在BeanDefinitionParserDelegate这个类的parseBeanDefinitionElement()方法中,先来看下代码
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
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 {
// 1.创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition,点进去
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 2.硬编码解析默认bean的各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 3.解析子元素
// 3.1 解析元数据
parseMetaElements(ele, bd);
// 3.2 解析lookup-method 属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 3.3 解析replaced-method 属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 3.4 解析构造函数参数
parseConstructorArgElements(ele, bd);
// 3.5 解析property子元素
parsePropertyElements(ele, bd);
// 3.6 解析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;
}
- 解析元数据
1.1 源码分析
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
// 获取当前节点的所有子元素
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 解析meta子元素
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
// 使用meta元素的key和value构造BeanMetadataAttribute 对象
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
// 把该attribute保存到AttributeAccessorSupport的attributes(是一个LinkedHashMap)属性中
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
1.2 使用方法
在bean标签中增加meta标签
<bean id="metaPerson" class="com.kaka.spring.pojo.Person">
<property name="age" value="22"/>
<meta key="myMeta" value="元数据"/>
</bean>
代码使用
@Before
public void initFactory(){
Resource classPathResource = new ClassPathResource("applicationContext.xml");
xmlBeanFactory = new XmlBeanFactory(classPathResource);
}
@Test
public void metaDataTest(){
BeanDefinition beanDefinition = ((XmlBeanFactory) xmlBeanFactory).getBeanDefinition("metaPerson");
// 通过getAttribute()方法就能获取到xml中meta标签中的值
Object myMeta = beanDefinition.getAttribute("myMeta");
System.out.println(myMeta);
}
- 解析lookup-method 属性
2.1 源码分析
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
Element ele = (Element) node;
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
String beanRef = ele.getAttribute(BEAN_ELEMENT);
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
// 把override实例存入AbstractBeanDefinition的methodOverrides属性中
overrides.addOverride(override);
}
}
}
2.2 使用方法
lookup-method标签的作用:一个A类型的bean中的某个方法的方法声明,返回值为B类型的bean,lookup-method标签就可以修饰该方法,来指定该方法的返回值为容器中某个B类型的bean。(AB可以是同一个类型)
2.2.1 声明一个接口和两个实现类
public interface Animal {
void say();
}
public class Cat implements Animal {
@Override
public void say() {
System.out.println("喵喵...");
}
}
public class Dog implements Animal {
@Override
public void say() {
System.out.println("汪汪");
}
}
2.2.3 声明一个类,该类包含一个方法声明的返回值为Animal
public abstract class AbstractMethodBean {
// xml中使用lookup-method标签修饰该方法
public abstract Animal getAnimalBean();
public void printSay() {
getAnimalBean().say();
}
}
2.2.4 配置文件声明lookup-method标签
<bean id="cat" class="com.kaka.spring.pojo.Cat"/>
<bean id="abstractMethodBean" class="com.kaka.spring.pojo.AbstractMethodBean">
<lookup-method name="getAnimalBean" bean="cat"/>
</bean>
此时abstractMethodBean这个bean的getAnimalBean()方法的返回值为cat实例;如需修改为dog,修改lookup-method标签中的bean属性值指向容器中的dog即可。
- 解析replaced-method 属性
3.1 源码分析
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
Element replacedMethodEle = (Element) node;
// 获取要替换的方法名
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
// 获取MethodReplacer类型的bean
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
// 创建replaceOverride 实例
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
// Look for arg-type match elements.
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
for (Element argTypeEle : argTypeEles) {
String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
if (StringUtils.hasText(match)) {
replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(extractSource(replacedMethodEle));
// 把replaceOverride实例存入AbstractBeanDefinition的methodOverrides属性中
overrides.addOverride(replaceOverride);
}
}
}
3.2 使用方法
3.2.1 创建一个MethodReplacer 类型的类和一个Dog普通类
public class ReplaceMethodBean implements MethodReplacer {
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("我是一个汪星人...");
return null;
}
}
public class Dog implements Animal {
@Override
public void say() {
System.out.println("汪汪");
}
}
3.2.2 xml配置修改dog类中的say方法,当调用dog的say()方法时,就回转到replaceMethodBean的reimplement()方法。
<bean id="replaceMethodBean" class="com.kaka.spring.pojo.ReplaceMethodBean"/>
<bean id="dog" class="com.kaka.spring.pojo.Dog">
<replaced-method name="say" replacer="replaceMethodBean"/>
</bean>
- 解析property子元素
4.1 源码分析
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 获取property节点的name值
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 不允许多次对同一属性配置
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 解析property节点的value值(property元素可能还包含子元素)
Object val = parsePropertyValue(ele, bd, propertyName);
// 创建PropertyValue 实例承载property节点对应的信息
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
// 把PropertyValue 实例保存至AbstractBeanDefinition的propertyValues
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
- 解析qualifier子元素
5.1 源码分析
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
parseQualifierElement((Element) node, bd);
}
}
}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
if (!StringUtils.hasLength(typeName)) {
error("Tag 'qualifier' must have a 'type' attribute", ele);
return;
}
this.parseState.push(new QualifierEntry(typeName));
try {
// 创建qualifier 实例
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
qualifier.setSource(extractSource(ele));
// 获取qualifier的value值
String value = ele.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(value)) {
qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
}
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 处理qualifier的子元素:attribute节点
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
Element attributeEle = (Element) node;
String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
// 创建attribute 实例来承载attribute节点的信息
BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
attribute.setSource(extractSource(attributeEle));
// 把attribute保存至AttributeAccessorSupport的attribute中
qualifier.addMetadataAttribute(attribute);
}
else {
error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
return;
}
}
}
// 保存qualifier对象
bd.addQualifier(qualifier);
}
finally {
this.parseState.pop();
}
}