DescriptiveResource
这个类更简单,仅仅一个不可变的描述字符串的包装
// @since 1.2.6 public class DescriptiveResource extends AbstractResource { @Override public InputStream getInputStream() throws IOException { throw new FileNotFoundException( getDescription() + " cannot be opened because it does not point to a readable resource"); } }
这个类实际只是对资源描述的定义,既不是可读,实际文件也是不存在的,其他Resource接口中的方法也并未实现。当一个方法需要你传递一个资源对象,但又不会在方法中真正读取该对象的时候,如果没有合适的资源对象作为参数,就创建一个 DescriptiveResource 资源做参数。比如ConfigurationClass就有使用~~~
另外BeanDefinitionResource和DescriptiveResource有点像。但它持有的是一个BeanDefinition,也不能对它进行读、写。一般也是占位用的
AbstractFileResolvingResource
它复写了AbstractResource
大多数方法,是一个比较重要的分支。有不少非常好用的实现类
// @since 3.0 public abstract class AbstractFileResolvingResource extends AbstractResource { }
UrlResource:通过URL地址获取资源
可以从网络里获取资源
public static void main(String[] args) throws IOException { UrlResource resource = new UrlResource("http://www.springframework.org/schema/beans/spring-beans.xsd"); if (resource.exists()) { File file = resource.getFile(); System.out.println(file); //报错 java.io.FileNotFoundException: URL [xxx] cannot be resolved to absolute file path because it dumpStream(resource); //输出这个.xsd文件的所有的内容... } }
FileUrlResource
//@since 5.0.2 显然它出现得很晚。 并且还实现了WritableResource接口 public class FileUrlResource extends UrlResource implements WritableResource { @Nullable private volatile File file; public FileUrlResource(URL url) { super(url); } // 注意:若使用此构造函数,此处使用的是file协议 而UrlResource采用的是http协议,此处需注意 // 若想http,请用上面构造。自己构造一个URL对象吧 public FileUrlResource(String location) throws MalformedURLException { super(ResourceUtils.URL_PROTOCOL_FILE, location); } @Override public File getFile() throws IOException { File file = this.file; if (file != null) { return file; } file = super.getFile(); this.file = file; return file; } @Override public boolean isWritable() { try { URL url = getURL(); if (ResourceUtils.isFileURL(url)) { // Proceed with file system resolution File file = getFile(); return (file.canWrite() && !file.isDirectory()); } else { return true; } } catch (IOException ex) { return false; } } @Override public OutputStream getOutputStream() throws IOException { return Files.newOutputStream(getFile().toPath()); } @Override public WritableByteChannel writableChannel() throws IOException { return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE); } }
它提供了我们访问网络资源能像访问本地文件一样的能力~~~
public static void main(String[] args) throws IOException { //FileUrlResource resource = new FileUrlResource("http://www.springframework.org/schema/beans/spring-beans.xsd"); FileUrlResource resource = new FileUrlResource(new URL("http://www.springframework.org/schema/beans/spring-beans.xsd")); if (resource.exists()) { dumpStream(resource); //输出这个.xsd文件的所有的内容... } }
ClassPathResource:通过类路径获取资源文件
听这名字就知道,它是直接去读取类路径下的资源文件的。
其实它的底层都是依赖于我们上面说得clazz.getResourceAsStream或者classLoader.getResourceAsStream。掌握了上面之后,这个其实就非常简单了
public class ClassPathResource extends AbstractFileResolvingResource { private final String path;' @Nullable private ClassLoader classLoader; @Nullable private Class<?> clazz; // 它还可以自己指定clazz @Nullable public final ClassLoader getClassLoader() { return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader); } @Override public boolean exists() { return (resolveURL() != null); } // 这是它最重要的一个方法,依赖于JDK的实现嘛 @Override public InputStream getInputStream() throws IOException { InputStream is; if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else if (this.classLoader != null) { is = this.classLoader.getResourceAsStream(this.path); } else { is = ClassLoader.getSystemResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; } @Override public URL getURL() throws IOException { URL url = resolveURL(); if (url == null) { throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist"); } return url; } // 非常简单 直接解析path即可 @Override @Nullable public String getFilename() { return StringUtils.getFilename(this.path); } }
Demo:
public static void main(String[] args) { //ClassPathResource resource = new ClassPathResource("spring.properties"); // 如果是要获取指定类所在包下的文件,建议指定class ClassPathResource resource = new ClassPathResource("demo.properties",Main.class); if (resource.exists()) { dumpStream(resource); //name=fangshixiang 或者 demo=value } }
ServletContextResource:获取ServletContext环境下的资源
这个在web包里面。org.springframework.web.context.support
为访问Web容器上下文中的资源而设计的类,负责以相对于Web应用程序根目录的路径加载资源,它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File的方式访问,还可以直接从JAR包中访问资源
public class ServletContextResource extends AbstractFileResolvingResource implements ContextResource { // 持有servletContext的引用 private final ServletContext servletContext; private final String path; // 只提供这一个构造函数,来构造一个资源 public ServletContextResource(ServletContext servletContext, String path) { // check ServletContext Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext"); this.servletContext = servletContext; // check path Assert.notNull(path, "Path is required"); String pathToUse = StringUtils.cleanPath(path); if (!pathToUse.startsWith("/")) { pathToUse = "/" + pathToUse; } this.path = pathToUse; } // 我们发现,它底层都是依赖于servletContext.getResource getResourceAsStream这些方法去找到资源的 @Override public boolean isFile() { try { URL url = this.servletContext.getResource(this.path); if (url != null && ResourceUtils.isFileURL(url)) { return true; } else { return (this.servletContext.getRealPath(this.path) != null); } } catch (MalformedURLException ex) { return false; } } @Override public InputStream getInputStream() throws IOException { InputStream is = this.servletContext.getResourceAsStream(this.path); if (is == null) { throw new FileNotFoundException("Could not open " + getDescription()); } return is; } // 这个有点意思。如果URL就是File类型。就ok // 如果不是file类型,就根据绝对路径 new一个出来 @Override public File getFile() throws IOException { URL url = this.servletContext.getResource(this.path); if (url != null && ResourceUtils.isFileURL(url)) { // Proceed with file system resolution... return super.getFile(); } else { String realPath = WebUtils.getRealPath(this.servletContext, this.path); return new File(realPath); } } }
总结
Spring内部,针对于资源文件有一个统一的接口Resource表示。
因为我们现在绝大部分应用都构建在Spring的基础上,因此它提供的这些便捷的获取资源的工具,我们也是可以使用的。而不用去使用源生JDK的获取了~~~