Spring resource

Spring Resource 1


一、介紹

    java的標準的URL類不足夠能訪問大部分狀況的資源,如沒有一個標準的功能獲取一個classpath或者想對於servletContext路徑下的資源html

二、spring resoruce class

    spring的resource是一個可以訪問low-level resources的抽象接口java

public interface InputStreamSource {   /**    * Return an {@link InputStream}.    * <p>It is expected that each call creates a <i>fresh</i> stream.    * <p>This requirement is particularly important when you consider an API such    * as JavaMail, which needs to be able to read the stream multiple times when    * creating mail attachments. For such a use case, it is <i>required</i>    * that each {@code getInputStream()} call returns a fresh stream.    * @return the input stream for the underlying resource (must not be {@code null})    * @throws IOException if the stream could not be opened    * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource)    */   InputStream getInputStream() throws IOException;}
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.core.io;import java.io.File;import java.io.IOException;import java.net.URI;import java.net.URL;/** * 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 FileSystemResource * @see ClassPathResource * @see UrlResource * @see ByteArrayResource * @see InputStreamResource * @see PathResource */public interface Resource extends InputStreamSource {   /**    * Return 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();   /**    * Return whether the contents of this resource can be read,    * e.g. via {@link #getInputStream()} or {@link #getFile()}.    * <p>Will be {@code true} for typical resource descriptors;    * 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()    */   boolean isReadable();   /**    * Return whether this resource represents a handle with an open    * stream. If 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.    */   boolean isOpen();   /**    * 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    */   URI getURI() throws IOException;   /**    * Return a File handle for this resource.    * @throws IOException if the resource cannot be resolved as absolute    * file path, i.e. if the resource is not available in a file system    */   File getFile() throws IOException;   /**    * 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.    */   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();}


它有好多的實現類web

UrlResourcespring

/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.core.io;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.net.URLConnection;import org.springframework.util.Assert;import org.springframework.util.ResourceUtils;import org.springframework.util.StringUtils;/** * {@link Resource} implementation for {@code java.net.URL} locators. * Obviously supports resolution as URL, and also as File in case of * the "file:" protocol. * * @author Juergen Hoeller * @since 28.12.2003 * @see java.net.URL */public class UrlResource extends AbstractFileResolvingResource {   /**    * Original URI, if available; used for URI and File access.    */   private final URI uri;   /**    * Original URL, used for actual access.    */   private final URL url;   /**    * Cleaned URL (with normalized path), used for comparisons.    */   private final URL cleanedUrl;   /**    * Create a new UrlResource based on the given URI object.    * @param uri a URI    * @throws MalformedURLException if the given URL path is not valid    */   public UrlResource(URI uri) throws MalformedURLException {      Assert.notNull(uri, "URI must not be null");      this.uri = uri;      this.url = uri.toURL();      this.cleanedUrl = getCleanedUrl(this.url, uri.toString());   }   /**    * Create a new UrlResource based on the given URL object.    * @param url a URL    */   public UrlResource(URL url) {      Assert.notNull(url, "URL must not be null");      this.url = url;      this.cleanedUrl = getCleanedUrl(this.url, url.toString());      this.uri = null;   }   /**    * Create a new UrlResource based on a URL path.    * <p>Note: The given path needs to be pre-encoded if necessary.    * @param path a URL path    * @throws MalformedURLException if the given URL path is not valid    * @see java.net.URL#URL(String)    */   public UrlResource(String path) throws MalformedURLException {      Assert.notNull(path, "Path must not be null");      this.uri = null;      this.url = new URL(path);      this.cleanedUrl = getCleanedUrl(this.url, path);   }   /**    * Create a new UrlResource based on a URI specification.    * <p>The given parts will automatically get encoded if necessary.    * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon);    * also known as "scheme"    * @param location the location (e.g. the file path within that protocol);    * also known as "scheme-specific part"    * @throws MalformedURLException if the given URL specification is not valid    * @see java.net.URI#URI(String, String, String)    */   public UrlResource(String protocol, String location) throws MalformedURLException  {      this(protocol, location, null);   }   /**    * Create a new UrlResource based on a URI specification.    * <p>The given parts will automatically get encoded if necessary.    * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon);    * also known as "scheme"    * @param location the location (e.g. the file path within that protocol);    * also known as "scheme-specific part"    * @param fragment the fragment within that location (e.g. anchor on an HTML page,    * as following after a "#" separator)    * @throws MalformedURLException if the given URL specification is not valid    * @see java.net.URI#URI(String, String, String)    */   public UrlResource(String protocol, String location, String fragment) throws MalformedURLException  {      try {         this.uri = new URI(protocol, location, fragment);         this.url = this.uri.toURL();         this.cleanedUrl = getCleanedUrl(this.url, this.uri.toString());      }      catch (URISyntaxException ex) {         MalformedURLException exToThrow = new MalformedURLException(ex.getMessage());         exToThrow.initCause(ex);         throw exToThrow;      }   }   /**    * Determine a cleaned URL for the given original URL.    * @param originalUrl the original URL    * @param originalPath the original URL path    * @return the cleaned URL    * @see org.springframework.util.StringUtils#cleanPath    */   private URL getCleanedUrl(URL originalUrl, String originalPath) {      try {         return new URL(StringUtils.cleanPath(originalPath));      }      catch (MalformedURLException ex) {         // Cleaned URL path cannot be converted to URL         // -> take original URL.         return originalUrl;      }   }   /**    * This implementation opens an InputStream for the given URL.    * It sets the "UseCaches" flag to {@code false},    * mainly to avoid jar file locking on Windows.    * @see java.net.URL#openConnection()    * @see java.net.URLConnection#setUseCaches(boolean)    * @see java.net.URLConnection#getInputStream()    */   @Override   public InputStream getInputStream() throws IOException {      URLConnection con = this.url.openConnection();      ResourceUtils.useCachesIfNecessary(con);      try {         return con.getInputStream();      }      catch (IOException ex) {         // Close the HTTP connection (if applicable).         if (con instanceof HttpURLConnection) {            ((HttpURLConnection) con).disconnect();         }         throw ex;      }   }   /**    * This implementation returns the underlying URL reference.    */   @Override   public URL getURL() throws IOException {      return this.url;   }   /**    * This implementation returns the underlying URI directly,    * if possible.    */   @Override   public URI getURI() throws IOException {      if (this.uri != null) {         return this.uri;      }      else {         return super.getURI();      }   }   /**    * This implementation returns a File reference for the underlying URL/URI,    * provided that it refers to a file in the file system.    * @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String)    */   @Override   public File getFile() throws IOException {      if (this.uri != null) {         return super.getFile(this.uri);      }      else {         return super.getFile();      }   }   /**    * This implementation creates a UrlResource, applying the given path    * relative to the path of the underlying URL of this resource descriptor.    * @see java.net.URL#URL(java.net.URL, String)    */   @Override   public Resource createRelative(String relativePath) throws MalformedURLException {      if (relativePath.startsWith("/")) {         relativePath = relativePath.substring(1);      }      return new UrlResource(new URL(this.url, relativePath));   }   /**    * This implementation returns the name of the file that this URL refers to.    * @see java.net.URL#getFile()    * @see java.io.File#getName()    */   @Override   public String getFilename() {      return new File(this.url.getFile()).getName();   }   /**    * This implementation returns a description that includes the URL.    */   @Override   public String getDescription() {      return "URL [" + this.url + "]";   }   /**    * This implementation compares the underlying URL references.    */   @Override   public boolean equals(Object obj) {      return (obj == this ||         (obj instanceof UrlResource && this.cleanedUrl.equals(((UrlResource) obj).cleanedUrl)));   }   /**    * This implementation returns the hash code of the underlying URL reference.    */   @Override   public int hashCode() {      return this.cleanedUrl.hashCode();   }}

ClassPathResource:express

    This Resource implementation supports resolution as java.io.File if the class path resource
    resides in the file system, but not for classpath resources which reside in a jar and have not been
    expanded (by the servlet engine, or whatever the environment is) to the filesystem. To address this the
    various Resource implementations always support resolution as a java.net.URL.apache

/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.core.io;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.net.URL;import org.springframework.util.Assert;import org.springframework.util.ClassUtils;import org.springframework.util.ObjectUtils;import org.springframework.util.StringUtils;/** * {@link Resource} implementation for class path resources. * Uses either a given ClassLoader or a given Class for loading resources. * * <p>Supports resolution as {@code java.io.File} if the class path * resource resides in the file system, but not for resources in a JAR. * Always supports resolution as URL. * * @author Juergen Hoeller * @author Sam Brannen * @since 28.12.2003 * @see ClassLoader#getResourceAsStream(String) * @see Class#getResourceAsStream(String) */public class ClassPathResource extends AbstractFileResolvingResource {   private final String path;   private ClassLoader classLoader;   private Class<?> clazz;   /**    * Create a new {@code ClassPathResource} for {@code ClassLoader} usage.    * A leading slash will be removed, as the ClassLoader resource access    * methods will not accept it.    * <p>The thread context class loader will be used for    * loading the resource.    * @param path the absolute path within the class path    * @see java.lang.ClassLoader#getResourceAsStream(String)    * @see org.springframework.util.ClassUtils#getDefaultClassLoader()    */   public ClassPathResource(String path) {      this(path, (ClassLoader) null);   }   /**    * Create a new {@code ClassPathResource} for {@code ClassLoader} usage.    * A leading slash will be removed, as the ClassLoader resource access    * methods will not accept it.    * @param path the absolute path within the classpath    * @param classLoader the class loader to load the resource with,    * or {@code null} for the thread context class loader    * @see ClassLoader#getResourceAsStream(String)    */   public ClassPathResource(String path, ClassLoader classLoader) {      Assert.notNull(path, "Path must not be null");      String pathToUse = StringUtils.cleanPath(path);      if (pathToUse.startsWith("/")) {         pathToUse = pathToUse.substring(1);      }      this.path = pathToUse;      this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());   }   /**    * Create a new {@code ClassPathResource} for {@code Class} usage.    * The path can be relative to the given class, or absolute within    * the classpath via a leading slash.    * @param path relative or absolute path within the class path    * @param clazz the class to load resources with    * @see java.lang.Class#getResourceAsStream    */   public ClassPathResource(String path, Class<?> clazz) {      Assert.notNull(path, "Path must not be null");      this.path = StringUtils.cleanPath(path);      this.clazz = clazz;   }   /**    * Create a new {@code ClassPathResource} with optional {@code ClassLoader}    * and {@code Class}. Only for internal usage.    * @param path relative or absolute path within the classpath    * @param classLoader the class loader to load the resource with, if any    * @param clazz the class to load resources with, if any    */   protected ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {      this.path = StringUtils.cleanPath(path);      this.classLoader = classLoader;      this.clazz = clazz;   }   /**    * Return the path for this resource (as resource path within the class path).    */   public final String getPath() {      return this.path;   }   /**    * Return the ClassLoader that this resource will be obtained from.    */   public final ClassLoader getClassLoader() {      return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);   }   /**    * This implementation checks for the resolution of a resource URL.    * @see java.lang.ClassLoader#getResource(String)    * @see java.lang.Class#getResource(String)    */   @Override   public boolean exists() {      return (resolveURL() != null);   }   /**    * Resolves a URL for the underlying class path resource.    * @return the resolved URL, or {@code null} if not resolvable    */   protected URL resolveURL() {      if (this.clazz != null) {         return this.clazz.getResource(this.path);      }      else if (this.classLoader != null) {         return this.classLoader.getResource(this.path);      }      else {         return ClassLoader.getSystemResource(this.path);      }   }   /**    * This implementation opens an InputStream for the given class path resource.    * @see java.lang.ClassLoader#getResourceAsStream(String)    * @see java.lang.Class#getResourceAsStream(String)    */   @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;   }   /**    * This implementation returns a URL for the underlying class path resource,    * if available.    * @see java.lang.ClassLoader#getResource(String)    * @see java.lang.Class#getResource(String)    */   @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;   }   /**    * This implementation creates a ClassPathResource, applying the given path    * relative to the path of the underlying resource of this descriptor.    * @see org.springframework.util.StringUtils#applyRelativePath(String, String)    */   @Override   public Resource createRelative(String relativePath) {      String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);      return new ClassPathResource(pathToUse, this.classLoader, this.clazz);   }   /**    * This implementation returns the name of the file that this class path    * resource refers to.    * @see org.springframework.util.StringUtils#getFilename(String)    */   @Override   public String getFilename() {      return StringUtils.getFilename(this.path);   }   /**    * This implementation returns a description that includes the class path location.    */   @Override   public String getDescription() {      StringBuilder builder = new StringBuilder("class path resource [");      String pathToUse = path;      if (this.clazz != null && !pathToUse.startsWith("/")) {         builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));         builder.append('/');      }      if (pathToUse.startsWith("/")) {         pathToUse = pathToUse.substring(1);      }      builder.append(pathToUse);      builder.append(']');      return builder.toString();   }   /**    * This implementation compares the underlying class path locations.    */   @Override   public boolean equals(Object obj) {      if (obj == this) {         return true;      }      if (obj instanceof ClassPathResource) {         ClassPathResource otherRes = (ClassPathResource) obj;         return (this.path.equals(otherRes.path) &&               ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&               ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));      }      return false;   }   /**    * This implementation returns the hash code of the underlying    * class path location.    */   @Override   public int hashCode() {      return this.path.hashCode();   }}


FileSystemResource :

This is a Resource implementation for java.io.File handles. It obviously supports resolution as a File, and as a URL.api

/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.core.io;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.URI;import java.net.URL;import org.springframework.util.Assert;import org.springframework.util.StringUtils;/** * {@link Resource} implementation for {@code java.io.File} handles. * Obviously supports resolution as File, and also as URL. * Implements the extended {@link WritableResource} interface. * * @author Juergen Hoeller * @since 28.12.2003 * @see java.io.File */public class FileSystemResource extends AbstractResource implements WritableResource {   private final File file;   private final String path;   /**    * Create a new {@code FileSystemResource} from a {@link File} handle.    * <p>Note: When building relative resources via {@link #createRelative},    * the relative path will apply <i>at the same directory level</i>:    * e.g. new File("C:/dir1"), relative path "dir2" -> "C:/dir2"!    * If you prefer to have relative paths built underneath the given root    * directory, use the {@link #FileSystemResource(String) constructor with a file path}    * to append a trailing slash to the root path: "C:/dir1/", which    * indicates this directory as root for all relative paths.    * @param file a File handle    */   public FileSystemResource(File file) {      Assert.notNull(file, "File must not be null");      this.file = file;      this.path = StringUtils.cleanPath(file.getPath());   }   /**    * Create a new {@code FileSystemResource} from a file path.    * <p>Note: When building relative resources via {@link #createRelative},    * it makes a difference whether the specified resource base path here    * ends with a slash or not. In the case of "C:/dir1/", relative paths    * will be built underneath that root: e.g. relative path "dir2" ->    * "C:/dir1/dir2". In the case of "C:/dir1", relative paths will apply    * at the same directory level: relative path "dir2" -> "C:/dir2".    * @param path a file path    */   public FileSystemResource(String path) {      Assert.notNull(path, "Path must not be null");      this.file = new File(path);      this.path = StringUtils.cleanPath(path);   }   /**    * Return the file path for this resource.    */   public final String getPath() {      return this.path;   }   /**    * This implementation returns whether the underlying file exists.    * @see java.io.File#exists()    */   @Override   public boolean exists() {      return this.file.exists();   }   /**    * This implementation checks whether the underlying file is marked as readable    * (and corresponds to an actual file with content, not to a directory).    * @see java.io.File#canRead()    * @see java.io.File#isDirectory()    */   @Override   public boolean isReadable() {      return (this.file.canRead() && !this.file.isDirectory());   }   /**    * This implementation opens a FileInputStream for the underlying file.    * @see java.io.FileInputStream    */   @Override   public InputStream getInputStream() throws IOException {      return new FileInputStream(this.file);   }   /**    * This implementation returns a URL for the underlying file.    * @see java.io.File#toURI()    */   @Override   public URL getURL() throws IOException {      return this.file.toURI().toURL();   }   /**    * This implementation returns a URI for the underlying file.    * @see java.io.File#toURI()    */   @Override   public URI getURI() throws IOException {      return this.file.toURI();   }   /**    * This implementation returns the underlying File reference.    */   @Override   public File getFile() {      return this.file;   }   /**    * This implementation returns the underlying File's length.    */   @Override   public long contentLength() throws IOException {      return this.file.length();   }   /**    * This implementation creates a FileSystemResource, applying the given path    * relative to the path of the underlying file of this resource descriptor.    * @see org.springframework.util.StringUtils#applyRelativePath(String, String)    */   @Override   public Resource createRelative(String relativePath) {      String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);      return new FileSystemResource(pathToUse);   }   /**    * This implementation returns the name of the file.    * @see java.io.File#getName()    */   @Override   public String getFilename() {      return this.file.getName();   }   /**    * This implementation returns a description that includes the absolute    * path of the file.    * @see java.io.File#getAbsolutePath()    */   @Override   public String getDescription() {      return "file [" + this.file.getAbsolutePath() + "]";   }   // implementation of WritableResource   /**    * This implementation checks whether the underlying file is marked as writable    * (and corresponds to an actual file with content, not to a directory).    * @see java.io.File#canWrite()    * @see java.io.File#isDirectory()    */   @Override   public boolean isWritable() {      return (this.file.canWrite() && !this.file.isDirectory());   }   /**    * This implementation opens a FileOutputStream for the underlying file.    * @see java.io.FileOutputStream    */   @Override   public OutputStream getOutputStream() throws IOException {      return new FileOutputStream(this.file);   }   /**    * This implementation compares the underlying File references.    */   @Override   public boolean equals(Object obj) {      return (obj == this ||         (obj instanceof FileSystemResource && this.path.equals(((FileSystemResource) obj).path)));   }   /**    * This implementation returns the hash code of the underlying File reference.    */   @Override   public int hashCode() {      return this.path.hashCode();   }}

ServletContextResource :

    This is a Resource implementation for ServletContext resources, interpreting relative paths within
the relevant web application’s root directory.
This always supports stream access and URL access, but only allows java.io.File access when
the web application archive is expanded and the resource is physically on the filesystem. Whether or
not it’s expanded and on the filesystem like this, or accessed directly from the JAR or somewhere else
like a DB (it’s conceivable) is actually dependent on the Servlet container.mvc

ServletContextResourceServletContextResourceServletContextResource

InputStreamResource :

A Resource implementation for a given InputStream. This should only be used if no specific Resource implementation is applicable. In particular, prefer ByteArrayResource or any of the file-based Resource implementations where possible.In contrast to other Resource implementations, this is a descriptor for an already opened resource - therefore returning true from isOpen(). Do not use it if you need to keep the resource descriptor
app

somewhere, or if you need to read a stream multiple times.less

InputStreamResourceInputStreamResource


ByteArrayResource:

    This is a Resource implementation for a given byte array. It creates a ByteArrayInputStream for the given byte array. It’s useful for loading content from any given byte array, without having to resort to a single-use InputStreamResource.


ByteArrayResourceByteArrayResourceByteArrayResource


三、Spring ResourceLoader

這個接口是用來獲取Resource類的


有第二部分可知每一個Resource會對應有個ResourceLoader類

/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.core.io;import org.springframework.util.ResourceUtils;/** * Strategy interface for loading resources (e.. class path or file system * resources). An {@link org.springframework.context.ApplicationContext} * is required to provide this functionality, plus extended * {@link org.springframework.core.io.support.ResourcePatternResolver} support. * * <p>{@link DefaultResourceLoader} is a standalone implementation that is * usable outside an ApplicationContext, also used by {@link ResourceEditor}. * * <p>Bean properties of type Resource and Resource array can be populated * from Strings when running in an ApplicationContext, using the particular * context's resource loading strategy. * * @author Juergen Hoeller * @since 10.03.2004 * @see Resource * @see org.springframework.core.io.support.ResourcePatternResolver * @see org.springframework.context.ApplicationContext * @see org.springframework.context.ResourceLoaderAware */public interface ResourceLoader {   /** Pseudo URL prefix for loading from the class path: "classpath:" */   String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;   /**    * Return a Resource handle for the specified resource.    * The handle should always be a reusable resource descriptor,    * allowing for multiple {@link Resource#getInputStream()} calls.    * <p><ul>    * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".    * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".    * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".    * (This will be implementation-specific, typically provided by an    * ApplicationContext implementation.)    * </ul>    * <p>Note that a Resource handle does not imply an existing resource;    * you need to invoke {@link Resource#exists} to check for existence.    * @param location the resource location    * @return a corresponding Resource handle    * @see #CLASSPATH_URL_PREFIX    * @see org.springframework.core.io.Resource#exists    * @see org.springframework.core.io.Resource#getInputStream    */   Resource getResource(String location);   /**    * Expose the ClassLoader used by this ResourceLoader.    * <p>Clients which need to access the ClassLoader directly can do so    * in a uniform manner with the ResourceLoader, rather than relying    * on the thread context ClassLoader.    * @return the ClassLoader (only {@code null} if even the system    * ClassLoader isn't accessible)    * @see org.springframework.util.ClassUtils#getDefaultClassLoader()    */   ClassLoader getClassLoader();}

    

Resource template = ctx.getResource("some/resource/path/myTemplate.txt")

當你這樣獲取一個資源的時候,ctx爲ClassPathXmlApplicationContext獲得ClassPathResource,FileSystemXmlApplicationContext獲得FileSystemResource,WebApplicationContext,獲得ServletContextResource,用啥環境的什麼資源

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");

能夠這樣子指定資源的url


Table 6.1. Resource strings

Prefix
Example Explanation
classpath: classpath:com/myapp/config.xml Loaded from the classpath.
file: file:///data/config.xml Loaded as a URL, from thefilesystem.
http: http://myserver/logo.png Loaded as a URL.
(none) /data/config.xml Depends on the underlying ApplicationContext.

 

四、The ResourceLoaderAware interface

/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.context;import org.springframework.beans.factory.Aware;import org.springframework.core.io.ResourceLoader;/** * Interface to be implemented by any object that wishes to be notified of * the <b>ResourceLoader</b> (typically the ApplicationContext) that it runs in. * This is an alternative to a full ApplicationContext dependency via the * ApplicationContextAware interface. * * <p>Note that Resource dependencies can also be exposed as bean properties * of type Resource, populated via Strings with automatic type conversion by * the bean factory. This removes the need for implementing any callback * interface just for the purpose of accessing a specific file resource. * * <p>You typically need a ResourceLoader when your application object has * to access a variety of file resources whose names are calculated. A good * strategy is to make the object use a DefaultResourceLoader but still * implement ResourceLoaderAware to allow for overriding when running in an * ApplicationContext. See ReloadableResourceBundleMessageSource for an example. * * <p>A passed-in ResourceLoader can also be checked for the * <b>ResourcePatternResolver</b> interface and cast accordingly, to be able * to resolve resource patterns into arrays of Resource objects. This will always * work when running in an ApplicationContext (the context interface extends * ResourcePatternResolver). Use a PathMatchingResourcePatternResolver as default. * See also the {@code ResourcePatternUtils.getResourcePatternResolver} method. * * <p>As alternative to a ResourcePatternResolver dependency, consider exposing * bean properties of type Resource array, populated via pattern Strings with * automatic type conversion by the bean factory. * * @author Juergen Hoeller * @author Chris Beams * @since 10.03.2004 * @see ApplicationContextAware * @see org.springframework.beans.factory.InitializingBean * @see org.springframework.core.io.Resource * @see org.springframework.core.io.support.ResourcePatternResolver * @see org.springframework.core.io.support.ResourcePatternUtils#getResourcePatternResolver * @see org.springframework.core.io.DefaultResourceLoader * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver * @see org.springframework.context.support.ReloadableResourceBundleMessageSource */public interface ResourceLoaderAware extends Aware {   /**    * Set the ResourceLoader that this object runs in.    * <p>This might be a ResourcePatternResolver, which can be checked    * through {@code instanceof ResourcePatternResolver}. See also the    * {@code ResourcePatternUtils.getResourcePatternResolver} method.    * <p>Invoked after population of normal bean properties but before an init callback    * like InitializingBean's {@code afterPropertiesSet} or a custom init-method.    * Invoked before ApplicationContextAware's {@code setApplicationContext}.    * @param resourceLoader ResourceLoader object to be used by this object    * @see org.springframework.core.io.support.ResourcePatternResolver    * @see org.springframework.core.io.support.ResourcePatternUtils#getResourcePatternResolver    */   void setResourceLoader(ResourceLoader resourceLoader);}

獲取ResourceLoader的方法實現 ResourceLoaderAware 這個接口,在容器啓動給你注入(這個樣子很差,耦合api)

第二種作法用註解

@Autowired private ResourceLoader resourceLoader;

看來spring爲你們提供了好多Aware接口去獲取系統的對象啊這個一個擴展思路,能夠借鑑下!


四、什麼時候加載Resource


ApplicationContext applicationContext =
        new FileSystemXmlApplicationContext("file:src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml");

爲例子,在

 1

FileSystemXmlApplicationContext("file:src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml");
調用
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, true, null);
}
再調用
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}


一直調用至父類 AbstractApplicationContext
public AbstractApplicationContext(ApplicationContext parent) {
   this();
   setParent(parent);
}

在調用
public AbstractApplicationContext() {
   this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
   return new PathMatchingResourcePatternResolver(this);
}
這個時候獲取Resource的Resolver類被設定了
PathMatchingResourcePatternResolver

public PathMatchingResourcePatternResolver() {
        this.resourceLoader = new DefaultResourceLoader();
    }

public ResourceLoader getResourceLoader() {
   return this.resourceLoader;
}

@Override
public ClassLoader getClassLoader() {
   return getResourceLoader().getClassLoader();
}

@Override
public Resource[] getResources(String locationPattern) throws IOException {
   Assert.notNull(locationPattern, "Location pattern must not be null");
   if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
      // a class path resource (multiple resources for same name possible)
      if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
         // a class path resource pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // all class path resources with the given name
         return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
      }
   }
   else {
      // Only look for a pattern after a prefix here
      // (to not get fooled by a pattern symbol in a strange prefix).
      int prefixEnd = locationPattern.indexOf(":") + 1;
      if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
         // a file pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // a single resource with the given name
         return new Resource[] {getResourceLoader().getResource(locationPattern)};
      }
   }
}


再獲取資源的時候會調用DefaultResourceLoader的getResource

@Override
public Resource getResource(String location) {
   Assert.notNull(location, "Location must not be null");
   if (location.startsWith("/")) {
      return getResourceByPath(location);
   }
   else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
      return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
   }
   else {
      try {
         // Try to parse the location as a URL...
         URL url = new URL(location);
         return new UrlResource(url);
      }
      catch (MalformedURLException ex) {
         // No URL -> resolve as resource path.
         return getResourceByPath(location);
      }
   }
}

ok至此獲取資源的流程清晰了

別忘記此時指示初始化了,尚未被調用,回到

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
     // Prepare this context for refreshing.
     prepareRefresh();

     // Tell the subclass to refresh the internal bean factory.
     ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

     // Prepare the bean factory for use in this context.
     prepareBeanFactory(beanFactory);

     try {
        // Allows post-processing of the bean factory in context subclasses.
        postProcessBeanFactory(beanFactory);

        // Invoke factory processors registered as beans in the context.
        invokeBeanFactoryPostProcessors(beanFactory);

        // Register bean processors that intercept bean creation.
        registerBeanPostProcessors(beanFactory);

        // Initialize message source for this context.
        initMessageSource();

        // Initialize event multicaster for this context.
        initApplicationEventMulticaster();

        // Initialize other special beans in specific context subclasses.
        onRefresh();

        // Check for listener beans and register them.
        registerListeners();

        // Instantiate all remaining (non-lazy-init) singletons.
        finishBeanFactoryInitialization(beanFactory);

        // Last step: publish corresponding event.
        finishRefresh();
     }

     catch (BeansException ex) {
        logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

        // Destroy already created singletons to avoid dangling resources.
        destroyBeans();

        // Reset 'active' flag.
        cancelRefresh(ex);

        // Propagate exception to caller.
        throw ex;
     }
  }
}
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}


protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

到了關鍵了在

loadBeanDefinitions(beanFactory);方法時候

AbstractXmlApplicationContext的

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}

而後是

AbstractBeanDefinitionReader的
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
   Assert.notNull(locations, "Location array must not be null");
   int counter = 0;
   for (String location : locations) {
      counter += loadBeanDefinitions(location);
   }
   return counter;
}

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
   ResourceLoader resourceLoader = getResourceLoader();
   if (resourceLoader == null) {
      throw new BeanDefinitionStoreException(
            "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
   }

   if (resourceLoader instanceof ResourcePatternResolver) {
      // Resource pattern matching available.
      try {
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
         int loadCount = loadBeanDefinitions(resources);
         if (actualResources != null) {
            for (Resource resource : resources) {
               actualResources.add(resource);
            }
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
         }
         return loadCount;
      }
      catch (IOException ex) {
         throw new BeanDefinitionStoreException(
               "Could not resolve bean definition resource pattern [" + location + "]", ex);
      }
   }
   else {
      // Can only load single resources by absolute URL.
      Resource resource = resourceLoader.getResource(location);
      int loadCount = loadBeanDefinitions(resource);
      if (actualResources != null) {
         actualResources.add(resource);
      }
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
      }
      return loadCount;
   }
}





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

便是調用PathMatchingResourcePatternResolver的getResources

@Override
public Resource[] getResources(String locationPattern) throws IOException {
   Assert.notNull(locationPattern, "Location pattern must not be null");
   if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
      // a class path resource (multiple resources for same name possible)
      if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
         // a class path resource pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // all class path resources with the given name
         return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
      }
   }
   else {
      // Only look for a pattern after a prefix here
      // (to not get fooled by a pattern symbol in a strange prefix).
      int prefixEnd = locationPattern.indexOf(":") + 1;
      if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
         // a file pattern
         return findPathMatchingResources(locationPattern);
      }
      else {
         // a single resource with the given name
         return new Resource[] {getResourceLoader().getResource(locationPattern)};
      }
   }
}

ok完成了 入口就是在

AbstractApplicationContext的refresh方法裏面的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
相關文章
相關標籤/搜索