Spring之BeanDefinition创建过程源码解析

BeanFactory的具体实现为DefaultListableBeanFactory,下面是一个简单的小例子:

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions("applicationContext.xml");

TestInstance test = (TestInstance) factory.getBean("instance");
test.sayHello();

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="instance" class="com.zws.register.sever.TestInstance"></bean>
</beans>

从上面程序中可以看出类XmlBeanDefinitionReader的loadBeanDefinitions方法触发了BeanDefinition对象创建的过程,下面看下是如何创建BeanDefinition对象的。
XmlBeanDefinitionReader的方法registerBeanDefinitions(Document, Resource)会创建两个对象:BeanDefinitionDocumentReader和XmlReaderContext,源码如下:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

其中方法createBeanDefinitionDocumentReader()直接创建BeanDefinitionDocumentReader的子类DefaultBeanDefinitionDocumentReader返回,源码如下:

private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}

XmlReaderContext对象由方法createReaderContext()创建,源码如下:

public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
            this.sourceExtractor, this, getNamespaceHandlerResolver());
}

XmlReaderContext的构造函数接受一个NamespaceHandlerResolver类型的对象,此对象由方法getNamespaceHandlerResolver()创建,源码如下:

public NamespaceHandlerResolver getNamespaceHandlerResolver() {
    if (this.namespaceHandlerResolver == null) {
        this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
    }
    return this.namespaceHandlerResolver;
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
        return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
}

可以看到这里创建的是DefaultNamespaceHandlerResolver对象,此对象在构造函数里初始化了它的一个属性handlerMappingsLocation,此属性被设置成了默认的META-INF/spring.handlers,源码如下:

public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
    this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
    Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
    this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    this.handlerMappingsLocation = handlerMappingsLocation;
}

那么重点来了,META-INF/spring.handlers其实是jar包下的一个文件,spring默认会去读jar包的这个文件,这个文件记录了命名空间到NamespaceHandler的对应关系,例如下面是spring-beans-4.3.17.RELEASE.jar内该文件的内容:

http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler

所以如果想要定义自己的标签就可以在这里做手脚。接着调用DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element),此方法创建了BeanDefinitionParserDelegate对象,并且调用了BeanDefinitionParserDelegate对象的parseCustomElement()方法解析出了BeanDefinition对象。源代码如下:

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

这里的逻辑比较清晰了,首先根据Element解析出了namespaceUri,然后根据namespaceUri找到对应的NamespaceHandler,然后调用NamespaceHandler的parse()方法返回BeanDefinition对象。那么是如何做到的呢,还记得上面创建XmlReaderContext的时候顺便创建了DefaultNamespaceHandlerResolver对象么?那么这里的this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)其实调用的就是DefaultNamespaceHandlerResolver的resolve(namespaceUri)方法,此方法源码如下:

public NamespaceHandler resolve(String namespaceUri) {
    Map<String, Object> handlerMappings = getHandlerMappings();
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    }
    else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    }
    else {
        String className = (String) handlerOrClassName;
        try {
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                        "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            namespaceHandler.init();
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }
        catch (ClassNotFoundException ex) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
                    namespaceUri + "] not found", ex);
        }
        catch (LinkageError err) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
                    namespaceUri + "]: problem with handler class file or dependent class", err);
        }
    }
}

这个方法信息量很大,首先第一行通过调用getHandlerMappings()方法获取了一个map集合handlerMappings,从下面的代码其实可以看出这个集合存储了命名空间到NamespaceHandler的映射关系,那么看下getHandlerMappings()方法是如何获取命名空间到NamespaceHandler的映射关系的,源码如下:

private Map<String, Object> getHandlerMappings() {
    if (this.handlerMappings == null) {
        synchronized (this) {
            if (this.handlerMappings == null) {
                try {
                    Properties mappings =
                            PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                }
                catch (IOException ex) {
                    throw new IllegalStateException(
                            "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
            }
        }
    }
    return this.handlerMappings;
}

这里的this.handlerMappingsLocation即为META-INF/spring.handlers,这个方法读取jar包中的META-INF/spring.handlers文件,然后把namespace和对应的NamespaceHandler关系存储至map集合handlerMappings中,此时handlerMappings的key和value都是字符串,回到方法resolve(String namespaceUri),根据namespaceUri获取处理器,如果是NamespaceHandler类型则直接返回,否则实例化NamespaceHandler并调用其init()方法。init()方法在parse()方法调用前调用做一些初始化工作。parse()方法返回一个BeanDefinition对象,至此,BeanDefinition对象创建完成。下面是相关类的关系结构图:
Spring之BeanDefinition创建过程源码解析
Spring之BeanDefinition创建过程源码解析

小结

BeanDefinition作为描述bean信息的类记录了很多bean的重要元数据,它是spring的核心接口,spring创建bean的第一步就是收集bean信息并创建BeanDefinition对象,后续bean的创建也是根据BeanDefinition对象创建的,BeanDefinition会告诉spring如何创建bean。NamespaceHandler接口是另外一个值得关注的接口,它是spring底层的核心接口,spring很多特性都是通过NamespaceHandler接口解析并 装载对应组件的BeanDefinition进而实例化组件发挥特性。

猜你喜欢

转载自blog.51cto.com/wenshengzhu/2126879