文章目录
  1. 1. 初始化流程
    1. 1.1. 初始化xml解析器
    2. 1.2. 解析配置文件为Document对象
    3. 1.3. 解析DOM节点
    4. 1.4. 实例化bean

spring初始化bean有xml与注解两种方式,虽然注解可以减少很多xml配置,但还是要在xml配置文件里面配置好标签之后才能生效,里面涉及到很多对xml命名空间的解析,对后面模块的分析也有帮助,所以先从xml解析初始化分析走,注解方式的注入就分析个大概了。随便吐槽下,分析开源框架最忌讳的就是陷入到分析解析xml去了,现在流行的框架差不多都会涉及到解析xml,每研究一个开源框架,分析xml都会花很多时间,其实不想写出来,因为没有技术含量,但是有时候跟同事交流又会问道怎么解析xml的,真的好蛋疼。由于spring有很多自定义标签而初始化了很多内嵌对象,所以还是写下初始化流程吧。

这里先声明下,下面的分析只针对单个bean的初始化,并没有涉及到其他复杂场景的bean初始化,配置文件如下:

<?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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd" 
        default-autowire="default">

    <bean id="simple" class="mytest.bean.simpleBean.SimpleBean"/>

</beans>

就如此简单。

初始化流程

从最简单的初始化一个bean进行分析,以ClassPathXmlApplicationContext为例,由于该类继承了AbstractApplicationContext,所以初始化的时候都是从refresh方法开始的。前面分析了,容器里面最核心的一个类是DefaultListableBeanFactory,在初始化解析器之前就要先创建该类。解析xml为BeanDefinition在obtainFreshBeanFactory完成,下面就详细分析改方法。

初始化xml解析器

参考前面章节的加载bean的入口在AbstractRefreshableApplicationContext的loadBeanDefinitions方法,由于XmlWebApplicationContext与一般的应用加载bean的配置文件有些不一样,所以loadBeanDefinitions是单独由实现的,其实内部还是由XmlBeanDefinitionReader完成bean的解析。ClassPathXmlApplicationContext、FileSystemXmlApplicationContext都由AbstractXmlApplicationContext的loadBeanDefinitions实现了初始化xml解析器操作。参考代码:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

在实例化ResourceEntityResolver解析器时,在父类DelegatingEntityResolver初始化了BeansDtdResolver、PluggableSchemaResolver,这两种解析器分别解析dtd与schema两种方式的xml。

解析配置文件为Document对象

实例化XmlBeanDefinitionReader的时候,内部的DefaultDocumentLoader就创建好了,此类完成创建Document对象。参考loadDocument方法:

@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
        ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isDebugEnabled()) {
        logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
    }
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource);
}

由于实例化的时候已经设置了解析器为ResourceEntityResolver,所以直接看resolveEntity方法,有父类DelegatingEntityResolver去执行解析:

@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
    if (systemId != null) {
        if (systemId.endsWith(DTD_SUFFIX)) {
            return this.dtdResolver.resolveEntity(publicId, systemId);
        }
        else if (systemId.endsWith(XSD_SUFFIX)) {
            return this.schemaResolver.resolveEntity(publicId, systemId);
        }
    }
    return null;
}

由于spring都是使用的schema方式的定义的xml,所有使用PluggableSchemaResolver去解析xml,从这个类中就可以看到spring定义的xml标签约束了,在没个模块下面有个spring.schema文件,也就是以后的标签必须按照定义的schema规范来写标签。

解析DOM节点

上面分析了已经创建好Docment对象了,接下来就解析DOM节点了。spring有一般的标签(如),还有种命名空间类型的标签(如:context:component-scan),第一种按照正常的流程解析就完了,而第二种就是需要初始化一些内部对象会用到了。参考把初始化后的Document对象传到XmlBeanDefinitionReader的registerBeanDefinitions方法:

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;
}

需要注解的就是createReaderContext创建XmlReaderContext的时候,就有getNamespaceHandlerResolver方法把spring.handlers文件里面的内置对象加载进来了,用于解析命名空间类型的标签。DefaultBeanDefinitionDocumentReader将xml解析最后生成BeanDefinitionHolder,参考方法processBeanDefinition:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            //注册bean到容器(DefaultListableBeanFactory)
            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));
    }
}

这里比较重要的一个对象就是BeanDefinitionHolder的内部对象BeanDefinition,它保存了bean的所有信息,包括各种依赖关系,随便画了一个简单的类图:

至此解析XML就完成了。这里虽然没有介绍解析命名空间,但是后面分析注解的时候会顺带分析了,分析完自己也画了个时序图,包含了对命名空间类型节点的解析流程:

实例化bean

由上面的分析就只之,解析xml保存到DefaultListableBeanFactory中的只是BeanDefinition,并没有实例化。上面都初始化都发生在AbstractApplicationContext的obtainFreshBeanFactory方法,在refresh方法中可以看到,有个finishBeanFactoryInitialization,只要是singleton的bean,这里就是实例化的入口了,最终会走到DefaultListableBeanFactory.preInstantiateSingletons(),遍历解析xml时保存的beanDefinitionNames,并调用getBean方法,参考AbstractBeanFactory的方法:

protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {
    ......

            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            //开始创建bean,由AbstractAutowireCapableBeanFactory实现
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
    ......
    return (T) bean;
}

注意获取bean的时候有个createBean方法,参考《spring源码分析之Ioc容器分析》,AbstractBeanFactory的子类就是AbstractAutowireCapableBeanFactory,所以这个类就是创建bean入口。由于不涉及到代理bean的创建,所以直接参考doCreateBean方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
//实例化bean
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
}

将实例化后的bean设置到BeanWrapper (转换属性类型)

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                }
            }, getAccessControlContext());
        }
        else {
            //bean必须有空构造函数
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

需要注意的是实例化的bean必须有空的构造函数,参考SimpleInstantiationStrategy类:

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    if (bd.getMethodOverrides().isEmpty()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                            @Override
                            public Constructor<?> run() throws Exception {
                                return clazz.getDeclaredConstructor((Class[]) null);
                            }
                        });
                    }
                    else {
                        //必须有空构造函数,不然反射就抛异常
                        constructorToUse =    clazz.getDeclaredConstructor((Class[]) null);
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Exception ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // Must generate CGLIB subclass.
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

然后通过反射实例化的bean添加到BeanWrapperImpl,看配置文件是否注册了转换器,最终BeanWrapperImpl通过getWrappedInstance就获取到实例化后的bean了。实例化bean也画了一个时序图,便于以后复习:

文章目录
  1. 1. 初始化流程
    1. 1.1. 初始化xml解析器
    2. 1.2. 解析配置文件为Document对象
    3. 1.3. 解析DOM节点
    4. 1.4. 实例化bean