spring代码分析

最近用spring的时候感觉不怎么了解内部原理,用起来有些不习惯,于是找空看了一下spring的源码,看了一下bean加载的流程以及调用流程,现总结如下:

 

加载

 

 contextLoaderListener->ContextLoader.initWebApplicationContext,调用本对象的createWebApplicationContext->ConfigurableWebApplicationContext.refresh()->AbstractApplicationContext.refresh();

在上面的refresh里面有

 

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

   追踪这段代码,发现调用了:AbstractRefreshableApplicationContext的以下方法:

 

 protected final void refreshBeanFactory()
        throws BeansException
    {
        if(hasBeanFactory())
        {
            destroyBeans();
            closeBeanFactory();
        }
        try
        {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized(beanFactoryMonitor)
            {
                this.beanFactory = beanFactory;
            }
        }
        catch(IOException ex)
        {
            throw new ApplicationContextException((new StringBuilder("I/O error parsing bean definition source for ")).append(getDisplayName()).toString(), ex);
        }
    }

    这个方法里面有一句很重要: loadBeanDefinitions(beanFactory);

    这一句的作用是从配置文件加载所有的BeanDefinition.

 

   项目中用到的是基于xml的spring配置方式,所以最终的工厂类是:XmlWebApplicationContext。

   加载beandefinition时,把逐个文件用XmlBeanDefinitionReader进行解析并加载bean。

 

  XmlBeanDefinitionReader首先把每个配置文件载入成一个w3c的Document对象,然后 用 BeanDefinitionDocumentReader解析Document.

 

 BeanDefinitionDocumentReader的实现类是DefaultBeanDefinitionDocumentReader。

 实现类加载bean的方法如下:

 

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
    {
        if(delegate.isDefaultNamespace(delegate.getNamespaceURI(root)))
        {
            NodeList nl = root.getChildNodes();
            for(int i = 0; i < nl.getLength(); i++)
            {
                org.w3c.dom.Node node = nl.item(i);
                if(node instanceof Element)
                {
                    Element ele = (Element)node;
                    String namespaceUri = delegate.getNamespaceURI(ele);
                    if(delegate.isDefaultNamespace(namespaceUri))
                        parseDefaultElement(ele, delegate);
                    else
                        delegate.parseCustomElement(ele);
                }
            }

        } else
        {
            delegate.parseCustomElement(root);
        }
    }

 

   方法中的Element对象root其实就是之前的Document,是一个顶级的Element。

   然后再通过BeanDefinitionParserDelegate解析这个root下面的每个Element,看看是不是下级Element,如果是,

   判断Element是不是默认namespace(比如:beans-这个是默认,security,aop等),如果是:

   调用parseDefaultElement(ele, delegate);否则调用delegate.parseCustomElement(ele)。

   BeanDefinitionParserDelegate是一个很核心的类,这个类完成对bean对应的element的构造函数,bean参数,

   bean的fields的解析并且分别进行保存,之后生成bean的实例的时候需要从中取出这些信息来生成bean实例。

   parseCustomElemen方法的主要作用就是根据namespace调用对用的Namespacehandler解析element并且做   相应的操作(比如:securitynamespacehandler的作用是为应用根据security配置文件添加相应的filter).现在主要集中 在parseDefaultElement 方法上面,这个方法是提取bean的关键方法。

 

   

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
    {
        if(delegate.nodeNameEquals(ele, "import"))
            importBeanDefinitionResource(ele);
        else
        if(delegate.nodeNameEquals(ele, "alias"))
            processAliasRegistration(ele);
        else
        if(delegate.nodeNameEquals(ele, "bean"))
            processBeanDefinition(ele, delegate);
    }

  

  对于在默认namespace下面的常用标签:import,alias,bean,上面的方法都做了处理。下面主要跟踪一下常用的bean的解析: processBeanDefinition。

   

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
    {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null)
        {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try
            {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch(BeanDefinitionStoreException ex)
            {
                getReaderContext().error((new StringBuilder("Failed to register bean definition with name '")).append(bdHolder.getBeanName()).append("'").toString(), ele, ex);
            }
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

 

    至此,真正执行bean解析工作的类出来了:BeanDefinitionParserDelegate 。此类解析Element并且返回一个

    BeanDefinitionHolder 对象。然后通过 

   

 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

 

    支持,把BeanDefinition注册到了beanfactory里面。下面的工作就是取出bean了。

 

 

bean的获取

 

    一个常用的方式是通过ApplicationContext接口来获取bean。getBean(String name)的实现类是AbstractApplicationContext。追踪代码,最终发现bean的获取着落在AbstractBeanFactory的doGetBean方法上。继续跟踪,可以跟踪到:AbstractAutowireCapableBeanFactory的doCreateBean方法(对于Prototype的bean),此方法的作用是创建bean的实例。跟踪以上方法,发现是依靠InstantiationStrategy来实例化bean。

有两张策略来实例化bean: SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy。从名字上很容易看出,前者是不用代理的实例化,后者是通过cglib生成代理类对象的实例化。

 

至此,bean的取出过程也大概清楚了。因为时间仓促,很多细节来不及描述,等有空了补全这篇文章。

   

   

 

 

 
   

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/softtech2008/article/details/83600092
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞