当前位置 博文首页 > 刘博仁:spring源码学习笔记之容器的基本实现(一)
最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结、分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用.
建议与源码配合使用,效果更嘉,使用的spring版本为5.0.x: 官方源码下载 添加中文注解版源码
下面正文开始.
本文要分享的内容就是从读取配置文件到注册BeanDefinition的过程中spring到底做了怎样的处理.
下面是一个具体的代码示例,首先创建一个对象
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
第二步创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean >
</beans>
第三步创建测试用例
public class BeanFactoryTest (
@Test
public void testSirnpleLoad() {
BeanFactory bf = new XmlBeanFactory (new ClassPathResource ("beanFactoryTest.xml"));
MyTestBean bean=(MyTestBean) bf.getBean("myTestBean");
System.out.println(bean.getTestStr());
}
}
执行后会正确输出testStr.
本篇博客的重点就是关注下列代码到底做了什么
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
第一步通过ClassPathResource将xml文件转换为Resource对象.
new ClassPathResource("beanFactoryTest.xml")
这里不再赘述,直接进入XmlBeanFactory这个类.
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
这个类很简单继承了DefaultListableBeanFactory,有一个私有的成员变量XmlBeanDefinitionReader 和两个构造方法.
可以看出XmlBeanFactory类本身并没有复写父类的方法,XmlBeanFactory与其父类的区别就在于使用私有成员变量XmlBeanDefinitionReader去读取资源文件.
进入XmlBeanFactory的构造方法
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
有一点需要关注一下,就是在执行this.reader.loadBeanDefinitions(resource)前先调用了super(parentBeanFactory);
追踪这行代码进入了XmlBeanFactory的父类DefaultListableBeanFactory
/**
* Create a new DefaultListableBeanFactory with the given parent.
* @param parentBeanFactory the parent BeanFactory
*/
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
发现又是一个super(parentBeanFactory),继续追,又进入了DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory
/**
* Create a new AbstractAutowireCapableBeanFactory with the given parent.
* @param parentBeanFactory parent bean factory, or {@code null} if none
*/
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
现在追进去this()方法,我们需要关注的东西就是里面的ignoreDependencyInterface()方法
/**
* Create a new AbstractAutowireCapableBeanFactory.
*/
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
那么这个方法是做什么用的呢?
首先先明确一下这个方法实现的功能是什么,然后我们再追踪一下代码
ignoreDependencyInterface的主要功能是忽略给定接口的自动装配功能.
举例来说当A中有属性B.那么当Spring在获取A的Bean的时候如果其属性B还没有初始化,那么Spring 会自动初始化B,这也是Spring中提供的一个重要特性。但是,某些情况
下,B不会被初始化,其中的一种情况就是B实现了BeanNameAware接口
接下来看看源码部分是如何实现上述功能的
实现分为三个步骤:
第一步存入源码,直接追踪ignoreDependencyInterface()
/**
* Dependency interfaces to ignore on dependency check and autowire, as Set of
* Class objects. By default, only the BeanFactory interface is ignored.
*/
// set 专门存入需要需要过滤的类
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
/**
* Ignore the given dependency interface for autowiring.
* <p>This will typically be used by application contexts to register
* dependencies that are resolved in other ways, like BeanFactory through
* BeanFactoryAware or ApplicationContext through ApplicationContextAware.
* <p>By default, only the BeanFactoryAware interface is ignored.
* For further types to ignore, invoke this method for each type.
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.context.ApplicationContextAware
*/
public void ignoreDependencyInterface(Class<?> ifc) {
//放入集合
this.ignoredDependencyInterfaces.add(ifc);
}
将传入的值方法一个set集合(对就是ignoredDependencyInterfaces这个集合).
第二步过滤部分的源码
/**
* Return an array of non-simple bean properties that are unsatisfied.
* These are probably unsatisfied references to other beans in the
* factory. Does not include simple properties like primitives or Strings.
* @param mbd the merged bean definition the bean was created with
* @param bw the BeanWrapper the bean was created with
* @return an array of bean property names
* @see org.springframework.beans.BeanUtils#isSimpleProperty
*/
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
// 方法的第一个参数AbstractBeanDefinition mbd 可以理解为2.1.1举的例子类A
// 声明了一个集合
Set<String> result = new TreeSet<>();
// 拿到beanDefinition的所有属性
PropertyValues pvs = mbd.getPropertyValues();
// 得到属性的所有描述
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 这里遍历所有属性,可以理解为2.1.1举的例子属性B
// 过滤属性的方法在!isExcludedFromDependencyCheck(pd)
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
result.add(pd.getName());
}
}
// 最后返回过滤后的属性
return StringUtils.toStringArray(result);
}
通过源码我们知道了具体过滤的逻辑 !isExcludedFromDependencyCheck(pd) 在这个方法中,继续追踪
/**
* Determine whether the given bean property is excluded from dependency checks.
* <p>This implementation excludes properties defined by CGLIB and
* properties whose type matches an ignored dependency type or which
* are defined by an ignored dependency interface.
* @param pd the PropertyDescriptor of the bean property
* @return whether the bean property is excluded
* @see #ignoreDependencyType(Class)
* @see #ignoreDependencyInterface(Class)
*/
protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
// 这里使用了第一步存入的集合
AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
}
看条件 AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces),这里使用了我们第一步存入的集合,接近真相了,继续追踪
/**
* Return whether the setter method of the given bean property is defined
* in any of the given interfaces.
* @param pd the PropertyDescriptor of the bean property pd就是某个对象的一个属性
* @param interfaces the Set of interfaces (Class objects)
* @return whether the setter method is defined by an interface
*/
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) {
// 这里得到B的set方法
Method setter = pd.getWriteMethod();
// 如果set方法不为空
if (setter != null) {
/*
* getDeclaringClass
* 该方法返回一个Class对象,返回当前class对象的声明对象class,一般针对内部类的情况,比如A类有内部类B,那么通过B.class.getDeclaringClass()方法将获取到A的Class对象.
* 在使用反射对象时比如Method和Field的getDeclaringClass方法将获取到所属类对象
* */
// 所以这个targetClass 为所属类对象
// 这里得到了属性B的class
Class<?> targetClass = setter.getDeclaringClass();
for (Class<?> ifc : interfaces) {
// 判断 ifc 是否是属性B的父类(这里的ifc 则是第一步存入的接口)
// 如果 属性B继承了第一步存入的接口 并且 存入的接口也有相同的set方法,就会被过滤
if (ifc.isAssignableFrom(targetClass) &&
// 判断类是否有指定的public方法;
ClassUtils.hasMethod(ifc, setter.getName(), setter.getParameterTypes())) {
return true;
}
}
}
return false;
}
看到上面的代码我们明白了过滤属性的步骤:
最后是第三部分使用,使用过滤后的属性进行初始化
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 过滤后的属性是在这里使用的
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 过滤后的属性是在这里使用的
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
第二步过滤后的属性是用来注入属性的无论是通过name还是通过type注入. 经过一系列的追踪我们证实了2.1.1节的功能实现.
构造方法解释完毕了,进入正题,xmlBeanFactory使用私有成员变量XmlBeanDefinitionReader去加载资源
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
进入this.reader.loadBeanDefinitions(),发现创建了一个EncodedResource对象,传入loadBeanDefinitions()方法
/**
* Load bean definitions from the specified XML file.
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
进入loadBeanDefinitions(new EncodedResource(resource))方法
/**
* Load bean definitions from the specified XML file.
* @param encodedResource the resource descriptor for the XML file,
* allowing to specify an encoding to use for parsing the file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource);
}
// 获得当前正在加载的资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// 如果当前正在加载的资源已经拥有该元素,报循环加载的错误
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
这个方法主要做了两个操作: 1. 检测资源是否循环加载,如果是则抛出异常 2. 对inputSource设置编码.
继续往下追踪,进入doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法.
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 通过inputSource, resource获得文档对象
Document doc = doLoadDocument(inputSource, resource);
// 获取到document后注册BeanDefinition
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法通过inputSource、 resource获得了Document这个方法就不展开解释了,继续往下追踪进入了registerBeanDefinitions(doc, resource)
/**
* Register the bean definitions contained in the given DOM document.
* Called by {@code loadBeanDefinitions}.
* <p>Creates a new instance of the parser class and invokes
* {@code registerBeanDefinitions} on it.
* @param doc the DOM document
* @param resource the resource descriptor (for context information)
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of parsing errors
* @see #loadBeanDefinitions
* @see #setDocumentReaderClass
* @see BeanDefinitionDocumentReader#registerBeanDefinitions
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//1. 生成BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 返回注册列表中注册的bean的数量
int countBefore = getRegistry().getBeanDefinitionCount();
//2. 通过生成的BeanDefinitionDocumentReader注册beanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 这里返回的是新注册的bean的数量
//3. 返回最新的注册的bean的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
registerBeanDefinitions(Document doc, Resource resource)主要做了三件事:
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
DefaultBeanDefinitionDocumentReader.class;
/**
* Create the {@link BeanDefinitionDocumentReader} to use for actually
* reading bean definitions from an XML document.
* <p>The default implementation instantiates the specified "documentReaderClass".
* @see #setDocumentReaderClass
*/
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanUtils.instantiateClass(this.documentReaderClass);
}
可以看出这里生成的BeanDefinitionDocumentReader实际上是DefaultBeanDefinitionDocumentReader类型的
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
这里要留意一下createReaderContext(resource)方法
/**
* Create the {@link XmlReaderContext} to pass over to the document reader.
*/
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
注意第五个参数this,相当于把自己(XmlBeanDefinitionReader)也传递给了BeanDefinitionDocumentReader,方便后续调用
return getRegistry().getBeanDefinitionCount() - countBefore;
这里的getRegistry()是哪里来的,当时有点懵,找了一会才明白... 是这么来的
public class XmlBeanFactory extends DefaultListableBeanFactory {
// 看XmlBeanDefinitionReader构造方法的参数this
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
嗯... 答案就在XmlBeanDefinitionReader的构造方法中
/**
* Create new XmlBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
这里划重点,因为后续得到的BeanDefinition还需要使用registry(实际上是XmlBeanFactory)去注册BeanDefinition
XmlBeanDefinitionReader实现的功能到这里告一段落了, 进入下一个类DefaultBeanDefinitionDocumentReader
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
这个很简单没什么说的,通过document得到了Element,然后调用doRegisterBeanDefinitions(root)
/**
* Register each bean definition within the given root {@code <beans/>} element.
*/
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
// 对配置文件进行处理
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// 主要逻辑就是判断这个配置文件是否是允许存在,不存在则 return,不再浪费时间解析了
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
/*解析前处理,该方法为空实现*/
preProcessXml(root);
/*解析bean的定义*/
parseBeanDefinitions(root, this.delegate);
/*解析后处理,该方法为空实现*/
postProcessXml(root);
this.delegate = parent;
}
上述代码做了三件事:
<!-- 开发环境配置文件 -->
<beans profile="development">
<context:property-placeholder location="/WEB-INF/test-orm.properties" />
</beans>
<!-- 本地环境配置文件 -->
<beans profile="test">
<context:property-placeholder location="/WEB-INF/local-orm.properties" />
</beans>
<!--在web.xml中添加-->
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>development</param-value>
</context-param>
重点关注解析bean的定义parseBeanDefinitions(root, this.delegate)方法
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
*
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析默认标签
parseDefaultElement(ele, delegate);
} else {
// 解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
进入解析bean的定义parseBeanDefinitions(root, this.delegate)方法,可以看到这里进行了一个判断,判断这个element究竟是自定义标签还是默认标签,并且如果是默认标签的情况还会进行遍历,再次判断是自定义标签还是默认标签,说明了默认标签中有可能包含自定义标签.
那什么是默认标签? 什么是自定义标签?
默认标签是spring自己定义的,比如:
<bean >
自定义标签:
<tx:annotation-driven>
这两种标签的解析方式有很大的不同. 我们先追踪解析默认标签的方法
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标签
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
可以看到有四种默认标签,分别是: import标签(导入其他配置文件)、alias标签(设置别名)、bean标签、beans标签(嵌套的bean). 限于篇幅及重要程度,我们重点关注processBeanDefinition(ele, delegate)方法,理解了bean标签的解析相信其他三类标签也可以触类旁通.
进入processBeanDefinition(ele, delegate)方法
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/*
* 首先委托BeanDefinitionDelegate 类的parseBeanDefinitionElement 方法进行元素解析,
返回BeanDefinitionHolder 类型的实例bdHolder ,经过这个方法后,bdHolder 实例已经包含我
们配置文件中配置的各种属性了,例如class 、name、id 、alias 之类的属性
* */
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/*
* 当返回的bdHolder 不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要
再次对自定义标签进行解析
* */
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
/*
* 解析完成后,需要对解析后的bdHolder 进行注册,同样,注册操作委托给了
* BeanDefinitionReaderUtils的registerBeanDefinition方法
* */
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));
}
}