Spring源码之容器的根本实现

概述

Spring是一个凋谢源代码的设计层面框架,他解决的是业务逻辑层和其余各层的松耦合问题,因而它将面向接口的编程思维贯通整个零碎利用。Spring是于2003 年衰亡的一个轻量级的Java 开发框架,由Rod Johnson创立。简略来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

本文以Spring 5.1.X版本为前提

Spring的构造组成

Spring框架是一个分层架构,它蕴含一系列的性能因素,并被分为大概20个模块,如下图所示:

Spring容器类型

Spring提供了两种不同的类型的容器

Spring BeanFactory容器:它是最简略的容器,给 DI 提供了根本的反对ApplicationContext容器 :ApplicationContext 容器继承自BeanFactory,它包含 BeanFactory 容器的所有性能,所以通常倡议应用。

Spring容器的类别及其特点

IoC容器的初始化过程

所谓的IOC,其实就是把咱们的类打包成一个BeanDefinition对象,该对象外面会蕴含咱们的类Class名称,以及咱们在xml中定义的scope,还要这个类的属性等信息。而后把这个BeanDefinition对象put到Map中,这个Map就是咱们所谓的容器。

具体来说,这个启动包含BeanDefinition的Resouce定位、载入和注册三个根本过程。如果咱们理解如何编程式地应用IoC容器,就能够分明地看到Resource定位和载入过程的接口调用。.具体别离如下:

  • 第一个过程是Resource定位过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过对立的Resource接口来实现,这个Resource对各种模式的BeanDefinition的应用都提供了对立接口。对于这些BeanDefinition的存在模式,置信大家都不会感到生疏。比方,在文件系统中的Bean定义信息能够应用FileSystemResource来进行形象;在类门路中的Bean定义信息能够应用后面提到的ClassPathResource来应用,等等。这个定位过程相似于容器寻找数据的过程,就像用水桶装水先要把水找到一样。
  • 第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean示意成IoC容器外部的数据结构,而这个容器外部的数据结构就是BeanDefinition。上面介绍这个数据结构的具体定义。具体来说,这个BeanDefinition实际上就是POJO对象在IoC容器中的形象,通过这个BeanDefinition定义的数据结构,使IoC容器可能不便地对POJO对象也就是Bean进行治理。在上面的章节中,咱们会对这个载入的过程进行具体的剖析,使大家对整个过程有比较清楚的理解。
  • 第三个过程是向IoC容器注册这些BeanDefinition的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来实现的。这个注册过程把载入过程中解析失去的BeanDefinition向IoC容器进行注册。通过剖析,咱们能够看到,在IoC容器外部将BeanDefinition注入到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的.

值得注意的是,这里谈的是IoC容器初始化过程,在这个过程中,个别不蕴含Bean依赖注入的实现。在Spring IoC的设计中,Bean定义的载入和依赖注入是两个独立的过程,上面咱们看看这个启动过程.

在应用IoC容器时,须要如下几个步骤:

1)创立IoC配置文件的形象资源,这个形象资源蕴含了BeanDefinition的定义信息.

2)创立一个BeanFactory,比方罕用的DefaultListableBeanFactory。

3)创立一个载入BeanDefinition的读取器,比方XmlBeanDefinitionReader来载入XML文件模式的BeanDefinition,通过一个回调配置给BeanFactory。

4)从定义好的资源地位读入配置信息,具体的解析过程由XmlBeanDefinitionReader来实现。实现整个载入和注册Bean定义之后,须要的IoC容器就建设起来了。这个时候就能够间接应用IoC容器了。

IOC容器具体实现源码解析

以读取xml配置文件为例

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)            throws BeansException {    // 动静确定应用哪个加载器加载配置文件        super(parent);        Assert.notNull(paths, "Path array must not be null");        Assert.notNull(clazz, "Class argument must not be null");    // 获取配置文件的门路        this.configResources = new Resource[paths.length];        for (int i = 0; i < paths.length; i++) {            this.configResources[i] = new ClassPathResource(paths[i], clazz);        }    // 加载配置文件        refresh();    }

ClassPathResource

ClassPathResource 中的实现形式便是通 class 或者 classLoader 提供的底层办法进行调用

public class ClassPathResource extends AbstractFileResolvingResource {    private final String path;    @Nullable    private ClassLoader classLoader;    @Nullable    private Class<?> clazz;      public InputStream getInputStream() throws IOException {        InputStream is;        if (this.clazz != null) {            is = this.clazz.getResourceAsStream(this.path);        } else if (this.classLoader != null) {            is = this.classLoader.getResourceAsStream(this.path);        } else {            is = ClassLoader.getSystemResourceAsStream(this.path);        }        if (is == null) {            throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");        } else {            return is;        }    }}

ClassPathXmlApplicationContext

refresh()是来自AbstractApplicationContext外面,ClassPathXmlApplicationContext的refresh()也是出自

AbstractApplicationContext.refresh()办法代码如下(从外面也根本能够看出初始化的大抵过程):

public void refresh() throws BeansException, IllegalStateException {    synchronized (this.startupShutdownMonitor) {        // Prepare this context for refreshing.        //筹备启动spring容器,设置容器的启动日期和流动标记         prepareRefresh();        // Tell the subclass to refresh the internal bean factory.        //取得容器ApplicationContext的子类BeanFactory。步骤如下:        //1.如果曾经有了BeanFactory就销毁它外面的单例Bean并敞开这个BeanFactory。        //2.创立一个新的BeanFactory。        //3.对这个BeanFactory进行定制(customize),如allowBeanDefinitionOverriding等参数        //4.转载BeanDefinitions(读取配置文件,将xml转换成对应得BeanDefinition)        //5.查看是否同时启动了两个BeanFactory。          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();        // Prepare the bean factory for use in this context.        //配置BeanFactory(就是将ApplicationContext的一些属性配置到BeanFactory上吧)     //如重要的如设置classLoader;将BeanPostProcess注册到BeanFactory里          prepareBeanFactory(beanFactory);        try {        // Allows post-processing of the bean factory in context subclasses.        //容许上下文的子类去执行postProcessor          postProcessBeanFactory(beanFactory);        // Invoke factory processors registered as beans in the context.        // 执行注册到该上下文的BeanFactoryPostProcessors        invokeBeanFactoryPostProcessors(beanFactory);        // Register bean processors that intercept bean creation.        // 开始注册BeanPostProcessor来拦挡其余的bean的初始化过程        registerBeanPostProcessors(beanFactory);        // Initialize message source for this context.        // 初始化音讯源        initMessageSource();        // Initialize event multicaster for this context.        //注册上下文事件的播送集          initApplicationEventMulticaster();        // Initialize other special beans in specific context subclasses.        //初始化一些非凡的bean        onRefresh();        // Check for listener beans and register them.        //查问并校验监听器并注册        registerListeners();        // Instantiate all remaining (non-lazy-init) singletons.        /// 实例化所有非懒加载的所有bean        finishBeanFactoryInitialization(beanFactory);        // Last step: publish corresponding event.        //最初一步公布所有的使用        finishRefresh();        }        catch (BeansException ex) {            if (logger.isWarnEnabled()) {                logger.warn("Exception encountered during context initialization - " +                "cancelling refresh attempt: " + ex);            }            // Destroy already created singletons to avoid dangling resources.            destroyBeans();            // Reset 'active' flag.            cancelRefresh(ex);            // Propagate exception to caller.            throw ex;        }        finally {            // Reset common introspection caches in Spring's core, since we            // might not ever need metadata for singleton beans anymore...            resetCommonCaches();        }    }}

BeanFactory

obtainFreshBeanFactory办法如下:

    /**     * Tell the subclass to refresh the internal bean factory.     * @return the fresh BeanFactory instance     * @see #refreshBeanFactory()     * @see #getBeanFactory()     */    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {    //第一步对Resource定位        refreshBeanFactory();        ConfigurableListableBeanFactory beanFactory = getBeanFactory();        if (logger.isDebugEnabled()) {            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);        }        return beanFactory;    }

AbstractRefreshableApplicationContext.refreshBeanFactory办法源码如下:

    /**     * This implementation performs an actual refresh of this context's underlying     * bean factory, shutting down the previous bean factory (if any) and     * initializing a fresh bean factory for the next phase of the context's lifecycle.     */    @Override    protected final void refreshBeanFactory() throws BeansException {        if (hasBeanFactory()) {            destroyBeans();            closeBeanFactory();        }        try {      // 创立容器            DefaultListableBeanFactory beanFactory = createBeanFactory();            beanFactory.setSerializationId(getId());      // 对容器进行定制化,如设置启动的参数,开启注解的主动拆卸等            customizeBeanFactory(beanFactory);      // 载入BeanDefinition,委派模式            loadBeanDefinitions(beanFactory);            synchronized (this.beanFactoryMonitor) {                this.beanFactory = beanFactory;            }        }        catch (IOException ex) {            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);        }    }

DefaultListableBeanFactory

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {      super(parentBeanFactory);}

AbstractAutowireCapableBeanFactory.java

public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {   this();   this.setParentBeanFactory(parentBeanFactory);}
    public AbstractAutowireCapableBeanFactory() {        this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();        this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();        this.allowCircularReferences = true;        this.allowRawInjectionDespiteWrapping = false;        this.ignoredDependencyTypes = new HashSet();        this.ignoredDependencyInterfaces = new HashSet();        this.currentlyCreatedBean = new NamedThreadLocal("Currently created bean");        this.factoryBeanInstanceCache = new ConcurrentHashMap(16);        this.filteredPropertyDescriptorsCache = new ConcurrentHashMap(256);        // 主动拆卸时疏忽给定的依赖接口        // 疏忽该接口的实现类中和接口setter办法入参类型雷同的依赖        this.ignoreDependencyInterface(BeanNameAware.class);        this.ignoreDependencyInterface(BeanFactoryAware.class);        this.ignoreDependencyInterface(BeanClassLoaderAware.class);    }

ignoreDependencylnterface 的次要性能是 疏忽给定接口的向动拆卸性能。

举例来说,当 A 中有属性 B ,那么当 Spring 在获取 A的 Bean 的时候如果其属性 B 还没有 初始化,那么 Spring 会主动初始化 B,这也是 Spring 提供的一个重要个性 。然而,某些状况 下, B不会被初始化,其中的一种状况就是B 实现了 BeanNameAware 接口 。Spring 中是这样介绍的:主动拆卸时疏忽给定的依赖接口,典型利用是边过其余形式解析 Application 上下文注册依赖,相似于 BeanFactory 通过 BeanFactoryAware 进行注入或者 ApplicationContext 通过 ApplicationContextAware 进行注入。

调用ignoreDependencyInterface办法后,被疏忽的接口会存储在BeanFactory的名为ignoredDependencyInterfaces的Set汇合中:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {    private final Set<Class<?>> ignoredDependencyInterfaces;    public void ignoreDependencyInterface(Class<?> ifc) {      this.ignoredDependencyInterfaces.add(ifc);  }}

ignoredDependencyInterface的真正作用还得看AutowireUtils类的isSetterDefinedInInterface办法:

public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) {        // //获取bean中某个属性对象在bean类中的setter办法        Method setter = pd.getWriteMethod();        if (setter != null) {            // // 获取bean的类型            Class<?> targetClass = setter.getDeclaringClass();            Iterator var4 = interfaces.iterator();            while(var4.hasNext()) {                Class<?> ifc = (Class)var4.next();                // bean类型是否接口的实现类                // 接口是否有入参和bean类型完全相同的setter办法                if (ifc.isAssignableFrom(targetClass) && ClassUtils.hasMethod(ifc, setter.getName(), setter.getParameterTypes())) {                    return true;                }            }        }        return false;}

咱们最后了解是在主动拆卸时疏忽该接口的实现,实际上是在主动拆卸时疏忽该接口实现类中和setter办法入参雷同的类型,也就是疏忽该接口实现类中存在依赖内部的bean属性注入。

典型利用就是BeanFactoryAware和ApplicationContextAware接口。首先看该两个接口的源码:

public interface BeanFactoryAware extends Aware {    void setBeanFactory(BeanFactory var1) throws BeansException;}public interface ApplicationContextAware extends Aware {    void setApplicationContext(ApplicationContext var1) throws BeansException;}

在Spring源码中在不同的中央疏忽了该两个接口:

// AbstractAutowireCapableBeanFactory.javathis.ignoreDependencyInterface(BeanFactoryAware.class);// AbstractApplicationContext.javabeanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

这样的做法使得ApplicationContextAware和BeanFactoryAware中的ApplicationContext或BeanFactory依赖在主动拆卸时被疏忽,而对立由框架设置依赖,如ApplicationContextAware接口的设置会在ApplicationContextAwareProcessor类中实现:

    private void invokeAwareInterfaces(Object bean) {        if (bean instanceof Aware) {            if (bean instanceof EnvironmentAware) {                ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());            }            if (bean instanceof EmbeddedValueResolverAware) {                ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);            }            if (bean instanceof ResourceLoaderAware) {                ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);            }            if (bean instanceof ApplicationEventPublisherAware) {                ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);            }            if (bean instanceof MessageSourceAware) {                ((MessageSourceAware)bean).setMessageSource(this.applicationContext);            }            if (bean instanceof ApplicationContextAware) {                ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);            }        }    }

通过这种形式保障了ApplicationContextAware和BeanFactoryAware中的容器保障是生成该bean的容器。

BeanDefinitions

AbstractXmlApplicationContext.loadBeanDefinitions

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        // Create a new XmlBeanDefinitionReader for the given BeanFactory.    // 创立Bean读取器,并通过回调设置到容器中,容器应用该读取器        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        // Configure the bean definition reader with this context's        // resource loading environment.    // 为Bean读取器设置环境变量        beanDefinitionReader.setEnvironment(this.getEnvironment());    // 设置Spring资源加载器        beanDefinitionReader.setResourceLoader(this);    // 设置SAX xml解析器        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);    }

最终调用了XmlBeanDefinitionReader.loadBeanDefinitions

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  ...    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());  ...}    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {        try {            // 调用doLoadDocument办法将资源文件转换为Document实例            Document doc = this.doLoadDocument(inputSource, resource);            // 调用registerBeanDefinitions办法提取并注册bean            return this.registerBeanDefinitions(doc, resource);        } catch (BeanDefinitionStoreException var4) {            throw var4;        } catch (SAXParseException var5) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);        } catch (SAXException var6) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);        } catch (ParserConfigurationException var7) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);        } catch (IOException var8) {            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);        } catch (Throwable var9) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);        }    }

持续向下走会发现调用了DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions办法实现了bean的解析及注册。

    protected void doRegisterBeanDefinitions(Element root) {        BeanDefinitionParserDelegate parent = this.delegate;        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);        if (this.delegate.isDefaultNamespace(root)) {            String profileSpec = root.getAttribute("profile");            if (StringUtils.hasText(profileSpec)) {                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");                if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                    if (this.logger.isInfoEnabled()) {                        this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());                    }                    return;                }            }        }        // 解析前解决,子类实现        this.preProcessXml(root);        this.parseBeanDefinitions(root, this.delegate);        // 解析后处理,子类实现        this.postProcessXml(root);        this.delegate = parent;    }

类的构造档次图

XmlBeanFactory继承自DefaultListableBeanFactory,而DefaultListableBeanFactory是整个bean加载的外围局部,是Spring注册及加载bean的默认实现

XML配置文件的读取是Spring中重要的性能,因为Spring的大部分性能都是以配置作为切入点的,能够从XmlBeanDefinitionReader中梳理一下资源文件读取、解析及注册的大抵脉络