资讯专栏INFORMATION COLUMN

spring-framework的Resource知识点

Jonathan Shieber / 1200人阅读

摘要:接口类三个具有代表性的实现类通过的和,我们找到利用去解析路径配置文件的路径。上面可能讲的有点绕,但却是入口之一。根据路径的特性,分别封装为或对象。另外用包里的做了实验,发现可以读到包里的信息。则是包的根地方,如,用于公共配置文件。

接口类:org.springframework.core.io.Resource
三个具有代表性的实现类:

org.springframework.web.context.support.ServletContextResource

org.springframework.core.io.ClassPathResource

org.springframework.core.io.UrlResource

通过XmlWebApplicationContext的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)和loadBeanDefinitions(XmlBeanDefinitionReader reader),我们找到ApplicationContext利用ServletContextResourcePatternResolver去解析路径(配置文件的路径)。
上面可能讲的有点绕,但却是入口之一。 我们可以跳出这个细节来看,其实Resource是通过ResourceLoader去加载(名字也能看出啦),而ApplicationContex是ResourceLoader的一个实现。所以Application有getResource()的方法,但具体实例化Resource,ApplicationContex不亲自干,而是用组合的形式交给ResourcePatternResolver去处理,这是因为不同环境寻找配置文件的形式不一样,而其中PathMatchingResourcePatternResolver和ServletContextResourcePatternResolver是ResourcePatternResolver的实现,用于不同环境中加载Resource。

ServletContextResourcePatternResolver会将路径封装成Resource对象。根据路径的特性,分别封装为ServletContextResource、ClassPathResource或UrlResource对象。

这里个路径清理的工具类StringUtils.cleanPath,参考《StringUtils知识点》

我们先看一些默认路径的知识:

package org.springframework.jc;

import org.apache.commons.logging.Log;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

public class ClassGetResourceTest {

    public static void main(String[] args) throws IOException {
        System.out.println("============================================env===================================");
        Map map = System.getenv();
        for (Iterator itr = map.keySet().iterator(); itr.hasNext(); ) {
            String key = itr.next();
            System.out.println(key + "=" + map.get(key));
        }
        System.out.println("============================================properties===================================");
        Properties properties = System.getProperties();
        for(String key:properties.stringPropertyNames()){
            System.out.println(key + "=" + properties.get(key));  // user.dir=/home/cherry/git/spring-framework
        }
        System.out.println(ClassGetResourceTest.class.getResource(""));  //file:/home/cherry/git/spring-framework/spring-core/out/test/classes/org/springframework/jc/
        System.out.println(ClassGetResourceTest.class.getResource("/")); //file:/home/cherry/git/spring-framework/spring-core/out/test/classes/

        //哟哟,不同包下的类,Log.class.getResource("")是不一样的!!! 可以获取jar包里的配置文件哦,如commons-logging-1.2.jar包
        System.out.println(Log.class.getResource(""));  //jar:file:/home/cherry/.gradle/caches/modules-2/files-2.1/commons-logging/commons-logging/1.2/4bfc12adfe4842bf07b657f0369c4cb522955686/commons-logging-1.2.jar!/org/apache/commons/logging/
        System.out.println(Log.class.getResource("/")); //file:/home/cherry/git/spring-framework/spring-core/out/test/classes/


        File file = new File("test.txt");
        file.createNewFile();
        System.out.println(file.getAbsolutePath());  //使用user.dir作为根目录

        System.out.println(ClassGetResourceTest.class.getName() + ".ROOT");

        System.out.println(ClassGetResourceTest.class.getClassLoader());                        //sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(ClassGetResourceTest.class.getClassLoader().getResource(""));  //file:/home/cherry/git/spring-framework/spring-core/out/test/classes/
                                                                                                //作用和ClassGetResourceTest.class.getResource("/")一样

        System.out.println(ClassGetResourceTest.class.getClassLoader().getResource("/")); //null
                                                                                                //ClassLoader.getResource不可以使用"/"

        //不同包下的类,结果也与ClassGetResourceTest.class.getClassLoader()一样,于是不可以获取jar包里的配置文件哦,如commons-logging-1.2.jar包
        System.out.println(Log.class.getClassLoader());                        //sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(Log.class.getClassLoader().getResource(""));  //file:/home/cherry/git/spring-framework/spring-core/out/test/classes/
                                                                                                //作用和ClassGetResourceTest.class.getResource("/")一样

        System.out.println(Log.class.getClassLoader().getResource("/")); //null
                                                                                                //ClassLoader.getResource不可以使用"/"


    }
}

从上可以得出一些结论:

user.dir是jvm的系统属性,默认是取你执行命令时的目录,也就是说如果在/mydata使用命令 /mydata/jc-test/server.sh start,此时user.dir为/mydata,如果在/mydata/other目录执行/mydata/jc-test/server.sh start,则此时user.dir为/mydata/other

class.getResource方法,根据是否以根目录“/”开始来决定文件目录:

class.getResource("")相对于当前类的目录,是个相对路径。例如一些不是公共的配置文件,仅仅这个类或这个包下使用的配置文件。   另外用jar包里的class做了实验,发现可以读到jar包里的信息。   
class.getResource("/")则是包的根地方,如..../classes/,用于公共配置文件。

ClassLoader.getResource方法,不可以根目录“/”开始来决定文件目录,否则为null:

ClassLoader.getResource("")则是包的根地方,如..../classes/  
ClassLoader.getResource("")为null

好了,我们现在回归主题,org.springframework.core.io.ClassPathResource能够根据类或加载器(classload)来加载类路径的文件,原文:

Resource implementation for class path resources. Uses either a given ClassLoader or a given Class for loading resources.

核心逻辑:

/**
     * This implementation opens an InputStream for the given class path resource.
     * @see java.lang.ClassLoader#getResourceAsStream(String)
     * @see java.lang.Class#getResourceAsStream(String)
     */
    @Override
    public InputStream getInputStream() throws IOException {
        InputStream is;
        if (this.clazz != null) {
            is = this.clazz.getResourceAsStream(this.path);
        }
        else if (this.classLoader != null) {
            is = this.classLoader.getResourceAsStream(this.path);
        }
        else {
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (is == null) {
            throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
        }
        return is;
    }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67937.html

相关文章

  • Spring笔记03_AOP

    摘要:介绍什么是在软件业,为的缩写,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。切面是切入点和通知引介的结合。切面类权限校验。。。 1. AOP 1.1 AOP介绍 1.1.1 什么是AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术...

    blair 评论0 收藏0
  • spring-framework源码研读

    摘要:额外知识点参考知识点加载策略资源后,容器启动时会调用的方法。从获取对象对象,如果存在则抛异常。这个是重点核心的知识点,参考知识点。看到这里应该知道每一层的作用吧,一层一层往上递进第四步正在研读 1.根据我们常用的web.xml里,我们找到的org.springframework.web.context.ContextLoaderListener。web.xml如下 moo...

    rottengeek 评论0 收藏0
  • Spring笔记04_AOP注解开发_模板_事务

    摘要:后置增强周杰伦环绕通知在切面类中添加以下方法环绕通知环绕前增强环绕前增强测试前置增强保存订单。。。不使用事务管理。 1. Spring基于AspectJ的注解的AOP开发 1. 1 SpringAOP的注解入门 创建项目,导入jar包 需要导入Spring基础包4+2 需要导入AOP联盟包、AspectJ包、Spring整合Aspect包Spring-aop包 Spring整合单...

    youkede 评论0 收藏0
  • 基于注解方式配置springMVC 并整合mybatis(一)

    摘要:在实战一书中前面两部分分别介绍了和的高级特性,并且基于类配置有一套层的,但是没有将层整合层,于是我试着整合了下,也方便以后写测试。 在《springBoot实战》 一书中前面两部分分别介绍了spring 和 springMVC的高级特性,并且基于java类配置有一套web层的demo,但是没有将web层整合dao层,于是我试着整合了下,也方便以后写测试demo。下面是我的整理 pom....

    岳光 评论0 收藏0
  • Spring入门看这一篇就够了

    摘要:甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。这就是的核心思想。统一配置,便于修改。带参数的构造函数创建对象首先,就要提供带参数的构造函数接下来,关键是怎么配置文件了。 前言 前面已经学习了Struts2和Hibernate框架了。接下来学习的是Spring框架...本博文主要是引入Spring框架... Spring介绍 Spring诞生: 创建Spring的...

    superw 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<