13. spring-容器: Resource接口详解

在日常程序开发中,处理外部资源是很繁琐的事情,我们可能需要处理URL资源、File资源资源、ClassPath相关资源等很多资源。因为处理这些资源需要使用不同的接口,这就增加了我们系统的复杂性;而且处理这些资源步骤都是类似的(打开资源、读取资源、关闭资源),因此如果能抽象出一个统一的接口来对这些底层资源进行统一访问,是不是很方便?而且使我们系统更加简洁,都是对不同的底层资源使用同一个接口进行访问。

Spring 提供一个Resource接口来统一这些底层资源一致性的访问,而且提供了一些便利的接口,从而能提供我们的生产力。

Resource定义
package org.springframework.core.io;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

import org.springframework.lang.Nullable;

/**
 * Interface for a resource descriptor that abstracts from the actual
 * type of underlying resource, such as a file or class path resource.
 *
 * <p>An InputStream can be opened for every resource if it exists in
 * physical form, but a URL or File handle can just be returned for
 * certain resources. The actual behavior is implementation-specific.
 *
 * @author Juergen Hoeller
 * @since 28.12.2003
 * @see #getInputStream()
 * @see #getURL()
 * @see #getURI()
 * @see #getFile()
 * @see WritableResource
 * @see ContextResource
 * @see UrlResource
 * @see FileUrlResource
 * @see FileSystemResource
 * @see ClassPathResource
 * @see ByteArrayResource
 * @see InputStreamResource
 */
public interface Resource extends InputStreamSource {

	/**
	 * Determine whether this resource actually exists in physical form.
	 * <p>This method performs a definitive existence check, whereas the
	 * existence of a {@code Resource} handle only guarantees a valid
	 * descriptor handle.
	 */
	boolean exists();

	/**
	 * Indicate whether non-empty contents of this resource can be read via
	 * {@link #getInputStream()}.
	 * <p>Will be {@code true} for typical resource descriptors that exist
	 * since it strictly implies {@link #exists()} semantics as of 5.1.
	 * Note that actual content reading may still fail when attempted.
	 * However, a value of {@code false} is a definitive indication
	 * that the resource content cannot be read.
	 * @see #getInputStream()
	 * @see #exists()
	 */
	default boolean isReadable() {
		return exists();
	}

	/**
	 * Indicate whether this resource represents a handle with an open stream.
	 * If {@code true}, the InputStream cannot be read multiple times,
	 * and must be read and closed to avoid resource leaks.
	 * <p>Will be {@code false} for typical resource descriptors.
	 */
	default boolean isOpen() {
		return false;
	}

	/**
	 * Determine whether this resource represents a file in a file system.
	 * A value of {@code true} strongly suggests (but does not guarantee)
	 * that a {@link #getFile()} call will succeed.
	 * <p>This is conservatively {@code false} by default.
	 * @since 5.0
	 * @see #getFile()
	 */
	default boolean isFile() {
		return false;
	}

	/**
	 * Return a URL handle for this resource.
	 * @throws IOException if the resource cannot be resolved as URL,
	 * i.e. if the resource is not available as descriptor
	 */
	URL getURL() throws IOException;

	/**
	 * Return a URI handle for this resource.
	 * @throws IOException if the resource cannot be resolved as URI,
	 * i.e. if the resource is not available as descriptor
	 * @since 2.5
	 */
	URI getURI() throws IOException;

	/**
	 * Return a File handle for this resource.
	 * @throws java.io.FileNotFoundException if the resource cannot be resolved as
	 * absolute file path, i.e. if the resource is not available in a file system
	 * @throws IOException in case of general resolution/reading failures
	 * @see #getInputStream()
	 */
	File getFile() throws IOException;

	/**
	 * Return a {@link ReadableByteChannel}.
	 * <p>It is expected that each call creates a <i>fresh</i> channel.
	 * <p>The default implementation returns {@link Channels#newChannel(InputStream)}
	 * with the result of {@link #getInputStream()}.
	 * @return the byte channel for the underlying resource (must not be {@code null})
	 * @throws java.io.FileNotFoundException if the underlying resource doesn't exist
	 * @throws IOException if the content channel could not be opened
	 * @since 5.0
	 * @see #getInputStream()
	 */
	default ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}

	/**
	 * Determine the content length for this resource.
	 * @throws IOException if the resource cannot be resolved
	 * (in the file system or as some other known physical resource type)
	 */
	long contentLength() throws IOException;

	/**
	 * Determine the last-modified timestamp for this resource.
	 * @throws IOException if the resource cannot be resolved
	 * (in the file system or as some other known physical resource type)
	 */
	long lastModified() throws IOException;

	/**
	 * Create a resource relative to this resource.
	 * @param relativePath the relative path (relative to this resource)
	 * @return the resource handle for the relative resource
	 * @throws IOException if the relative resource cannot be determined
	 */
	Resource createRelative(String relativePath) throws IOException;

	/**
	 * Determine a filename for this resource, i.e. typically the last
	 * part of the path: for example, "myfile.txt".
	 * <p>Returns {@code null} if this type of resource does not
	 * have a filename.
	 */
	@Nullable
	String getFilename();

	/**
	 * Return a description for this resource,
	 * to be used for error output when working with the resource.
	 * <p>Implementations are also encouraged to return this value
	 * from their {@code toString} method.
	 * @see Object#toString()
	 */
	String getDescription();

}

从源码中可以看出:

  • 该接口用于统一描述底层抽象资源

  • 常见的资源对应专门的子类,如:

    • UrlResource: url资源(常用)
    • FileSystemResource:文件系统资源(常用)
    • ClassPathResource:classpath路径下的资源(常用)
    • ByteArrayResource: 字节数组封装的资源(常用)
    • ServletContextResource:ServletContext环境下资源
    • InputStreamResource:输入流封装的资源
  • 该类位于spring-core 包,且1.0时就已存在

使用示例
ByteArrayResource
package win.elegentjs.spring.ioc.resource.bytearray;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import win.elegentjs.spring.util.FileUtil;

import java.io.IOException;


/**
 * 演示ByteArrayResource的使用
 *
 * 读取ByteArrayResource资源并打印出来
 *
 */
@Slf4j
public class ByteArrayResourceSample {

    public static void main(String[] args) throws IOException {
        Resource resource = new ByteArrayResource("hello world".getBytes());

        log.info("==> resource.exists(): {}", resource.exists());
        log.info("==> resource.getDescription(): {}", resource.getDescription());
        log.info("==> resource.isReadable(): {}", resource.isReadable());

        String result = FileUtil.inputStreamToString(resource.getInputStream());
        log.info("==> result: {}", result);

    }
}

// result:
2021-06-02 10:51:20.482 [main] INFO  w.e.s.i.resource.bytearray.ByteArrayResourceSample-==> resource.exists(): true
2021-06-02 10:51:20.488 [main] INFO  w.e.s.i.resource.bytearray.ByteArrayResourceSample-==> resource.getDescription(): Byte array resource [resource loaded from byte array]
2021-06-02 10:51:20.488 [main] INFO  w.e.s.i.resource.bytearray.ByteArrayResourceSample-==> resource.isReadable(): true
2021-06-02 10:51:20.488 [main] INFO  w.e.s.i.resource.bytearray.ByteArrayResourceSample-==> result: hello world

UrlResource
package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import win.elegentjs.spring.util.FileUtil;

import java.io.IOException;


/**
 * 演示UrlResource的使用
 */
@Slf4j
public class UrlResourceSample {

    public static void main(String[] args) throws IOException {
        Resource resource = new UrlResource("https://www.baidu.com");

        log.info("==> resource.exists(): {}", resource.exists());
        log.info("==> resource.getDescription(): {}", resource.getDescription());
        log.info("==> resource.isReadable(): {}", resource.isReadable());

        String result = FileUtil.inputStreamToString(resource.getInputStream());
        log.info("==> result: {}", result);

    }
}

// result
2021-06-03 10:22:20.169 [main] INFO  w.elegentjs.spring.ioc.resource.UrlResourceSample-==> resource.exists(): true
2021-06-03 10:22:20.172 [main] INFO  w.elegentjs.spring.ioc.resource.UrlResourceSample-==> resource.getDescription(): URL [https://www.baidu.com]
2021-06-03 10:22:20.178 [main] INFO  w.elegentjs.spring.ioc.resource.UrlResourceSample-==> resource.isReadable(): true
2021-06-03 10:22:20.189 [main] INFO  w.elegentjs.spring.ioc.resource.UrlResourceSample-==> result: <!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

FileSystemResource
package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import win.elegentjs.spring.util.FileUtil;

import java.io.IOException;


/**
 * 演示FileSystemResource的使用
 */
@Slf4j
public class FileSystemResourceSample {

    public static void main(String[] args) throws IOException {
        Resource resource = new FileSystemResource("/Users/liupeijun/logs/nacos/config.log");

        log.info("==> resource.exists(): {}", resource.exists());
        log.info("==> resource.getDescription(): {}", resource.getDescription());
        log.info("==> resource.isReadable(): {}", resource.isReadable());

        String result = FileUtil.inputStreamToString(resource.getInputStream());
        log.info("==> result: {}", result);

    }
}

// result:
2021-06-03 10:39:59.438 [main] INFO  w.e.spring.ioc.resource.FileSystemResourceSample-==> resource.exists(): true
2021-06-03 10:39:59.443 [main] INFO  w.e.spring.ioc.resource.FileSystemResourceSample-==> resource.getDescription(): file [/Users/liupeijun/logs/nacos/config.log]
2021-06-03 10:39:59.444 [main] INFO  w.e.spring.ioc.resource.FileSystemResourceSample-==> resource.isReadable(): true
2021-06-03 10:39:59.458 [main] INFO  w.e.spring.ioc.resource.FileSystemResourceSample-==> result: 2021-04-02 16:23:50.515 INFO [main :c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port:88482021-04-02 16:23:50.520 INFO [main :c.a.n.c.u.ParamUtil] [settings] [http-client] connect timeout:10002021-04-02 16:23:50.522 INFO [main 

InputStreamResource
package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import win.elegentjs.spring.util.FileUtil;

import java.io.FileInputStream;
import java.io.IOException;


/**
 * 演示InputStreamSystemResource的使用
 */
@Slf4j
public class InputStreamResourceSample {

    public static void main(String[] args) throws IOException {
        Resource resource = new InputStreamResource(new FileInputStream("/Users/liupeijun/logs/nacos/config.log"));

        log.info("==> resource.exists(): {}", resource.exists());
        log.info("==> resource.getDescription(): {}", resource.getDescription());
        log.info("==> resource.isReadable(): {}", resource.isReadable());

        String result = FileUtil.inputStreamToString(resource.getInputStream());
        log.info("==> result: {}", result);

    }
}

// result:
2021-06-03 10:43:19.096 [main] INFO  w.e.spring.ioc.resource.InputStreamResourceSample-==> resource.exists(): true
2021-06-03 10:43:19.102 [main] INFO  w.e.spring.ioc.resource.InputStreamResourceSample-==> resource.getDescription(): InputStream resource [resource loaded through InputStream]
2021-06-03 10:43:19.102 [main] INFO  w.e.spring.ioc.resource.InputStreamResourceSample-==> resource.isReadable(): true
2021-06-03 10:43:19.104 [main] INFO  w.e.spring.ioc.resource.InputStreamResourceSample-==> result: 2021-04-02 16:23:50.515 INFO [main :c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port:88482021-04-02 16:23:50.520 INFO [main :c.a.n.c.u.ParamUtil] [settings] [http-client] connect timeout:10002021-04-02 16:23:50.522 INFO [main 

ClassPathResource
package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import win.elegentjs.spring.util.FileUtil;

import java.io.FileInputStream;
import java.io.IOException;


/**
 * 演示ClasspathResource的使用
 */
@Slf4j
public class ClasspathResourceSample {

    public static void main(String[] args) throws IOException {
        Resource resource = new ClassPathResource("application.properties");

        log.info("==> resource.exists(): {}", resource.exists());
        log.info("==> resource.getDescription(): {}", resource.getDescription());
        log.info("==> resource.isReadable(): {}", resource.isReadable());

        String result = FileUtil.inputStreamToString(resource.getInputStream());
        log.info("==> result: {}", result);

    }
}

// result:
2021-06-03 11:01:52.400 [main] INFO  w.e.spring.ioc.resource.ClasspathResourceSample-==> resource.exists(): true
2021-06-03 11:01:52.404 [main] INFO  w.e.spring.ioc.resource.ClasspathResourceSample-==> resource.getDescription(): class path resource [application.properties]
2021-06-03 11:01:52.405 [main] INFO  w.e.spring.ioc.resource.ClasspathResourceSample-==> resource.isReadable(): true
2021-06-03 11:01:52.409 [main] INFO  w.e.spring.ioc.resource.ClasspathResourceSample-==> result: weather=sunningwind=5

以上演示了各种资源的使用方法,可以看出使用Resource接口去抽象资源的访问确实挺方便。

通过ResourceLoader接口获取资源

Spring框架为了更方便的获取资源,尽量减少直接使用各个具体的资源实现类,定义了一个ResourceLoader接口。该接口的getResource(String location)方法可以用来获取资源。它有个默认的实现DefaultResourceLoader实现类可以适用各种环境。

先看接口定义:

public interface ResourceLoader {

	/** Pseudo URL prefix for loading from the class path: "classpath:". */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	
	Resource getResource(String location);

	@Nullable
	ClassLoader getClassLoader();

}

// 核心方法是getResource,即从指定路径加载资源,返回Resource对象。

再看默认DefaultResourceLoader实现

@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		
		// 如果存在协议解析器,使用它们解析,默认为空
		for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}
		
		// 以/开头使用ClassPathResource解析
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		// 以classpath:开头以ClassPathResource解析
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
		    // 其他情况使用url解析
			try {
				// Try to parse the location as a URL...
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// 解析失败的情况下还是使用ClassPathResource解析
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

DefaultResourceLoader示例

package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import win.elegentjs.spring.util.FileUtil;

import java.io.IOException;

@Slf4j
public class DefaultResourceLoaderSample {

    public static void main(String[] args) throws IOException {
        ResourceLoader resourceLoader = new DefaultResourceLoader();

        // classPath下资源
        Resource r = resourceLoader.getResource("classpath:application.properties");
        print(r);

        // url资源
        r = resourceLoader.getResource("https://www.baidu.com");
        print(r);

        // file url资源
        r = resourceLoader.getResource("file:/Users/liupeijun/logs/nacos/config.log");
        print(r);
    }

    private static void print(Resource r) throws IOException {
        log.info("==> resource.exists(): {}", r.exists());
        log.info("==> resource.getDescription(): {}", r.getDescription());
        log.info("==> resource.isReadable(): {}", r.isReadable());

        String result = FileUtil.inputStreamToString(r.getInputStream());
        log.info("==> result: {}", result);
    }
}

// result:
2021-06-03 11:30:03.146 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:30:03.150 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.getDescription(): class path resource [application.properties]
2021-06-03 11:30:03.151 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:30:03.153 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> result: weather=sunningwind=5
2021-06-03 11:30:03.812 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:30:03.813 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.getDescription(): URL [https://www.baidu.com]
2021-06-03 11:30:03.821 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:30:03.833 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> result: <!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
2021-06-03 11:30:03.845 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:30:03.845 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.getDescription(): URL [file:/Users/liupeijun/logs/nacos/config.log]
2021-06-03 11:30:03.845 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:30:03.851 [main] INFO  w.e.s.ioc.resource.DefaultResourceLoaderSample-==> result: 2021-04-02 16:23:50.515 INFO [main :c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port:88482021-04-02 16:23:50.520 INFO [main :c.a.n.c.u.ParamUtil] [settings] [http-client] connect timeout:10002021-04-02 16:23:50.522 INFO [main :c.a.n.c.u.ParamUtil] PER_TASK_CONFIG_SIZE: 3000.02021-04-02 16:23:50.622 INFO [main :c.a.n.c.i.CredentialWatcher] null No credential found2021-04-02 16:26:33.461 INFO [restartedMain:c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port:88482021-04-02 16:26:33.464 INFO 

ApplicationContext

天生所有的ApplicationContext实例都实现了ResourceLoader接口,也就是说spring容器就是一个ResourceLoader。在能获取到spring容器的情况下可以不用新建DefaultResourceLoader实例。

示例如下:

package win.elegentjs.spring.ioc.resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import win.elegentjs.spring.util.FileUtil;

import java.io.IOException;

@Slf4j
public class ApplicationContextResourceLoaderSample {

    public static void main(String[] args) throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // classPath下资源
        Resource r = context.getResource("classpath:application.properties");
        print(r);

        // url资源
        r = context.getResource("https://www.baidu.com");
        print(r);

        // file url资源
        r = context.getResource("file:/Users/liupeijun/logs/nacos/config.log");
        print(r);


    }

    private static void print(Resource r) throws IOException {
        log.info("==> resource.exists(): {}", r.exists());
        log.info("==> resource.getDescription(): {}", r.getDescription());
        log.info("==> resource.isReadable(): {}", r.isReadable());

        String result = FileUtil.inputStreamToString(r.getInputStream());
        log.info("==> result: {}", result);
    }
}

// result:
2021-06-03 11:40:08.841 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:40:08.843 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.getDescription(): class path resource [application.properties]
2021-06-03 11:40:08.843 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:40:08.845 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> result: weather=sunningwind=5
2021-06-03 11:40:09.390 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:40:09.390 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.getDescription(): URL [https://www.baidu.com]
2021-06-03 11:40:09.398 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:40:09.412 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> result: <!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
2021-06-03 11:40:09.431 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.exists(): true
2021-06-03 11:40:09.431 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.getDescription(): URL [file:/Users/liupeijun/logs/nacos/config.log]
2021-06-03 11:40:09.431 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> resource.isReadable(): true
2021-06-03 11:40:09.434 [main] INFO  w.e.s.i.r.ApplicationContextResourceLoaderSample-==> result: 2021-04-02 16:23:50.515 INFO [main :c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port:88482021-04-02 16:23:50.520 INFO [main :c.a.n.c.u.ParamUtil] [settings] [http-client] connect timeout:10002021-04-02 16:23:50.522 INFO [main :c.a.n.c.u.ParamUtil] PER_TASK_CONFIG_SIZE: 3000.02021-04-02 16:23:50.622 INFO [main :c.a.n.c.i.CredentialWatcher] null No credential found2021-04-02 16:26:33.461 INFO [restartedMain:c.a.n.c.u.ParamUtil] [settings] [req-serv] nacos-server port
小结

本章讲了Resource接口及其实现,学习spring使用一个抽象接口统一所有资源访问的思想。实际将主流的资源实现做了示例。

分析了ResourceLoader接口的作用,及其默认实现DefaultResourceLoader,分析默认实现的源码,并做了代码示例。

最后分析了原来ApplicationContext接口本身就实现了ResourceLoader接口,即spring容器实例就是一个ResourceLoader。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值