简单的spring ioc源码脉络分析


本文主要是记录自己在学习spring源码时的理解

基于xml的ioc时序图

基于xml的ioc时序图

简单分析

在ioc的的时序图中分为三个阶段,分别为定位,加载和注册。定位主要是用来找到配置的xml文件在哪。加载就是把找到的配置文件解析成BeanDefnition对象。注册则是把BeanDefinition放到ioc容器中

运行案例

IocDao 模拟持久层对象

public class IocDao {
    @Override
    public String toString() {
        return "返回iocDao对象";
    }
}

IocService 模拟service层对象

public class IocService {
    private List iocList;
    private IocDao iocDao;

    public List getIocList() {
        return iocList;
    }

    public void setIocList(List iocList) {
        this.iocList = iocList;
    }

    public IocDao getIocDao() {
        return iocDao;
    }

    public void setIocDao(IocDao iocDao) {
        this.iocDao = iocDao;
    }
}

xml配置文件applicationContext.xml中部分主要内容

        <bean id="iocDao" class="IocDao"/>
        <bean id="iocService" class="IocService">
            <property name="iocDao" ref="iocDao"/>
            <property name="iocList">
                <list>
                    <value>ioc11111111111</value>
                    <value>ioc22222222222</value>
                    <value>ioc33333333333</value>
                </list>
            </property>
        </bean>

Main 主类

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        IocService iocService = context.getBean("IocService", IocService.class);

        List iocList = iocService.getIocList();

        for (int i = 0; i < iocList.size(); i++) {
            System.out.println("list属性值"+iocList.get(i));
        }
        System.out.println();

        System.out.println(iocService.getIocDao().toString());
    }
}

ioc创建的三个基本过程

定位:找到xml配置文件在哪里,即获取到Resource

一、寻找入口

以我们使用最多的CalssPathXmlApplicationContext为例,通过main()方法启动
在此处打断点,准备进入spring源码,首先进入方法,查看构造方法的调用

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

进入构造器传进来的参数就是我们写的xml文件名,并且又调用了其他构造器。

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }

下面进入被调用的构造器里查看

	 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }

    }

参数列表

属性名属性值
configLocationsapplicationContext.xml
refreshtrue
parentnull

configLocation实际为String数组,为方便展示直接写的数组唯一的属性值

这个构造器有三个步骤

设置容器的资源加载器

对应的这句代码,对应第二步

        super(parent);

作用为设置容器的资源加载器,对应第二步

设置Bean配置信息的定位路径

将在第二步中进行分析

        this.setConfigLocations(configLocations);
启动整个ioc容器对Bean定义的载入过程(重要)

对应第三步

            this.refresh();

二、获得配置路径

我们跟随上面构造器的super()方法一直向上追踪,直到找到AbstractApplicationContext这个类

这里截取了三个方法的代码,虽然代码看起来很多很复杂,但是仔细梳理一下核心过程,上面的构造方法做了以下两项重要工作

为容器设置好Bean资源加载器

下面这个方法是我们追踪到AbstractApplicationContext的入口,首先先调用了自身的无参构造

    //debug追踪进来的入口,从此处开始分析
    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        this();
        this.setParent(parent);
    }

无参构造方法,对一些属性赋值,我们在此阶段只需要关注最后一个方法即可

	public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.applicationListeners = new LinkedHashSet();
        //只关注这个方法即可
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }

上面的方法又调用了下面这个getResourcePatternResolver方法
这个方法用来获取一个Spring Source的加载器用于读入Spring Bean定义资源文件

    protected ResourcePatternResolver getResourcePatternResolver() {
	    //AbstractApplicationContext继承了DefaultResourceLoader,因此也是一个资源加载器
	    //返回的对象是Spring资源加载器,其getResource(String location)方法用于载入资源
        return new PathMatchingResourcePatternResolver(this);
    }
设置Bean配置信息的定位路径

追踪上面提到过的setConfigLocations(configLocations)方法,进入父类AbstractRefreshableConfigApplicationContext中
可以找到方法的代码为

	public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];

            for(int i = 0; i < locations.length; ++i) {
            	//resolvePath为本类中将字符串解析为路径的方法
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }

    }

三、开始启动

SpringIOC 容器对 Bean 配置资源的载入是从 refresh()函数开始的,refresh()是一个模板方法,规定了IOC容器的启动流程,有些逻辑要交给其子类去实现。它对Bean配置资源进行载入。
追踪第一步中的refresh方法,进入父类AbstractRefreshableConfigApplicationContext的refresh方法

	public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            //准备刷新
            this.prepareRefresh();
            //获取BeanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备BeanFactory
            this.prepareBeanFactory(beanFactory);

            try {
            	//BeanFactory后置处理
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                //执行BeanFactory后置事件处理器
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册Bean后置事件处理器
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                //初始化MessageSource消息源
                this.initMessageSource();
                //初始化事件传播器
                this.initApplicationEventMulticaster();
                //调用子类的某些特殊Bean初始化方法
                this.onRefresh();
                //注册事件监听器
                this.registerListeners();
                //初始化所有剩余的单例Bean
                this.finishBeanFactoryInitialization(beanFactory);
                //发布容器事件,结束Refresh过程
                this.finishRefresh();
            } catch (BeansException var10) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }
				//销毁Bean
                this.destroyBeans();
                //取消Refresh
                this.cancelRefresh(var10);
                throw var10;
            } finally {
            	//重设公共缓存
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }

代码同样很长,下面详细分析refresh的逻辑,篇幅原因不进入每个方法,可以自行进入方法查看

准备刷新
	prepareRefresh();

调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识

获取BeanFactory
		ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

获取到应用上下文维护的beanFactory,默认是DefaultListableBeanFactory。并设置刷新标志refreshed为true

准备BeanFactory
        this.prepareBeanFactory(beanFactory);

对beanFactory做了一些基础设置的配置,比如BeanClassLoader、BeanExpressionResolver、ApplicationContextAwareProcessor、ApplicationListenerDetector监听器检测器以及默认的环境信息bean。并设置了哪些不需要自动注入以及哪些已经解析过可以直接使用。
对应第四步

BeanFactory的后置处理
        this.postProcessBeanFactory(beanFactory);

为容器的某些子类指定特殊的BeanPost事件处理器

执行BeanFactory后置事件处理器
        this.invokeBeanFactoryPostProcessors(beanFactory);

注册并调用BeanFactoryPostProcessor,扫描获取BeanDefinition;

注册Bean后置事件处理器
         this.registerBeanPostProcessors(beanFactory);

注册BeanPostProcessor到BeanFactory;

初始化MessageSource消息源;
 	       this.initMessageSource();

国际化相关

初始化事件传播器
         this.initApplicationEventMulticaster();
调用子类的某些特殊Bean初始化方法
         this.onRefresh();
为事件传播器注册事件监听器
        this.registerListeners();

检查监听bean并将这些bean向容器中注册

初始化所有剩余的单例Bean
        this.finishBeanFactoryInitialization(beanFactory);

初始化所有non-lazy-init bean,比如我们的controller、service、mapper等

发布容器事件,结束Refresh过程
        this.finishRefresh();

初始化容器的生命周期事件处理器,并发布容器的生命周期事件

重设公共缓存
         this.resetCommonCaches();

重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据
下面两个是catch中的方法

销毁已经创建的bean
       this.destroyBeans();

为了防止Bean资源占用,如果出现异常则销毁已经在前面过程中生成的Bean

取消刷新
	this.cancelRefresh(var10)

参数为捕获到的异常,充值容器的同步标识

总结

refresh()方法主要为IOC容器Bean的生命周期管理提供条件,Spring IOC容器载入Bean配置信息从其子类容器的refreshBeanFactory()方法启动, 所以整个refresh()中“ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,我们前面说的载入就是从这句代码开始启动。

refresh()方法的主要作用是:在创建IOC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IOC容器。它类似于对IOC容器的重启,在新建立好的容器中对容器进行初始化,对Bean配置资源进行载入。

四、创建容器

AbstractApplicationContext 类中只抽象定义了 refreshBeanFactory()方法, 容器真正调用的是其子类 AbstractRefreshableApplicationContext 实现的 refreshBeanFactory()方法
我们进入上一步的obtainFreshBeanFactory()方法

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	    //创建BeanFactory
        this.refreshBeanFactory();
        //返回BeanFactory
        return this.getBeanFactory();
    }

继续进入refreshBeanFactory()方法

	protected final void refreshBeanFactory() throws BeansException {
		//如果已经有容器,则销毁容器中的bean并关闭容器
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
        	//创建ioc容器
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            //对ioc容器进行定制化,如设置启动参数,开启注解的自动装配等
            this.customizeBeanFactory(beanFactory);
            //调用Bean定义的方法,使用了委派模式
            //对应第五步
            this.loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException var2) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
        }
    }

能看出来,这里的逻辑还是很清晰的,如果有容器就销毁,然后进行容器的创建

五、载入配置路径

AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions方法,容器真正调用的是其子类AbstractXmlApplicationContext对该方法的实现,我们继续从上一步的loadBeanDefinitions(beanFactory)方法进入

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		//创建XmlBeanDefinitionReader,即创建Bean读取器
		//并通过回调设置到容器中	
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		//为Bean读取器设置spring属性
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        //设置SAX xml解析器
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        //当读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
        this.initBeanDefinitionReader(beanDefinitionReader);
        //Bean读取去真正实现的加载方法(由此进入)
        this.loadBeanDefinitions(beanDefinitionReader);
    }

接着进入loadBeanDefinitions(beanDefinitionReader)方法、

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		//获取Bean定义资源的定位
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
        	//调用父类的方法获取Bean的定义资源
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
       		//调用父类的方法获取Bean的定义资源
       		//对应第六步
            reader.loadBeanDefinitions(configLocations);
        }

    }

六、分配路径处理策略

进入loadBeanDefinitions(configLocations方法

	 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int count = 0;
        String[] var3 = locations;
        int var4 = locations.length;

		//对每一个路径进行处理
        for(int var5 = 0; var5 < var4; ++var5) {
            String location = var3[var5];
            //从这里进入
            count += this.loadBeanDefinitions(location);
        }

        return count;
    }
    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(location, (Set)null);
    }

进入到真正处理的方法

	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		//获取在ioc容器初始化过程中设置的资源加载器
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int count;
            if (resourceLoader instanceof ResourcePatternResolver) {
            	//主要理解这里即可
                try {
                	//加载指定位置的Bean资源定义文件,对应第七步
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //委派调用子类的方法,实现加载功能,对应第八步
                    count = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Collections.addAll(actualResources, resources);
                    }

                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                    }

                    return count;
                } catch (IOException var6) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var6);
                }
            } else {
                Resource resource = resourceLoader.getResource(location);
                count = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
                }

                return count;
            }
        }
    }

七、解析配置文件路径

从getResources(location)进入找到具体实现方法

    public Resource[] getResources(String locationPattern) throws IOException {
        Assert.notNull(locationPattern, "Location pattern must not be null");
        //判断是否为类路径下
        if (locationPattern.startsWith("classpath*:")) {
            return this.getPathMatcher().isPattern(locationPattern.substring("classpath*:".length())) ? this.findPathMatchingResources(locationPattern) : this.findAllClassPathResources(locationPattern.substring("classpath*:".length()));
        } else {
        	//如果不在类路径下则拼接前缀
            int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : locationPattern.indexOf(58) + 1;
            return this.getPathMatcher().isPattern(locationPattern.substring(prefixEnd)) ? this.findPathMatchingResources(locationPattern) : new Resource[]{this.getResourceLoader().getResource(locationPattern)};
        }
    }

在这一步已经成功获取了资源加载器

八、开始读取配置内容

继续回到第七步XmlBeanDefinitionReader类中的loadBeanDefinitions方法,并进入loadBeanDefinitions(resources)方法
一直进入直到找到真正读取的方法doLoadBeanDefinitions

	//从特定XMl文件中实际载入Bean定义资源
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
	        //将xml文档转换为dom对象,解析过程由documentLoader实现
	        //对应第九步
            Document doc = this.doLoadDocument(inputSource, resource);
            //启动对Bean定义解析的详细过程,该解析过程会用到SpringBean配置规则
            //对应第十步
            int count = this.registerBeanDefinitions(doc, resource);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + count + " bean definitions from " + resource);
            }

            return count;
        //之后为异常处理
        } catch (BeanDefinitionStoreException var5) {
            throw var5;
        } catch (SAXParseException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
        } catch (SAXException var7) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
        } catch (ParserConfigurationException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
        } catch (IOException var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
        } catch (Throwable var10) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
        }
    }

九、准备文档对象

进入doLoadDocument(inputSource, resource)

	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
		//创建文件解析工厂
		//由此进入
        DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isTraceEnabled()) {
            logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
		//创建文档解析器
        DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
        //解析Spring的Bean定义资源
        //将Resource解析成DOM文件
        return builder.parse(inputSource);
    }

创建文件解析工厂的方法

    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
    	//创建文档解析工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);
        //设置解析XML的校验
        if (validationMode != 0) {
            factory.setValidating(true);
            if (validationMode == 3) {
                factory.setNamespaceAware(true);

                try {
                    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
                } catch (IllegalArgumentException var6) {
                    ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(var6);
                    throw pcex;
                }
            }
        }

        return factory;
    }

至此,Spring IOC 容器根据定位的 Bean 配置信息, 将其加载读入并转换成为 Document 对象过程完成。

加载:解析xml文件,保存成BeanDefinition对象

下面注释中写的Bean定义就是BeanDefinition
** 在这里我们要继续分析 Spring IOC 容器将载入的 Bean 配置信息转换为 Document 对象之后, 是如何将其解析为 Spring IOC 管理的 Bean 对象并将其注册到容器中的。**

十、分配解析策略

回到第八步,进入registerBeanDefinitions(doc, resource)方法

	//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    	//得到BeanDefinitionDoucmentReader来对xml格式的BeanDefinition解析
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        //获得容器中注册的bean数量
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        //解析过程入口,这里使用了委派模式
        //具体的解释实现过程有实现类DefaultBeanDefinitionDoucmentReader实现
        //对应第十一部
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        //统计解析的Bean数量
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

按照 Spring Bean的定义规则对 Document对象进行解析,其解析过程是在接 口BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader 中实现。

十一、将配置载入内存

进入registerBeanDefinitions(doc, this.createReaderContext(resource))方法

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //获取xml描述符
        this.readerContext = readerContext;
        //调用实现具体逻辑的方法
		//doc.getDocumentElement()获取根标签
        this.doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    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.isDebugEnabled()) {
                        this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }
		//在解析Bean定义之前,进行自定义的解析,增强计息过程的可扩展性
        this.preProcessXml(root);
        //从document根元素开始进行Bean定义的Doucment对象
        //调用后面的方法
        this.parseBeanDefinitions(root, this.delegate);
        //在解析Bean定义之后,进行自定义的解析,增强计息过程的可扩展性
        this.postProcessXml(root);
        this.delegate = parent;
    }
	//创建BeanDefinitionParserDelegate,用于完成真正的解析
    protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        //BeanDefinitionParserDelegate初始化Document根标签
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    	//Bean定义的Document对象使用了Spring默认的XMl命名空间
        if (delegate.isDefaultNamespace(root)) {
        	//获取根元素的所有子节点
            NodeList nl = root.getChildNodes();

            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                //判断节点是否为xml元素节点
                if (node instanceof Element) {
                    Element ele = (Element)node;
                    if (delegate.isDefaultNamespace(ele)) {
                    	//调用后面的方法
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
	        //如果没有使用spring默认的命名空间,则使用用户自定义的解析规则进行解析
            delegate.parseCustomElement(root);
        }

    }
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//如果是import,则进行导入解析
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        //如果是alias,则进行别名解析
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        //如果既不是导入也不是别名,即最普通的bean元素
        } else if (delegate.nodeNameEquals(ele, "bean")) {
        	//调用下面的方法
            this.processBeanDefinition(ele, delegate);
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }
    }
	//解析bean元素
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//解析beanDefinition的子元素
    	//对应第十二步
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
            	//向ioc容器注册 解析得到的Bean定义,这是Bean定义向ioc容器注册的入口
            	//对应第十六步
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

			//在完成向ioc容器注册Bean的定义后,发送注册事件
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

十二、载入bean元素

Bean配置信息中的和元素解析在DefaultBeanDefinitionDocumentReader中已经完成
进入到parseBeanDefinitionElement方法

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    	//获取bean标签的id
        String id = ele.getAttribute("id");
        //获取name
        String nameAttr = ele.getAttribute("name");
        //获取alias属性值
        List<String> aliases = new ArrayList();
        //将所有name属性存放到别名中
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        //如果没有配置id属性时,将别名中的第一个赋值给beanName
        if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }
		//检查id或name的唯一性,containingBean标识bena标签中是否还有子bean标签
        if (containingBean == null) {
			//检查id,name和别名是否重复
            this.checkNameUniqueness(beanName, aliases, ele);
        }
		//下关系对bean标签中配置的bean定义进行解析
		//调用下面的方法
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                    	//如果没有配置id,name,别名,且不包含子元素
                    	//生成一个唯一的beanName并注册
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                    	//如果没有id,name,别名,并且包含子元素
                        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 (this.logger.isTraceEnabled()) {
                        this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                	//解析出错时,返回空
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }
	//详细对备案标签配置的其他属性进行解析
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		//记录解析的bean
        this.parseState.push(new BeanEntry(beanName));
        //只读取备案标签配置的class名字(类名),保存到BeanDefinition中
        //目前制作记录,不做实例化,实例化在后面依赖注入时完成
        String className = null;
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }
		//如果配置了parent属性,则获取parent属性值
        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }
		
        try {
        	//根据类名和parent属性值创建BeanDefition
        	//为载入bean定义信息做准备
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //对当前bean元素中配置的一些属性值进行解析和设置,如配置单态(singleton)等
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //设置Description西欧毛线哦
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //对元信息进行解析
            this.parseMetaElements(ele, bd);
            //对lookup-method属性解析
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //对repalce-method属性解析
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造方法属性
            this.parseConstructorArgElements(ele, bd);
            //解析<property>
            //对应第十三步
            this.parsePropertyElements(ele, bd);
            //解析Qualifier
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

只要使用过 Spring,对 Spring 配置文件比较熟悉的人,通过对上述源码的分析,就会明白我们在 Spring配置文件中元素的中配置的属性就是通过该方法解析和设置到 Bean 中去的。

注意: 在解析元素过程中没有创建和实例化 Bean 对象,只是创建了 Bean 对象的定义类BeanDefinition,将元素中的配置信息设置到 BeanDefinition 中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的 Bean 对象。
上面方法中一些对一些配置如元信息(meta)、qualifier 等的解析,我们在 Spring 中配置时使用的也不多,我们在使用 Spring 的元素时,配置最多的是属性,因此我们下面继续分析源码,了解 Bean 的属性在解析时是如何设置的。

十三、载入property元素

从上面parsePropertyElements(ele, bd);进入

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();
		//获取bean标签下的所有子标签
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //如果是property标签,则调用解析property标签的元素进行解析
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) {
            	//调用后面的方法
                this.parsePropertyElement((Element)node, bd);
            }
        }

    }
	//解析property标签
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
    	//获取name属性值
        String propertyName = ele.getAttribute("name");
        if (!StringUtils.hasLength(propertyName)) {
            this.error("Tag 'property' must have a 'name' attribute", ele);
        } else {
            this.parseState.push(new PropertyEntry(propertyName));

            try {
            	//如果有同名的property存在,不进行解析,直接返回
            	//即如果配置了同名的property,只有第一个生效
                if (bd.getPropertyValues().contains(propertyName)) {
                    this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                    return;
                }
				//解析获取property的值
				//调用后面的方法
                Object val = this.parsePropertyValue(ele, bd, propertyName);
                //根据property名字和值创建property实例
                PropertyValue pv = new PropertyValue(propertyName, val);
                //解析属性
                this.parseMetaElements(ele, pv);
                pv.setSource(this.extractSource(ele));
                bd.getPropertyValues().addPropertyValue(pv);
            } finally {
                this.parseState.pop();
            }

        }
    }
    public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
        String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
        //获取所有子标签,只能是其中一种类型:ref,value,list,etc等
        NodeList nl = ele.getChildNodes();
        Element subElement = null;

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //子元素不是description和mate属性
            if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "description")) {
                if (subElement != null) {
                    this.error(elementName + " must not contain more than one sub-element", ele);
                } else {
                	//当前标签还有子标签,如list内嵌套value标签
                    subElement = (Element)node;
                }
            }
        }
		//判断时ref还是value
        boolean hasRefAttribute = ele.hasAttribute("ref");
        boolean hasValueAttribute = ele.hasAttribute("value");
        //不允许既不是ref,也不是value
        if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
            this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
        }
		//如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref信息
        if (hasRefAttribute) {
            String refName = ele.getAttribute("ref");
            if (!StringUtils.hasText(refName)) {
                this.error(elementName + " contains empty 'ref' attribute", ele);
            }

            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(this.extractSource(ele));
            return ref;
        //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value信息
        } else if (hasValueAttribute) {
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
            valueHolder.setSource(this.extractSource(ele));
            return valueHolder;
        //如果还有子元素,如list
        } else if (subElement != null) {
        	//解析
        	//对应第十四步,
            return this.parsePropertySubElement(subElement, bd);
        } else {
            this.error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }

小结
1)ref 被封装为指向依赖对象一个引用。
2)value 配置都会封装成一个字符串类型的对象。
3)ref 和 value 都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与所引用的属性关联起来。

十四、载入property子元素

在上面方法的最后对于元素的子元素通过parsePropertySubElement()方法解析,我们继续分析该方法的源码,了解其解析过程。

    @Nullable
    public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
    	//如果没有使用spring默认的命名矿建,则使用自定义的规则解析
        if (!this.isDefaultNamespace((Node)ele)) {
            return this.parseNestedCustomElement(ele, bd);
        //如果是bean则用bean的解析器
        } else if (this.nodeNameEquals(ele, "bean")) {
            BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }

            return nestedBd;
        //如果是ref
        } else if (this.nodeNameEquals(ele, "ref")) {
            String refName = ele.getAttribute("bean");
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
            	//获取parent属性值,引用父级容器的bean
                refName = ele.getAttribute("parent");
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    this.error("'bean' or 'parent' is required for <ref> element", ele);
                    return null;
                }
            }

            if (!StringUtils.hasText(refName)) {
                this.error("<ref> element contains empty target attribute", ele);
                return null;
            } else {
            	//创建ref类型数据,指向被引用的对象
                RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
                //设置引用类型是被当前子元素所引用
                ref.setSource(this.extractSource(ele));
                return ref;
            }
        //按类别选择解析方法
        } else if (this.nodeNameEquals(ele, "idref")) {
            return this.parseIdRefElement(ele);
        } else if (this.nodeNameEquals(ele, "value")) {
            return this.parseValueElement(ele, defaultValueType);
        } else if (this.nodeNameEquals(ele, "null")) {
            TypedStringValue nullHolder = new TypedStringValue((String)null);
            nullHolder.setSource(this.extractSource(ele));
            return nullHolder;
        } else if (this.nodeNameEquals(ele, "array")) {
            return this.parseArrayElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "list")) {
        	//对应第十五步,解析list的子元素
            return this.parseListElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "set")) {
            return this.parseSetElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "map")) {
            return this.parseMapElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "props")) {
            return this.parsePropsElement(ele);
        } else {
            this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
    }

十五、解析list的子元素

下面,我们对集合元素的解析方法进行源码分析,了解其实现过程。
进入parseListElement(ele, bd)方法

    public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
    	//获取valueType属性,即获取数据类型
        String defaultElementType = collectionEle.getAttribute("value-type");
        //获取所有子节点
        NodeList nl = collectionEle.getChildNodes();
        //封装为ManagedList
        ManagedList<Object> target = new ManagedList(nl.getLength());
        target.setSource(this.extractSource(collectionEle));
        //设置集合目标数据类型
        target.setElementTypeName(defaultElementType);
        target.setMergeEnabled(this.parseMergeAttribute(collectionEle));
        //具体的元素解析
        //调用后面的方法
        this.parseCollectionElements(nl, target, bd, defaultElementType);
        return target;
    }
    protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, @Nullable BeanDefinition bd, String defaultElementType) {
    	//遍历集合所有节点
        for(int i = 0; i < elementNodes.getLength(); ++i) {
            Node node = elementNodes.item(i);
            if (node instanceof Element && !this.nodeNameEquals(node, "description")) {
            	//将元素加入集合,递归遍历下一个节点
                target.add(this.parsePropertySubElement((Element)node, bd, defaultElementType));
            }
        }

    }

注册:将BeanDefinition对象放入BeanFactory中

十六、分配注册策略

	//将解析的BeanDefinitionHold注册到容器中
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    	//获得解析的Beandefinition名称
        String beanName = definitionHolder.getBeanName();
        //注册
        //对应第十七步
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        //如果有别名注册别名
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }

十七、向容器注册

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var8) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
            }
        }

        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }

            if (existingDefinition.getRole() < beanDefinition.getRole()) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (this.logger.isTraceEnabled()) {
                this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (this.hasBeanCreationStarted()) {
                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;
                    this.removeManualSingletonName(beanName);
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.removeManualSingletonName(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition == null && !this.containsSingleton(beanName)) {
            if (this.isConfigurationFrozen()) {
                this.clearByTypeCache();
            }
        } else {
            this.resetBeanDefinition(beanName);
        }

    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值