在日常程序开发中,处理外部资源是很繁琐的事情,在上一篇文章里面我们已经介绍了有关资源定义的问题,那么如何加载这些资源呢。spring定义了不同的加载Resource的加载策略,主要用来返回一个Resource对象,说白了,你可以把他看做Resource的一个工厂。我们先来分析下。

1.ResourceLoader 类,这是定义资源加载策略的顶层接口,主要有两个方法。有两个直接的实现类:DefaultResourceLoader,ResourcePatternResolver

package com.wang.spring.beans.resourceLoader;

import com.wang.spring.beans.resource.Resource;

/**
 * @author wxe
 * @since 1.0.0
 */
public interface ResourceLoader {
    public static final String CLASSPATH_URL_PREFIX = "classpath:";
    /**
     * 获取资源
     * @param location
     * @return
     */
    Resource getResource(String location);
    /**
     * 获取ClassLoader
     * @return
     */
    ClassLoader getClassLoader();
}

2.DefaultResourceLoader类,这个是spring提供的默认ResourceLoader.其中根据location可以返回ClasPathResource、UrlResource实例等。ResourceLoader在进行加载资源时需要根据location的前缀来判断到底该返回哪种Resource.主要是判断:1)如果location以"/"开始的路径,则根据DefaultResourceLoader直接返回ClassPathContextResource,这个内部静态类getResourceByPath()方法默认返回ClassPathContextResource实例,在FileSystemResourceLoader中有不同实现。3)如果不是这两种情况,则返回URLResource.但是如果是以类似resources/META-INF/MENIFEST.MF的相对路径,创建URL的时候,会抛出异常,这个时候则返回ClassPathContextResource

package com.wang.spring.beans.resourceLoader;

import java.net.MalformedURLException;
import java.net.URL;

import com.wang.spring.beans.resource.ClassPathResource;
import com.wang.spring.beans.resource.ContextResource;
import com.wang.spring.beans.resource.Resource;
import com.wang.spring.utils.ClassUtils;

/**
 * 默认资源加载,可以返回ClassPathResource、UrlResource
 * @author wxe
 * @since 1.0.0
 */
public class DefaultResourceLoader implements ResourceLoader {

    private ClassLoader classLoader;
    
    /**
     * 使用前缀来判断需要加载返回什么类型的Resource,“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource资源
     * 如果没有添加前缀
     */
    @Override
    public Resource getResource(String location) {
        //如果以"/"开头,则根据path判断,返回ClassPathContextResource
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        //如果以"classpath:"开头,则返回ClassPathResource,并且传入的path需要截取掉classpath:前缀
        if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                URL url = new URL(location);
                return new UrlResource(url);
            } catch (MalformedURLException e) {
                //创建不成功,根据path返回Resource
                return getResourceByPath(location);
            }
        }
    }

    /**
     * 根据路径获取Resource
     * @param path
     * @return
     */
    protected Resource getResourceByPath(String path) {
        return new ClassPathContextResource(path, getClassLoader());
    }
    
    @Override
    public ClassLoader getClassLoader() {
        return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
    }
    
    /**
     * 
     * @author wxe
     * @since 1.0.0
     */
    protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

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

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

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

}

3.ResourcePatternResolver,这个接口只有一个方法,就是getResources()但是,这里与之前返回的不一样,返回的是一个Resouce数组,也就是说这个接口可以返回多个Resource。这个接口主要是为了适应ant风格路径而准备的。ANT通配符有三种:                  * ——匹配0或者任意数量的字符。比如URL路径为:classpath*:applicationContext-*.xml,表示在所有以classpath开始的路径中,所有以applicationContext-开始的xml文件。

?——匹配任何单字符,比如URL路径为:classpath:applicationContext-*.xml,表示在classpath路径下,任何以applicationContext-开始的xml文件。比如classpath:applicationContext-A.xml可以匹配到,但是classpath:applicationContext-AA.xml无法匹配。

**——匹配0或者更多的目录,比如URL路径为:“cn/**/config.xml”表示在任何cn目录下,任何子目录中的config.xml文件。将匹配“cn /config.xml”,也匹配“cn/javass/spring/config.xml”。

package com.wang.spring.beans.resourceLoader;

import java.io.IOException;

import com.wang.spring.beans.resource.Resource;


/**
 *用于匹配"classpath*:"的路径,获取多个Resource,简化路径配置的定义
 * @author wxe
 * @since 1.0.0
 */
public interface ResourcePatternResolver extends ResourceLoader {
    
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    /**
     * 返回多个Resource
     * @param locationPattern
     * @return
     * @throws IOException
     */
    Resource[] getResources(String locationPattern) throws IOException;
}

4.

我们只看继承,然后重写getResource()的方法。

@Override
    public Resource[] getResources(String locationPattern) throws IOException {
        return this.resourcePatternResolver.getResources(locationPattern);
    }

 

 posted on 2017-08-09 18:01  abysstoabyss  阅读(161)  评论(0)    收藏  举报