美文网首页
spring解析xml(二)解析相关结构

spring解析xml(二)解析相关结构

作者: guessguess | 来源:发表于2020-06-29 11:35 被阅读0次

    1.测试方法代码

    public class Config {
        
        public static void main(String args[]) {
            ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
            System.out.println(applicationContext.getBean(HelloService.class).sayHello());
        }
    }
    

    2.什么是application。
    application就是我们所谓的上下文,容器。
    FileSystemXmlApplicationContext是application的一个具体实现。spring中有许多application的不同实现,如ClassPathXmlApplicationContext,AnnotationConfigApplicationContext。下面我们先从FileSystemXmlApplicationContext开始入手。

    3.结构如图所示


    image.png

    从上图的结构来看。其实整个容器是由几部分组成的。分别为ResourceLoader, BeanFactory, ApplicationEventPublisher, EnvironmentCapable, Lifecycle, Closeable。

    分别介绍几个概念,ResourceLoader资源加载器,其中我们的类,class文件其实便是资源,资源加载器就是负责去加载资源, 至于根据什么去找到资源,那便是路径。那么有ResourceLoader便会有Resouce,那么resouce怎么跟bean关联起来呢,ResourceLoader便是将加载到的resouce转换成beandefinition, 最后再注册到beanfactory中去。这里只是讲解一下概念,后续会细致一点讲。

    AbstractApplicationContext是一个核心抽象类,实现了大部分的功能,剩下的交由子类去实现。

    4.可能3讲的很抽象,那么下面从代码入手吧。
    先看会之前的测试代码

    public class Config {
        
        public static void main(String args[]) {
            ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
            System.out.println(applicationContext.getBean(HelloService.class).sayHello());
        }
    }
    

    为什么选择FileSystemXmlApplicationContext呢,其实AbstractXmlApplicationContext有多个实现类,所以随便挑一个进行讲解,其实ClassPathXmlApplicationContext也是大体功能是一样的。

    那么好了,进入主题,先从构造方法入手吧。

    
    /**
         * Create a new FileSystemXmlApplicationContext, loading the definitions
         * from the given XML file and automatically refreshing the context.
         * @param configLocation file path
         * @throws BeansException if context creation failed
         */
        public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }
    
    
    /**
         * Create a new FileSystemXmlApplicationContext with the given parent,
         * loading the definitions from the given XML files.
         * @param configLocations array of file paths
         * @param refresh whether to automatically refresh the context,
         * loading all bean definitions and creating all singletons.
         * Alternatively, call refresh manually after further configuring the context.
         * @param parent the parent context
         * @throws BeansException if context creation failed
         * @see #refresh()
         */
        public FileSystemXmlApplicationContext(
                String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
    
            super(parent);//此处主要作用是将自身作为一个路径解析器的变量,并且注入到父类中
            setConfigLocations(configLocations);//此处是将路径保存到父类中去
            if (refresh) {//是否需要刷新
                refresh();//刷新容器---这里其实才是核心逻辑
            }
        }
    

    先从构造方法参数的定义来看public FileSystemXmlApplicationContext(String configLocation),该构造方法上方的注解,创建一个新的FileSystemXmlApplicationContext,从码农给予的xml文件加载definitions,并且自动刷新容器。definitions其实是bean的一个包装类,记载了bean的相关信息。

    接下来看其内部调用的构造方法,public FileSystemXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)。这里总共分为三个方法讲解,分别为 super(parent), setConfigLocations(configLocations), refresh()

    首先从super(parent)看起

    public FileSystemXmlApplicationContext(
                String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
    
            super(parent);//此处主要作用是将自身作为一个路径解析器的变量,并且注入到父类
            。。。。。。下面的代码暂时忽略
        }
    最终到达的父类AbstractApplicationContext位置,this是一开始新建的FileSystemXmlApplicationContext实例
    
    AbstractApplicationContext中的
    public abstract class AbstractApplicationContext extends DefaultResourceLoader
            implements ConfigurableApplicationContext{
        private ResourcePatternResolver resourcePatternResolver;
        public AbstractApplicationContext() {
            this.resourcePatternResolver = getResourcePatternResolver();
        }
        protected ResourcePatternResolver getResourcePatternResolver() {
            return new PathMatchingResourcePatternResolver(this);
        }
    }
    
    那么PathMatchingResourcePatternResolver类的结构是怎么样的呢?
    public class PathMatchingResourcePatternResolver{
        private final ResourceLoader resourceLoader;
        public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
            Assert.notNull(resourceLoader, "ResourceLoader must not be null");
            this.resourceLoader = resourceLoader;
        }
    }
    

    根据代码,最后发现,FileSystemXmlApplicationContext实例将自己包装成PathMatchingResourcePatternResolver并且注入到AbstractApplicationContext中去。这里为什么FileSystemXmlApplicationContext实例可以包装成路径匹配资源解析器呢?因为AbstractApplicationContext本身是FileSystemXmlApplicationContext的父类,同时AbstractApplicationContext也是ResourceLoader的子类。其实说白了就是,基本的功能都是在AbstractApplicationContext中实现的,而FileSystemXmlApplicationContext实例将自己包装成资"源路径匹配资源解析器"最后又注入到AbstractApplicationContext中去。这么做的好处是,当FileSystemXmlApplicationContext改变了某些逻辑的时候,代码可以不用做任何调整。

    其次是setConfigLocations(configLocations),这段代码便是将解析后的路径,注入到AbstractRefreshableConfigApplicationContext的成员变量configLocations中去。

    最后讲解的是核心refresh(),篇幅有点长,放下一篇吧。

    相关文章

      网友评论

          本文标题:spring解析xml(二)解析相关结构

          本文链接:https://www.haomeiwen.com/subject/ofuptktx.html