天天看点

Spring系列(五) 容器初始化过程源码

IoC/DI 的概念

容器是Spring的核心之一(另一个核心是AOP). 有了容器, IOC才可能实现.

  • 什么使IoC? IoC就是将类自身管理的与其由依赖关系的对象的创建/关联和管理交予容器实现, 容器按照配置(比如xml文件)来组织应用对象的创建和关联.
  • 什么使DI? DI是IoC的实现方式, 由容器在程序初始化的时候将类的依赖对象注入进去.
  • IoC和DI的关系? IoC(Inversion of Control)是一种设计原则, 可以减少代码的耦合度, DI(Dependency Injection)是IOC的具体实现方式, 还有其他的实现方式如 DL(Dependency Lookup).

Spring 容器

ClassPathXmlApplicationContext

类应该都比较熟悉, 从熟悉的事物开始寻找线索.

下载Spring源码后用idea打开, 找到类

ClassPathXmlApplicationContext

, idea可以使用

ctrl+N

输入类名搜索, 打开源文件, 按

ctrl+Alt+U

可以生成类图.

Spring系列(五) 容器初始化过程源码

BeanFactory

ResourceLoader

是两个顶层接口.

BeanFactory

是Bean的工厂,定义了IoC基本的功能.

ResourceLoader

是资源加载的策略接口,定义了加载资源的基本规范,

ApplicationContext

需要此接口的功能.

BeanFactory

提供了容器最基本的功能, 其中定义的方法会频繁使用, 接口定义如下:

public interface BeanFactory {
    // 一个标记, 带有此标记开头的类不是bean, 而是工厂本身
    String FACTORY_BEAN_PREFIX = "&";
    // 下面几个方法是各种获取bean的方式
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    // 判断bean是否存在
    boolean containsBean(String name);
    // bean作用域是否单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    // bean作用域是否原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    // bean是否与给定解析类型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    // 获取bean类型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    //获取bean别名数组
    String[] getAliases(String name);

}           

ApplicationContext

扩展了

BeanFactory

的功能, 除了作为工厂外, 它还提供了消息国际化(

MessageSource

), 获取环境bean(

EnvironmentCapable

), 容器消息发布(

ApplicationEventPublisher

)等功能. 因为它包含了容器以外的这些功能, 所以对了解容器来说多少会产生干扰. 事实上, 查看

BeanFactory

的子类(在类图上选中类,或者在源代码视图中按

Ctrl+Alt+B

)能从它的实现中找到

DefaultListableBeanFactory

, 从名称上二者在继承该关系上应该比较近, 功能也比较纯粹, 没有类似ApplicationContext的其他干扰.

DefaultListableBeanFactory

类是最基本的容器实现类, 它的继承关系如下图. 作为bean的工厂, 它的职责就是生产bean, 基本功能正是顶级接口

BeanFactory

定义的那些方法. 它上级的接口扩展了自动装配的能力(

AutowireCapableBeanFactory

), 注册和获取等操作

BeanDefinition

实例的能力(

BeanDefinitionRegistry

).

Spring系列(五) 容器初始化过程源码

BeanDefinition

BeanDefinition 用来抽象bean定义在spring中的抽象, 最终spring将外部配置的bean转化为

BeanDefinition

的实例存储.

Spring系列(五) 容器初始化过程源码

容器初始化过程

容器初始化过程分为三步, 资源Resource定位, 解析加载, 注册.

DefaultListableBeanFactory

是工厂, 继承它的子类只有一个

XmlBeanFactory

, 它被标注为

@Deprecated

.所以不应该在应用中使用该类, 但它可以作为了解源码的入口. 它有个

XmlBeanDefinitionReader

的私有变量直接new初始化, 参数this将工厂实例传给这个对象, 这样它就有了工厂的引用, 方便内部处理.

public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);


    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        // 这个是调用实际加载资源的方法
        this.reader.loadBeanDefinitions(resource);
    }           

大概串一下初始化的执行流程:

  1. 获得一个

    Resource

    实例resource, 其实就是xml文件生成的输入流
  2. 实例化

    DefaultListableBeanFactory

    工厂beanFactory, 将resource作为构造参数传入
  3. beanFactory实例化, 生成

    XmlBeanDefinitionReader

    的实例reader, 并将beanFactory的引用传递给他
  4. 在beanFactory构造函数中调用reader的方法加载resource, 解析生成一系列

    BeanDefinition

    的实例, 因为readere有工厂的实例, 所以这些实例可以注册到工厂中

加载XML Bean的关键代码

下面按照调用关系跟踪代码, 忽略其他的xml元素, 最终目标是找到加载注册bean的机制.

XmlBeanDefinitionReader

--> loadBeanDefinitions

--> doLoadBeanDefinitions

--> registerBeanDefinitions

DefaultBeanDefinitionDocumentReader: BeanDefinitionDocumentReader

--> doRegisterBeanDefinitions

--> parseBeanDefinitions

--> parseDefaultElement / processBeanDefinition

BeanDefinitionParserDelegate

--> parseBeanDefinitionElement

BeanDefinitionReaderUtils

--> registerBeanDefinition

DetaultListableBeanFactory

一.

XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)

生成InputSource对象(用来初始化XML Dom对象)

InputStream inputStream = encodedResource.getResource().getInputStream();
try {
    // 生成实例, 后面用来加载dom
    InputSource inputSource = new InputSource(inputStream);
    if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
    }
    // 生成InputSource后,调用这个方法
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
    inputStream.close();
}           

二.

XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)

加载生成Xml Document对象

// 生成doc实例
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);           

三.

XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource)

// 生成BeanDefinitionDocumentReader的实例, 默认实现为生成DefaultBeanDefinitionDocumentReader类的实例, 通过BeanUtil工具的实例化方法生成
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 传入doc和资源的上下文对象, 注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));           

四.

registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

BeanDefinitionDocumentReader

是接口, 实现类为

DefaultBeanDefinitionDocumentReader

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    // 获取根节点
    Element root = doc.getDocumentElement();
    // 从根节点开始, 调用的这个方法会递归子节点
    doRegisterBeanDefinitions(root);
}           

五.

doRegisterBeanDefinitions(Element root)

类为

DefaultBeanDefinitionDocumentReader

protected void doRegisterBeanDefinitions(Element root) {
    //任何嵌套的<beans>元素都将导致此方法的递归。为了正确传播和保留<beans> default- *属性,请跟踪当前(父)委托,该委托可以为null。创建新的(子)委托,引用父项以进行回退,然后最终将this.delegate重置为其原始(父)引用。此行为模拟了一堆代理,而实际上并不需要一个代理。
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        // 下面这一块代码主要是做profile检查, 没有启用profile的bean不加载, 将直接return
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            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);
    // 具体解析的方法, pre和post的在这个类中为空方法
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}           

六.

parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

/**
* 解析文档中的根节点
* "import", "alias", "bean".
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 是根节点,就获取子节点, 遍历,如果是根"import", "alias", "bean", 就调用parseDefaultElement, 否则parseCustomElement
    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);
    }
}           

七.

parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            // 解析"import"元素, 这个方法会定位import的资源位置并重复第一步开始的步骤
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            // 别名"alias"注册
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            // 前方高能... 处理bean元素
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // 递归"beans"
            doRegisterBeanDefinitions(ele);
        }
    }           

八.

processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader

/**
*  处理bean元素的定义, 并且注册
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 获取bean的包装对象,代码见第九步
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 注册最终的bean装饰对象
            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));
    }
}           

九.

parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)

BeanDefinitionParserDelegate

关注两个实例化过程,一个是

BeanDefinition

, 一个是其装饰对象

BeanDefinitionHolder

的实例

/**
* 解析bean元素, 可能会返回null, 如果有错误则报告给
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                    "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    // 实例化一个 BeanDefination 实例
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                            beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                            !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Neither XML 'id' nor 'name' specified - " +
                            "using generated bean name [" + beanName + "]");
                }
            }
            catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}           

十.

registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

是类的静态方法

BeanDefinitionReaderUtils

;给registry对象调用

// 注册bean的最终方法
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {

    // 使用首要名称注册bean
    String beanName = definitionHolder.getBeanName();
    // 注册bean, 具体实现在类DetaultListableBeanFactory中
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 注册bean的别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}           

十一.

registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

在类

DetaultListableBeanFactory

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    ....

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        ....
        // 存到map里面
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}           

到目前为止, bean就注册到工厂里面去了, 实际上工厂里面保存了BeanDefinition的一个映射Map, 这样有助于Spring做一些验证, 当获取bean的时候也可以方便实现懒加载.