Spring DefaultResourceLoader

Spring DefaultResourceLoader

Spring DefaultResourceLoader继承ResourceLoader接口,用来加载资源, 通过ResourceLoader,给定其可以接受的资源路径,我们可以获得对应资源的Resource对象,然后进行进行相应的资源访问 。

Spring提供了一个默认的实现类DefaultResourceLoader,可以用来加载classpath或者文件系统中的某个文件,也可以采用URL的形式加载某个网络的资源。

ResourceLoader接口定义如下:

public interface ResourceLoader {

	/** Pseudo URL prefix for loading from the class path: "classpath:". */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	/**
	 * 根据给定的资源路径,返回响应的Resource资源对象
	 * 支持如下三种形式:
	 *"file:C:/test.dat".
	 *"classpath:test.dat".
	 *"WEB-INF/test.dat".
	
	 */
	Resource getResource(String location);
	/**
	 * 获取资源类加载器
	 */
	@Nullable
	ClassLoader getClassLoader();

}

DefaultResourceLoader类中定义方法及属性如下:

public class DefaultResourceLoader implements ResourceLoader {
	@Nullable
	private ClassLoader classLoader;
	private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet<>(4);
	private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);

	//构造方法中获取默认个类加载器
	public DefaultResourceLoader() {
		this.classLoader = ClassUtils.getDefaultClassLoader();
	}

	public DefaultResourceLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	public void setClassLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
	//返回类加载器
	@Override
	@Nullable
	public ClassLoader getClassLoader() {
		return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
	}

	/**
	 * 注册资源解析器,会覆盖默认的资源规则
	 */
	public void addProtocolResolver(ProtocolResolver resolver) {
		Assert.notNull(resolver, "ProtocolResolver must not be null");
		this.protocolResolvers.add(resolver);
	}

	/**
	 * Return the collection of currently registered protocol resolvers,
	 * allowing for introspection as well as modification.
	 * @since 4.3
	 */
	public Collection<ProtocolResolver> getProtocolResolvers() {
		return this.protocolResolvers;
	}

	/**
	 * Obtain a cache for the given value type, keyed by {@link Resource}.
	 * @param valueType the value type, e.g. an ASM {@code MetadataReader}
	 * @return the cache {@link Map}, shared at the {@code ResourceLoader} level
	 * @since 5.0
	 */
	@SuppressWarnings("unchecked")
	public <T> Map<Resource, T> getResourceCache(Class<T> valueType) {
		return (Map<Resource, T>) this.resourceCaches.computeIfAbsent(valueType, key -> new ConcurrentHashMap<>());
	}

	/**
	 * 清空资源缓存
	 */
	public void clearResourceCaches() {
		this.resourceCaches.clear();
	}


	//加载资源并返回Resource对象
	@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		//如果有ProtocolResolver,会优先调用
		for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
			Resource resource = protocolResolver.resolve(location, this);
            //根据返回值是否为null来判断是否解决 资源加载的问题
			if (resource != null) {
				return resource;
			}
		}
		//资源路径是否以/开头
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}//判断资源路径是否以classpath:开头
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// T尝试将资源路径转化为URL形式去加载
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// 当上面无法转换为 URL的形式事,尝试从相对路径中加载资源
				return getResourceByPath(location);
			}
		}
	}

	//从相对路径中下载资源
	protected Resource getResourceByPath(String path) {
		return new ClassPathContextResource(path, getClassLoader());
	}


	/**
	 * DefaultResourceLoader内部类类,用来加载相对路径的资源,可以参看ClassPathResource
	 https://www.cnblogs.com/haizhilangzi/p/12717368.html
	 */
	protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

		public ClassPathContextResource(String path, @Nullable 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());
		}
	}

}

关于ProtocolResolver接口的详细使用,请参考 Spring ProtocolResolver

测试代码

        ResourceLoader resourceLoader = new DefaultResourceLoader();


        //获取classpath:上的资源
//        Resource resource = resourceLoader.getResource(
//                "classpath:resource/conf.txt");

        //获取相对路径上的某个资源,相当于classpath:
//        Resource resource = resourceLoader.getResource(
//                "resource/conf.txt");
        //同样是获取classpath:上的资源
//        Resource resource = resourceLoader.getResource(
//                "/resource/conf.txt");

        //获取网络上的资源
        Resource resource = resourceLoader.getResource(
                "https://www.cnblogs.com/haizhilangzi/p/12717368.html");


        System.out.println(resource.getFilename());
        System.out.println(resource.contentLength());
        System.out.println(resource.getURL());
        System.out.println(resource.getURI());

        InputStream inputStream = resource.getInputStream();

        StringBuffer out = new StringBuffer();
        byte[] b = new byte[4096];
        for (int n; (n = inputStream.read(b)) != -1; ) {
            out.append(new String(b, 0, n));
        }
        System.out.println(out);
原文地址:https://www.cnblogs.com/haizhilangzi/p/12764576.html