• Spring 学习记录4 ResourceLoader


    ResourceLoader

    Spring的ApplicationContext继承了ResourceLoader接口.这个接口主要就是可以加载各种resource..

    接口还是比较简单的:

     1 /*
     2  * Copyright 2002-2014 the original author or authors.
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *      http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    16 
    17 package org.springframework.core.io;
    18 
    19 import org.springframework.util.ResourceUtils;
    20 
    21 /**
    22  * Strategy interface for loading resources (e.. class path or file system
    23  * resources). An {@link org.springframework.context.ApplicationContext}
    24  * is required to provide this functionality, plus extended
    25  * {@link org.springframework.core.io.support.ResourcePatternResolver} support.
    26  *
    27  * <p>{@link DefaultResourceLoader} is a standalone implementation that is
    28  * usable outside an ApplicationContext, also used by {@link ResourceEditor}.
    29  *
    30  * <p>Bean properties of type Resource and Resource array can be populated
    31  * from Strings when running in an ApplicationContext, using the particular
    32  * context's resource loading strategy.
    33  *
    34  * @author Juergen Hoeller
    35  * @since 10.03.2004
    36  * @see Resource
    37  * @see org.springframework.core.io.support.ResourcePatternResolver
    38  * @see org.springframework.context.ApplicationContext
    39  * @see org.springframework.context.ResourceLoaderAware
    40  */
    41 public interface ResourceLoader {
    42 
    43     /** Pseudo URL prefix for loading from the class path: "classpath:" */
    44     String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
    45 
    46 
    47     /**
    48      * Return a Resource handle for the specified resource.
    49      * The handle should always be a reusable resource descriptor,
    50      * allowing for multiple {@link Resource#getInputStream()} calls.
    51      * <p><ul>
    52      * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".
    53      * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".
    54      * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".
    55      * (This will be implementation-specific, typically provided by an
    56      * ApplicationContext implementation.)
    57      * </ul>
    58      * <p>Note that a Resource handle does not imply an existing resource;
    59      * you need to invoke {@link Resource#exists} to check for existence.
    60      * @param location the resource location
    61      * @return a corresponding Resource handle
    62      * @see #CLASSPATH_URL_PREFIX
    63      * @see org.springframework.core.io.Resource#exists
    64      * @see org.springframework.core.io.Resource#getInputStream
    65      */
    66     Resource getResource(String location);
    67 
    68     /**
    69      * Expose the ClassLoader used by this ResourceLoader.
    70      * <p>Clients which need to access the ClassLoader directly can do so
    71      * in a uniform manner with the ResourceLoader, rather than relying
    72      * on the thread context ClassLoader.
    73      * @return the ClassLoader (only {@code null} if even the system
    74      * ClassLoader isn't accessible)
    75      * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
    76      */
    77     ClassLoader getClassLoader();
    78 
    79 }
    View Code

    我感觉主要可能就是getResource方法了.

    具体使用

    实验如下:

     1 @RunWith(SpringJUnit4ClassRunner.class)
     2 @ContextConfiguration("classpath:test-application-context.xml")
     3 public class ResourceLoaderTest implements ApplicationContextAware {
     4     ApplicationContext applicationContext;
     5 
     6     @Test
     7     public void testLoadResource() throws IOException {
     8 
     9         Resource resource = applicationContext.getResource("classpath:test.properties");
    10         System.out.println(resource.exists()); // true
    11 
    12         Resource resource2 = applicationContext.getResource("/test.properties");
    13         System.out.println(resource2.exists()); // true
    14 
    15         Resource resource3 = applicationContext.getResource("test.properties");
    16         System.out.println(resource3.exists()); // true
    17 
    18         Resource resource4 = applicationContext.getResource("classpath:1.html");
    19         System.out.println(FileUtils.readFileToString(resource4.getFile())); // 文件内容
    20 
    21         Resource resource5 = applicationContext.getResource("https://www.baidu.com/");
    22         System.out.println(IOUtils.toString(resource5.getInputStream())); // 网页内容
    23 
    24         Resource resource6 = applicationContext.getResource("/spring/Config.class");
    25         System.out.println(resource6.exists()); // true
    26 
    27         Resource resource7 = applicationContext.getResource("org/springframework/context/support/GenericApplicationContext.class");
    28         System.out.println(resource7.exists()); // true
    29     }
    30 
    31     @Test
    32     public void a() {
    33         System.out.println(1);
    34     }
    35 
    36     @Override
    37     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    38         this.applicationContext = applicationContext;
    39     }
    40 }

    实验中发现:

    1.可以通过classpath:XXX下载classpath下的资源

    2.可以通过/XXX也是加载classpath下的资源

    3.直接XXX,可以根据不同的协议去加载资源(比如http),没有的话去加载classpath下的资源

    4.不光可以加载classes下的资源,也可以加载lib里jar里面的资源.

    我用的junit 测试,applicationcontext是GenericApplicationContext的实例,getResource方法调的是DefaultResourceLoader的实现

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

    从代码中我们可以发现,

    1.如果是/开头的资源,会调用getResourceByPath方法,最后返回的其实也是ClassPathResource

     1     /**
     2      * Return a Resource handle for the resource at the given path.
     3      * <p>The default implementation supports class path locations. This should
     4      * be appropriate for standalone implementations but can be overridden,
     5      * e.g. for implementations targeted at a Servlet container.
     6      * @param path the path to the resource
     7      * @return the corresponding Resource handle
     8      * @see ClassPathResource
     9      * @see org.springframework.context.support.FileSystemXmlApplicationContext#getResourceByPath
    10      * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
    11      */
    12     protected Resource getResourceByPath(String path) {
    13         return new ClassPathContextResource(path, getClassLoader());
    14     }
    15 
    16 
    17     /**
    18      * ClassPathResource that explicitly expresses a context-relative path
    19      * through implementing the ContextResource interface.
    20      */
    21     protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {
    22 
    23         public ClassPathContextResource(String path, ClassLoader classLoader) {
    24             super(path, classLoader);
    25         }
    26 
    27         @Override
    28         public String getPathWithinContext() {
    29             return getPath();
    30         }
    31 
    32         @Override
    33         public Resource createRelative(String relativePath) {
    34             String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
    35             return new ClassPathContextResource(pathToUse, getClassLoader());
    36         }
    37     }
    View Code

    2.如果是classpath:开头,也是ClassPathResource

    3.如果是XXX.XX的话用URL去找资源失败的话,还是会返回ClassPathResource,成功的话就是返回UrlResource.

    然后我想到了1个问题.就是我们在项目中加载文件的时候经常会用classpath*:.............这种形式在这里似乎没有出现,可能是Servlet环境下的ApplicationContext覆盖了getResource方法,也可能是其他方法加载资源..等我学习了其他的applicationcontext就明白了...可能会再做分享.

    小结

    我感觉使用resourceloader相比于getResource里面写classpath:xxxxxx比自己去getClass().getResource的好处在于:

    1.更简单清晰...看过去就知道资源是相对于classpath的...

    2.resourceloader产生的ClassPathResource对于你传入的路径字符串是会转化的...你传入的windows的也会被转化成/..而getClass那种并不会....所以getClass().getResource在传入的String拼接的时候如果用到了File.sperator可能会找不到资源,而resourceloader不会...不过更多的时候可能都不需要拼接...直接写1个完整的字符串用/分割路径就行了...

  • 相关阅读:
    24节气冬至
    最佳人体舒适温度是多少?
    常用正则
    点击按钮后的Loading处理
    支付时过渡动画
    npm ci 和 npm install
    Vue批量上传文件及实时进度
    HTML DOM classList 属性的使用
    Electron Uncaught ReferenceError: require is not defined
    javascript 深拷贝的问题
  • 原文地址:https://www.cnblogs.com/abcwt112/p/7489494.html
Copyright © 2020-2023  润新知