博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring源码分析(一)资源文件的加载
阅读量:6944 次
发布时间:2019-06-27

本文共 3954 字,大约阅读时间需要 13 分钟。

spring是日常开发中用的非常多的一个框架,那么spring究竟是如何帮我们简化开发?短短的几行配置里,spring究竟做了啥?后续几篇博客会分析下spring的源码。

从一个配置文件开始

使用xml配置spring的话,这个配置可以说非常熟悉了。

然后如果想通过spring容器来加载配置这个类,简单的代码如下。

public class TestDemo {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");        Person person = (Person) context.getBean("person");        System.out.println("person name:" + person.getName());    }}

假想下,如果让我来写spring,那么我要做的第一步是啥?我想会是找到配置文件,加载它(这里先不管使用java配置的方式)

Spring对资源的封装

spring对于各种各样的资源抽象了一个接口,比如文件资源或者类路径的资源。

public interface Resource extends InputStreamSource {   boolean exists();   default boolean isReadable() {       return true;   }   default boolean isOpen() {       return false;   }   default boolean isFile() {       return false;   }   URL getURL() throws IOException;   URI getURI() throws IOException;   File getFile() throws IOException;   long contentLength() throws IOException;   long lastModified() throws IOException;   Resource createRelative(String relativePath) throws IOException;   String getFilename();   String getDescription();}

所有的资源都会通过这个类来抽象。

那么简单的说来,spring容器加载资源的第一步,就是加载配置文件,将这个配置文件转换成spring的抽象资源Resource

源码实现

源码还是比较简单的

1)在构造函数里,将路径处理下(替换占位符)存储在成员变量里
2)将配置文件转换为spring的一个资源(具体步骤在loadBeanDefinition里)

解析路径代码

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)        throws BeansException {    //1、父类设置ResourcePatternResolver    super(parent);    //设置路径到configLocations成员变量里,中间会执行一步,替换${}这样的占位符,    //比如路径填了 ${path}/application.xml,可以被替换为.properties里的路径    setConfigLocations(configLocations);    if (refresh) {                //实际启动spring容器        refresh();    }}public void setConfigLocations(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++) {            //把占位符给换掉 比如${path.xxx} 换成PropertyPlaceHolder的值            this.configLocations[i] = resolvePath(locations[i]).trim();        }    }    else {        this.configLocations = null;    }}

AbstractXmlApplicationContext类

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {    Resource[] configResources = getConfigResources();    if (configResources != null) {        reader.loadBeanDefinitions(configResources);    }    String[] configLocations = getConfigLocations();    if (configLocations != null) {        reader.loadBeanDefinitions(configLocations);    }}

最后会回调DefaultResourceLoader的getResources方法

public Resource getResource(String location) {    Assert.notNull(location, "Location must not be null");    for (ProtocolResolver protocolResolver : this.protocolResolvers) {        Resource resource = protocolResolver.resolve(location, this);        if (resource != null) {            return resource;        }    }    if (location.startsWith("/")) {        return getResourceByPath(location);    }    else if (location.startsWith(CLASSPATH_URL_PREFIX)) {        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());    }    else {        try {            // Try to parse the location as a URL...            URL url = new URL(location);            return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));        }        catch (MalformedURLException ex) {            // No URL -> resolve as resource path.            // 没有填前缀,最后会被解析为 ClassPathContextResource            return getResourceByPath(location);        }    }}protected Resource getResourceByPath(String path) {    return new ClassPathContextResource(path, getClassLoader());}

由于这里没有配置协议前缀(比如classpath:xxx)最后资源会被解析为ClassPathContextResource

ResourceLoader和ResourcePatternLoader

img_182c9230d0d39924223542ef52bd5540.png

总结

spring启动会去加载配置文件,将配置文件转换为spring可以识别的Resource

转载地址:http://ikonl.baihongyu.com/

你可能感兴趣的文章
冒充方法call和apply 简述
查看>>
我是如何开始去了解Python函数式编程--Python函数式编程初涉
查看>>
解决文字和表情存储到msql数据库出现异常问题
查看>>
oracle python
查看>>
Python 17.3 WSGI接口
查看>>
mysql日常小练习-20171012
查看>>
将Python脚本打包成可执行文件
查看>>
Linux motd详解
查看>>
根据status 对mysql进行性能优化
查看>>
java之CountDownLatch看看笔记
查看>>
Implement_strStr --leetcode
查看>>
我的友情链接
查看>>
centos 7设置smtp发送163邮件
查看>>
我的友情链接
查看>>
文件服务器之Branchcache分布式缓存
查看>>
我的友情链接
查看>>
Java设计模式百例 - 抽象工厂模式
查看>>
依赖倒置原则 DIP(Dependence Inversion Principle)
查看>>
智能硬件的简单剖析
查看>>
三种不同的交换机mac端口绑定模式的区别
查看>>