Spring源码之Resource加载源码解析(三)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取 2000+ 道 Java 面试题

ResourceLoader 架构概览

ResourceLoader接口用于返回Resource对象;其实现可以看作是一个生产Resource的工厂类。
20191123100273\_1.png
可以分为两类:
第一类:默认资源加载器DefaultResourceLoader及其子类;
Spring提供了一个适用于所有环境的DefaultResourceLoader实现,可以返回ClassPathResource、UrlResource;还提供一个用于web环境的ServletContextResourceLoader,它继承了DefaultResourceLoader的所有功能,又额外提供了获取ServletContextResource的支持。
第二类: 应用上下文ApplicationContext接口及其实现类;
ApplicationContext的主要实现类ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。本次不做说明,后面会单独介绍ApplicationContext。

ResourceLoader接口源码解析

    //通过ResourceLoader获取资源
    public interface ResourceLoader {

        //加载的类路径伪URL前缀:“classpath:”
        String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

        //根据提供的location参数返回相应的Resource对象
        Resource getResource(String location);

        //返回加载这些Resource的ClassLoader
        ClassLoader getClassLoader();

    }

ResourceLoader在进行加载资源时需要使用前缀来指定需要加载:“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource资源,如果不加前缀则需要根据当前上下文来决定,DefaultResourceLoader默认实现可以加载classpath资源

DefaultResourceLoader及其子类源码解析

    public class DefaultResourceLoader implements ResourceLoader {
        //加载该资源类加载器
        private ClassLoader classLoader;

        //构造函数
        public DefaultResourceLoader() {
            //默认:实际资源访问时使用的线程上下文类加载器
            this.classLoader = ClassUtils.getDefaultClassLoader();
        }

        //构造函数
        public DefaultResourceLoader(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }

        //设置类加载器
        public void setClassLoader(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }

        //获取类加载器,未设置,则返回实际资源访问时使用的线程上下文类加载器
        public ClassLoader getClassLoader() {
            return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
        }

        //根据提供的location参数返回相应的资源句柄Resource。
        public Resource getResource(String location) {
            Assert.notNull(location, "Location must not be null");
            //“classpath:”前缀,返回ClassPathResource对象
            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...
                    //尝试将location转化为URL,再返回UrlResource对象
                    URL url = new URL(location);
                    return new UrlResource(url);
                }
                catch (MalformedURLException ex) {
                    //不是URL,则解析为资源路径。
                    return getResourceByPath(location);
                }
            }
        }

        //返回给定路径path上资源的资源句柄Resource。
        protected Resource getResourceByPath(String path) {
            //默认实现支持类路径位置
            return new ClassPathContextResource(path, getClassLoader());
        }

        //类加载路径下的资源
        private static class ClassPathContextResource extends ClassPathResource implements ContextResource {

            public ClassPathContextResource(String path, ClassLoader classLoader) {
                super(path, classLoader);
            }

            public String getPathWithinContext() {
                return getPath();
            }

            // 关键 -> 创建相相对于当前资源路径下的资源。
            // 假设当前的 file 路径为 D:/DEMO/HELLO.TXT,且 relativePath = GOOD.TXT
            // 则该方法创建的资源路径为 D:/DEMO/GOOD.TXT 
            @Override
            public Resource createRelative(String relativePath) {
                String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
                return new ClassPathContextResource(pathToUse, getClassLoader());
            }
        }

    }

    //servlet上下文资源加载器
    public class ServletContextResourceLoader extends DefaultResourceLoader {

        private final ServletContext servletContext;

        //构造函数
        public ServletContextResourceLoader(ServletContext servletContext) {
            this.servletContext = servletContext;
        }

        //此实现支持Web应用程序根目录下的文件路径。
        @Override
        protected Resource getResourceByPath(String path) {
            return new ServletContextResource(this.servletContext, path);
        }

    }
    //文件系统资源加载器
    public class FileSystemResourceLoader extends DefaultResourceLoader {
        //将资源路径解析为文件系统路径。
        @Override
        protected Resource getResourceByPath(String path) {
            if (path != null && path.startsWith("/")) {
                path = path.substring(1);
            }
            return new FileSystemContextResource(path);
        }

        //文件系统里面的资源
        private static class FileSystemContextResource extends FileSystemResource implements ContextResource {

            public FileSystemContextResource(String path) {
                super(path);
            }

            public String getPathWithinContext() {
                return getPath();
            }
        }

    }

    //类相关资源加载器
    public class ClassRelativeResourceLoader extends DefaultResourceLoader {

        private final Class clazz;

        //创建一个指定类的相关资源加载器
        public ClassRelativeResourceLoader(Class clazz) {
            Assert.notNull(clazz, "Class must not be null");
            this.clazz = clazz;
            setClassLoader(clazz.getClassLoader());
        }

        protected Resource getResourceByPath(String path) {
            return new ClassRelativeContextResource(path, this.clazz);
        }

        //获取类路径下的资源文件
        private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource {

            private final Class clazz;

            public ClassRelativeContextResource(String path, Class clazz) {
                super(path, clazz);
                this.clazz = clazz;
            }

            public String getPathWithinContext() {
                return getPath();
            }

            @Override
            public Resource createRelative(String relativePath) {
                String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
                return new ClassRelativeContextResource(pathToUse, this.clazz);
            }
        }

    }

来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring源码之Resource加载源码解析(三)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏