zoukankan      html  css  js  c++  java
  • 对spring web启动时IOC源码研究(二)

    发现这样debug到哪说到哪好像有点回不来了~让我重新理下思路,主要步骤先上图,有什么不同意见欢迎批评教育~

    (一)spring IOC的主要步骤都在refresh()这个方法中,我给出了自己的理解注释

    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // 解析前准备工作,主要为打log,设置active标志
                prepareRefresh();
    
                // 对xml文件进行解析工作,并把解析后的BeanDefintiton定义信息保存入容器
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // 在上下文中用容器之前的准备工作,主要为对DefaultListableBeanFactory beanFactory的参数设置
                prepareBeanFactory(beanFactory);
    
                try {
                    // beanFactory添加后处理器
                    postProcessBeanFactory(beanFactory);
    
                    // 调用beanFactoryPostProcessor接口实现类,并放入容器
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // 实例化实现beanPostProcessor的类,并放入容器
                    registerBeanPostProcessors(beanFactory);
    
                    // 实例化MessageSource接口实现类,没有会实现默认实现类,用来实现国际化
                    initMessageSource();
    
                    // 实例化ApplicationEventMulticaster事件广播器,没有会创建默认类,应该是用来给监听的类发送广播吧
                    initApplicationEventMulticaster();
    
                    // 实例化一些特殊的类
                    onRefresh();
    
                    // 检查监听器并注册他们
                    registerListeners();
    
                    // 实例化所有非懒加载的单例对象,处理实现了Aware相关接口的类
                    finishBeanFactoryInitialization(beanFactory);
    
                    // 结束容器的更新,初始化lifecycleProcessor接口实现类,广播容器更新完毕事件
                    finishRefresh();
                }
    
            }
        }

    (二)接下来讲解几个我认为比较重要的部分,注意整篇随笔是根据方法的调用顺序一个个讲下去的

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }

     1、obtainFreshBeanFactory()方法,注释里有说明他的作用,具体深入下,主要操作在refreshBeanFactory()中,对beanFactory处理完成后getBeanFactory()去获得处理完成的beanFactory返回。

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

     2、进入refreshBeanFactory()方法,先是检查是否已经存在容器,第一次进都是没有的,之后进入红色字体方法createBeanFactory(),创建默认的beanFactory容器,设id和定制化操作后开始进入加载bean描述信息的loadBeanDefinitions()方法。

        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // 为beanFactory创建XmlBeanDefinitionReader即xml阅读器
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // 初始化阅读器的一些配置,比如加载环境信息,加载容器本身等等,由下面提供的运行调用截图可以看出,虽然在不同的子类调用方法,其本质都是XmlWebApplicationContext容器在运行
            beanDefinitionReader.setEnvironment(getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    // 允许子类提供定制的阅读器进行初始化,之后处理加载bean描述信息
            initBeanDefinitionReader(beanDefinitionReader);
            loadBeanDefinitions(beanDefinitionReader);
        } 

    3、

        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                for (String configLocation : configLocations) {
                    reader.loadBeanDefinitions(configLocation);
                }
            }
        }

    接上面的方法,loadBeanDefinitions()方法开始加载xml信息了,此方法后也算结束了一阶段xmlWebApplicationContext容器的使用,进入阅读器解析xml阶段

    此图可以看出从XmlWebApplicationContext到XmlBeanDefinitionReader的转换。

    4、

        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                for (String configLocation : configLocations) {
                    reader.loadBeanDefinitions(configLocation);
                }
            }
        }
        @Override
        public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(location, null);
        }
        public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
           //省略。。
                    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                    int loadCount = loadBeanDefinitions(resources);
         //省略。。
        }
        @Override
        public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
            Assert.notNull(resources, "Resource array must not be null");
            int counter = 0;
            for (Resource resource : resources) {
                counter += loadBeanDefinitions(resource);
            }
            return counter;
        }
        @Override
        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));
        }
        public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
            //省略
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                }
          //省略
        }

     我尽量把它进入的一个个步骤都列出来,以免看客觉得怎么突然到了这个方法,但还是会省略一些细节,比如进入上述最后一个方法后,会对encodedResource进行保存操作等等,这里只列出特别主要的部分。上述操作进行了对资源的编解码,这么多方法的层层进入都还是准备工作,主要工作的方法为doLoadBeanDefinitions().

    5、

        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
           //加载资源信息成Document对象 Document doc
    = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); }
      //开始
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
         //创建beanDefinition文档阅读器 BeanDefinitionDocumentReader documentReader
    = createBeanDefinitionDocumentReader(); documentReader.setEnvironment(getEnvironment());
         //获取DefalutListableBeanFactory中已经被加载的beanDefinition资源的多少
    int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } //这个方法是在DefalutListablebeanFactory中进行的,可以看出bean描述信息被保存在了这个类中 @Override public int getBeanDefinitionCount() { return this.beanDefinitionMap.size(); }   //这个方法开始对节点解析了,之前创建的文档阅读器开始发挥作用,
      //开始从XmlBeanDefinitionReader类处理转向DefaultBeanDefinitionDocumentReader类处理(
    BeanDefinitionDocumentReader的实现类)看下图
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
            doRegisterBeanDefinitions(root);
        }

     

    6、

       protected void doRegisterBeanDefinitions(Element root) {
            BeanDefinitionParserDelegate parent = this.delegate;
         //创建beanDefinition解析代理
    this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { 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)) { return; } } }      //根节点前置处理,预留子类实现 preProcessXml(root);
         //使用代理,解析bean定义 parseBeanDefinitions(root,
    this.delegate);
         //根节点后置处理,预留子类实现 postProcessXml(root);
    this.delegate = parent; } protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
         //初始化代理,查询根节点的各项默认属性并赋给代理文档默认定义的类
    DocumentDefaultsDefinition,这些属性包括lazy-init,autowire,init-method,destory-method等等
            delegate.initDefaults(root, parentDelegate);
            return delegate;
        }

     7、

        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
           //这里面开始对root根节点下的元素节点遍历
    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); } }
      //这里主要是对context:component-scan,mvc:annotation-driven等特别功能进行解析,同时对注解的类进行相应功能的操作,解析出对应的beanDefinfition
        public BeanDefinition parseCustomElement(Element ele) {
            return parseCustomElement(ele, null);
        }
        public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
         //取得xml文件命名空间url String namespaceUri
    = getNamespaceURI(ele);
         //初始化命名空间处理器 NamespaceHandler handler
    = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; }
         //根据传入元素获得相应的beanDefinition解析器解析
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }

     8、对另一个解析方法parseDefaultElement()再进行探讨,它主要用来解析我们自定义的<bean>、<import>、<alias>、<beans>标签

        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
         //这块代码很清晰的表示了对各明确元素的处理
         //对improt元素处理
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); }
         //对alias元素处理
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); }
         //对bean元素处理
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); }
         //对beans元素处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }

     9、就以bean处理为例子吧,对bean的处理也是最复杂的

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
         //解析bean,取得bean信息持有者 BeanDefinitionHolder bdHolder
    = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) {
           //包装bean,额外操作 bdHolder
    = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 注册被包装好的最终的beanDefintion BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 发送注册事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }

    10、由代理对bean元素解析

        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
            return parseBeanDefinitionElement(ele, null);
        }
        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
         //根据英文名也很好理解,获取id和name String id
    = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);     //省略 String beanName = id; //省略
         //对bean元素各方面进行解析,里面有很多细节处理,它的描述信息主要在这里生成
         //在这里我们获得的描述信息有:scope是否单例,isAbstract,lazy-init,autowire,dependCheck,depend-on,autowire-candidate
         //primary,init-method,destory-method,factory-method,factory-bean,className,parent,description,look-up,replace-method,
         //构造方法的name,type,index,属性的name,value等等,还设置extractSource,额外的资源供使用者扩展使用 AbstractBeanDefinition beanDefinition
    = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) {  //省略(若没有beanName则系统生成,有别名获取别名)
           //创建beanDefinitionHolder这个bean信息持有者类,将beanDefinition等信息传进去,并返回 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }

    11、正式注册处理完的beanDefinition信息,调用registerBeanDefinition()方法

        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {
    
            // 用beanName作为key值,注册beanDefinition信息
            String beanName = definitionHolder.getBeanName();
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
            // 如果有别名,注册别名和beanName绑定
            String[] aliases = definitionHolder.getAliases();
            if (aliases != null) {
                for (String alias : aliases) {
                    registry.registerAlias(beanName, alias);
                }
            }
        }
        @Override
        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException {
         //省略(可靠性判断)
         //这里主要就是把beanDefinition放入Map集合中由容器保存,这里省掉了对是否有旧的同名beanName的判断 this.beanDefinitionMap.put(beanName, beanDefinition);  //省略 }

    到此为止就把bean信息全部解析注册完成了,至于最后一步fireComponentRegistered()方法,是对BeanDefinition再做了一层包装,然后通知监听器,spring没有再进行处理,此处是用来给用户扩展用的。

    (pass:对bean的解说只是加载了一个bean的全部信息,执行完fireComponentRegistered()方法后,又进入了元素节点的循环解析,直到全部解析完成,XmlWebApplicationContext将保存存储有beanDefiniton信息的DefaultListableBeanFactory beanFactory,至此obtainFreshBeanFactory()方法才算运行完毕)

  • 相关阅读:
    docker入门——centos安装
    NET应用——你的数据安全有必要升级
    mysql事件机制——定时任务
    是时候升级你的Js工具了-分页【基于JQ】
    优美库图片系统
    爬虫之蜂鸟网图片爬取
    壁纸提取
    CSDN刷阅读数
    tkinter基础-输入框、文本框
    数据结构与算法之选择排序
  • 原文地址:https://www.cnblogs.com/sky-chen/p/6607843.html
Copyright © 2011-2022 走看看