zoukankan      html  css  js  c++  java
  • classpath: spring 中的查找方式

    Spring可以通过指定classpath*:与classpath:前缀加路径的方式从classpath加载文件,如bean的定义文件.classpath*:的出现是为了从多个jar文件中加载相同的文件.classpath:只能加载找到的第一个文件.

    比如 resource1.jar中的package 'com.test.rs' 有一个 'jarAppcontext.xml' 文件,内容如下:

    <bean name="ProcessorImplA" class="com.test.spring.di.ProcessorImplA" />

    resource2.jar中的package 'com.test.rs' 也有一个 'jarAppcontext.xml' 文件,内容如下:

    <bean id="ProcessorImplB" class="com.test.spring.di.ProcessorImplB" />

    通过使用下面的代码则可以将两个jar包中的文件都加载进来

    ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath*:com/test/rs/jarAppcontext.xml");

    而如果写成下面的代码,就只能找到其中的一个xml文件(顺序取决于jar包的加载顺序)

    ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:com/test/rs/jarAppcontext.xml");

    classpath*:的使用是为了多个component(最终发布成不同的jar包)并行开发,各自的bean定义文件按照一定的规则:package+filename,而使用这些component的调用者可以把这些文件都加载进来.

    classpath*:的加载使用了classloader的 getResources() 方法,如果是在不同的J2EE服务器上运行,由于应用服务器提供自己的classloader实现,它们在处理jar文件时的行为也许会有所不同。 要测试classpath*: 是否有效,可以用classloader从classpath中的jar文件里加载文件来进行测试:getClass().getClassLoader().getResources("<someFileInsideTheJar>")。(上面的例子是在sun的jre中运行的状态)

     从Spring的源码,在PathMatchingResourcePatternResolver类中,我们可以更清楚的了解其对的处理:如果是以classpath*开头,它会遍历classpath.

    1. protected Resource[] findAllClassPathResources(String location) throws IOException {  
    2.     String path = location;  
    3.     if (path.startsWith("/")) {  
    4.         path = path.substring(1);  
    5.     }  
    6.     Enumeration resourceUrls = getClassLoader().getResources(path);  
    7.     Set<Resource> result = new LinkedHashSet<Resource>(16);  
    8.     while (resourceUrls.hasMoreElements()) {  
    9.         URL url = (URL) resourceUrls.nextElement();  
    10.         result.add(convertClassLoaderURL(url));  
    11.     }  
    12.     return result.toArray(new Resource[result.size()]);  
    13. }  

    http://blog.csdn.net/kkdelta/article/details/5560210,简介了在JAVA里遍历classpath中读取找到的所有符合名称的文件.

    另外在加载resource的时候,其他前缀的意义如下表所示:注意classpath*只能用与指定配置文件的路径,不能用在用于 getResource的参数.如 appContext.getResource("classpath*:conf/bfactoryCtx.xml")会异常的.

    前缀例子说明

    classpath:

    classpath:com/myapp/config.xml

    从classpath中加载。

    file:

    file:/data/config.xml

    作为 URL 从文件系统中加载。

    http:

    http://myserver/logo.png

    作为 URL 加载。

    (none)

    /data/config.xml

    根据 ApplicationContext 进行判断。

    从Spring的源码可以看出原因:如果是classpath:开头,从classpath加载,否则尝试URL,如果失败,调用 getResourceByPath

    1. public Resource getResource(String location) {  
    2.         Assert.notNull(location, "Location must not be null");  
    3.         if (location.startsWith(CLASSPATH_URL_PREFIX)) {  
    4.             return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  
    5.         }  
    6.         else {  
    7.             try {  
    8.                 // Try to parse the location as a URL...  
    9.                 URL url = new URL(location);  
    10.                 return new UrlResource(url);  
    11.             }  
    12.             catch (MalformedURLException ex) {  
    13.                 // No URL -> resolve as resource path.  
    14.                 return getResourceByPath(location);  
    15.             }  
    16.         }  
    17.     }  


    getResourceByPath会被不同ApplicationContext 实现覆盖.

    如 GenericWebApplicationContext覆盖为如下:

    1. protected Resource getResourceByPath(String path) {  
    2.         return new ServletContextResource(this.servletContext, path);  
    3.     }  
    4.   
    5. 如 FileSystemXmlApplicationContext覆盖为如下:  
    6.   
    7. protected Resource getResourceByPath(String path) {  
    8.         if (path != null && path.startsWith("/")) {  
    9.             path = path.substring(1);  
    10.         }  
    11.         return new FileSystemResource(path);  
    12.     }  

    最终从文件加载的时候仍然是JAVA中常见的读取文件的方法:

    如ClassPathResource得到inputstream的方法是利用class loader.

    1. public InputStream getInputStream() throws IOException {  
    2.     InputStream is;  
    3.     if (this.clazz != null) {  
    4.         is = this.clazz.getResourceAsStream(this.path);  
    5.     }  

    如FileSystemResource得到inputstream的方法是利用FileInputStream.

        public InputStream getInputStream() throws IOException {
            return new FileInputStream(this.file);
        }

    如ServletContextResource得到inputstream的方法是利用servletContext.getResourceAsStream.

      1. public InputStream getInputStream() throws IOException {  
      2.     InputStream is = this.servletContext.getResourceAsStream(this.path);  
      3.     if (is == null) {  
      4.         throw new FileNotFoundException("Could not open " + getDescription());  
      5.     }  
      6.     return is;  
  • 相关阅读:
    bzoj 1017 魔兽地图DotR
    poj 1322 chocolate
    bzoj 1045 糖果传递
    poj 3067 japan
    timus 1109 Conference(二分图匹配)
    URAL 1205 By the Underground or by Foot?(SPFA)
    URAL 1242 Werewolf(DFS)
    timus 1033 Labyrinth(BFS)
    URAL 1208 Legendary Teams Contest(DFS)
    URAL 1930 Ivan's Car(BFS)
  • 原文地址:https://www.cnblogs.com/1995hxt/p/5800257.html
Copyright © 2011-2022 走看看