spring源代码分析(1)--Resource的分析(转载)

原文出处:http://wang4674890.iteye.com/blog/1772695

 

我们知道,在spring中,配置文件是通过资源形式加载的,我们首先来分析一些在spring中资源类的结构,并且查看一下资源的类型;

资源类图如下:

 
Java代码  收藏代码
  1. public interface InputStreamSource {  
  2.   
  3.     /** 
  4.      * Return an {@link InputStream}. 
  5.      * <p>It is expected that each call creates a <i>fresh</i> stream. 
  6.      * <p>This requirement is particularly important when you consider an API such 
  7.      * as JavaMail, which needs to be able to read the stream multiple times when 
  8.      * creating mail attachments. For such a use case, it is <i>required</i> 
  9.      * that each <code>getInputStream()</code> call returns a fresh stream. 
  10.      * @throws IOException if the stream could not be opened 
  11.      * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource) 
  12.      */  
  13.     InputStream getInputStream() throws IOException;  
  14.   
  15. }  

 

抽象出这层接口,事实上是把java底层的二进制流和spring中的resource给对应以来,把inputstream包装进Resource;



Java代码  收藏代码
  1. public interface Resource extends InputStreamSource {  
  2.   
  3.     /** 
  4.      * Return whether this resource actually exists in physical form. 
  5.      * <p>This method performs a definitive existence check, whereas the 
  6.      * existence of a <code>Resource</code> handle only guarantees a 
  7.      * valid descriptor handle. 
  8.      */  
  9.     boolean exists();  
  10.   
  11.     /** 
  12.      * Return whether the contents of this resource can be read, 
  13.      * e.g. via {@link #getInputStream()} or {@link #getFile()}. 
  14.      * <p>Will be <code>true</code> for typical resource descriptors; 
  15.      * note that actual content reading may still fail when attempted. 
  16.      * However, a value of <code>false</code> is a definitive indication 
  17.      * that the resource content cannot be read. 
  18.      */  
  19.     boolean isReadable();  
  20.   
  21.     /** 
  22.      * Return whether this resource represents a handle with an open 
  23.      * stream. If true, the InputStream cannot be read multiple times, 
  24.      * and must be read and closed to avoid resource leaks. 
  25.      * <p>Will be <code>false</code> for typical resource descriptors. 
  26.      */  
  27.     boolean isOpen();  
  28.   
  29.     /** 
  30.      * Return a URL handle for this resource. 
  31.      * @throws IOException if the resource cannot be resolved as URL, 
  32.      * i.e. if the resource is not available as descriptor 
  33.      */  
  34.     URL getURL() throws IOException;  
  35.   
  36.     /** 
  37.      * Return a URI handle for this resource. 
  38.      * @throws IOException if the resource cannot be resolved as URI, 
  39.      * i.e. if the resource is not available as descriptor 
  40.      */  
  41.     URI getURI() throws IOException;  
  42.   
  43.     /** 
  44.      * Return a File handle for this resource. 
  45.      * @throws IOException if the resource cannot be resolved as absolute 
  46.      * file path, i.e. if the resource is not available in a file system 
  47.      */  
  48.     File getFile() throws IOException;  
  49.   
  50.     /** 
  51.      * Determine the content length for this resource. 
  52.      * @throws IOException if the resource cannot be resolved 
  53.      * (in the file system or as some other known physical resource type) 
  54.      */  
  55.     long contentLength() throws IOException;  
  56.   
  57.     /** 
  58.      * Determine the last-modified timestamp for this resource. 
  59.      * @throws IOException if the resource cannot be resolved 
  60.      * (in the file system or as some other known physical resource type) 
  61.      */  
  62.     long lastModified() throws IOException;  
  63.   
  64.     /** 
  65.      * Create a resource relative to this resource. 
  66.      * @param relativePath the relative path (relative to this resource) 
  67.      * @return the resource handle for the relative resource 
  68.      * @throws IOException if the relative resource cannot be determined 
  69.      */  
  70.     Resource createRelative(String relativePath) throws IOException;  
  71.   
  72.     /** 
  73.      * Return a filename for this resource, i.e. typically the last 
  74.      * part of the path: for example, "myfile.txt". 
  75.      */  
  76.     String getFilename();  
  77.   
  78.     /** 
  79.      * Return a description for this resource, 
  80.      * to be used for error output when working with the resource. 
  81.      * <p>Implementations are also encouraged to return this value 
  82.      * from their <code>toString</code> method. 
  83.      * @see java.lang.Object#toString() 
  84.      */  
  85.     String getDescription();  
  86.   
  87. }  
 
抽象出来的Resource功能接口对于下面多种不同类型的资源,其有很多功能接口的实现势必是相同的,所以在这里spring建立了一个抽象类,在设计模式中,抽象类应该做到的是,尽量把子类相同的功能方法放到抽象父类中实现,增加复用,而尽量把少的数据推到子类中实现,减少空间的消耗;

                 

在这类Resource中,我们使用得最多的,估计就是要属于ClassPathResource和FileSystemReource;顾名思意,这两种资源类分别是默认在ClassPath和FileSystem下查找资源;而我们用得最多的是classPath,因为这样对工程的移植更有利;
Java代码  收藏代码
  1. public class ClassPathResource extends AbstractFileResolvingResource {  
  2.   
  3.     private final String path;  
  4.   
  5.     private ClassLoader classLoader;  
  6.   
  7.     private Class<?> clazz;  
  8.   
  9.   
  10.     /** 
  11.      * Create a new ClassPathResource for ClassLoader usage. 
  12.      * A leading slash will be removed, as the ClassLoader 
  13.      * resource access methods will not accept it. 
  14.      * <p>The thread context class loader will be used for 
  15.      * loading the resource. 
  16.      * @param path the absolute path within the class path 
  17.      * @see java.lang.ClassLoader#getResourceAsStream(String) 
  18.      * @see org.springframework.util.ClassUtils#getDefaultClassLoader() 
  19.      */  
  20.     public ClassPathResource(String path) {  
  21.         this(path, (ClassLoader) null);  
  22.     }  
  23.   
  24.     /** 
  25.      * Create a new ClassPathResource for ClassLoader usage. 
  26.      * A leading slash will be removed, as the ClassLoader 
  27.      * resource access methods will not accept it. 
  28.      * @param path the absolute path within the classpath 
  29.      * @param classLoader the class loader to load the resource with, 
  30.      * or <code>null</code> for the thread context class loader 
  31.      * @see java.lang.ClassLoader#getResourceAsStream(String) 
  32.      */  
  33.     public ClassPathResource(String path, ClassLoader classLoader) {  
  34.         Assert.notNull(path, "Path must not be null");  
  35.         String pathToUse = StringUtils.cleanPath(path);  
  36.         if (pathToUse.startsWith("/")) {  
  37.             pathToUse = pathToUse.substring(1);  
  38.         }  
  39.         this.path = pathToUse;  
  40.         this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());  
  41.     }  
  42.   
  43.     /** 
  44.      * Create a new ClassPathResource for Class usage. 
  45.      * The path can be relative to the given class, 
  46.      * or absolute within the classpath via a leading slash. 
  47.      * @param path relative or absolute path within the class path 
  48.      * @param clazz the class to load resources with 
  49.      * @see java.lang.Class#getResourceAsStream 
  50.      */  
  51.     public ClassPathResource(String path, Class<?> clazz) {  
  52.         Assert.notNull(path, "Path must not be null");  
  53.         this.path = StringUtils.cleanPath(path);  
  54.         this.clazz = clazz;  
  55.     }  
  56.   
  57.     /** 
  58.      * Create a new ClassPathResource with optional ClassLoader and Class. 
  59.      * Only for internal usage. 
  60.      * @param path relative or absolute path within the classpath 
  61.      * @param classLoader the class loader to load the resource with, if any 
  62.      * @param clazz the class to load resources with, if any 
  63.      */  
  64.     protected ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {  
  65.         this.path = StringUtils.cleanPath(path);  
  66.         this.classLoader = classLoader;  
  67.         this.clazz = clazz;  
  68.     }  
  69.   
  70.   
  71.     /** 
  72.      * Return the path for this resource (as resource path within the class path). 
  73.      */  
  74.     public final String getPath() {  
  75.         return this.path;  
  76.     }  
  77.   
  78.     /** 
  79.      * Return the ClassLoader that this resource will be obtained from. 
  80.      */  
  81.     public final ClassLoader getClassLoader() {  
  82.         return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader());  
  83.     }  
  84.   
  85.   
  86.     /** 
  87.      * This implementation checks for the resolution of a resource URL. 
  88.      * @see java.lang.ClassLoader#getResource(String) 
  89.      * @see java.lang.Class#getResource(String) 
  90.      */  
  91.     @Override  
  92.     public boolean exists() {  
  93.         URL url;  
  94.         if (this.clazz != null) {  
  95.             url = this.clazz.getResource(this.path);  
  96.         }  
  97.         else {  
  98.             url = this.classLoader.getResource(this.path);  
  99.         }  
  100.         return (url != null);  
  101.     }  
  102.   
  103.     /** 
  104.      * This implementation opens an InputStream for the given class path resource. 
  105.      * @see java.lang.ClassLoader#getResourceAsStream(String) 
  106.      * @see java.lang.Class#getResourceAsStream(String) 
  107.      */  
  108.     public InputStream getInputStream() throws IOException {  
  109.         InputStream is;  
  110.         if (this.clazz != null) {  
  111.             is = this.clazz.getResourceAsStream(this.path);  
  112.         }  
  113.         else {  
  114.             is = this.classLoader.getResourceAsStream(this.path);  
  115.         }  
  116.         if (is == null) {  
  117.             throw new FileNotFoundException(  
  118.                     getDescription() + " cannot be opened because it does not exist");  
  119.         }  
  120.         return is;  
  121.     }  
  122.   
  123.     /** 
  124.      * This implementation returns a URL for the underlying class path resource. 
  125.      * @see java.lang.ClassLoader#getResource(String) 
  126.      * @see java.lang.Class#getResource(String) 
  127.      */  
  128.     @Override  
  129.     public URL getURL() throws IOException {  
  130.         URL url;  
  131.         if (this.clazz != null) {  
  132.             url = this.clazz.getResource(this.path);  
  133.         }  
  134.         else {  
  135.             url = this.classLoader.getResource(this.path);  
  136.         }  
  137.         if (url == null) {  
  138.             throw new FileNotFoundException(  
  139.                     getDescription() + " cannot be resolved to URL because it does not exist");  
  140.         }  
  141.         return url;  
  142.     }  
  143.   
  144.     /** 
  145.      * This implementation creates a ClassPathResource, applying the given path 
  146.      * relative to the path of the underlying resource of this descriptor. 
  147.      * @see org.springframework.util.StringUtils#applyRelativePath(String, String) 
  148.      */  
  149.     @Override  
  150.     public Resource createRelative(String relativePath) {  
  151.         String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);  
  152.         return new ClassPathResource(pathToUse, this.classLoader, this.clazz);  
  153.     }  
  154.   
  155.     /** 
  156.      * This implementation returns the name of the file that this class path 
  157.      * resource refers to. 
  158.      * @see org.springframework.util.StringUtils#getFilename(String) 
  159.      */  
  160.     @Override  
  161.     public String getFilename() {  
  162.         return StringUtils.getFilename(this.path);  
  163.     }  
  164.   
  165.     /** 
  166.      * This implementation returns a description that includes the class path location. 
  167.      */  
  168.     public String getDescription() {  
  169.         StringBuilder builder = new StringBuilder("class path resource [");  
  170.   
  171.         if (this.clazz != null) {  
  172.             builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));  
  173.             builder.append('/');  
  174.         }  
  175.   
  176.         builder.append(this.path);  
  177.         builder.append(']');  
  178.         return builder.toString();  
  179.     }  
  180.   
  181.   
  182.     /** 
  183.      * This implementation compares the underlying class path locations. 
  184.      */  
  185.     @Override  
  186.     public boolean equals(Object obj) {  
  187.         if (obj == this) {  
  188.             return true;  
  189.         }  
  190.         if (obj instanceof ClassPathResource) {  
  191.             ClassPathResource otherRes = (ClassPathResource) obj;  
  192.             return (this.path.equals(otherRes.path) &&  
  193.                     ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&  
  194.                     ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));  
  195.         }  
  196.         return false;  
  197.     }  
  198.   
  199.     /** 
  200.      * This implementation returns the hash code of the underlying 
  201.      * class path location. 
  202.      */  
  203.     @Override  
  204.     public int hashCode() {  
  205.         return this.path.hashCode();  
  206.     }  
  207.   
  208. }  
 


是将//tihuan成/的代码,我们可见,在这段代码中,对传入的参数进行了严密的验证,正如代码大全中所介绍的防御性编程,我们假定从public传入进来的参数都是不安全的,只有在私有方法中,我们才对传入的参数不进行合法验证;

在这里,我们很明显的看出,代码中使用了适配器模式中的类适配器,在新的接口中,我们用resource接口包装了File,
在新的接口中,我们依然能访问file的isExist方法,却丝毫不知道我们是用的file;
其中,StrigUtils类是一个工具,他对path进行了预处理,处理了如//分解符和.  ..等文件路径描述的特殊操作符
另外的byte等资源,跟bye和ByteInputeStream的关系是类似的,分别是把不同源的数据当作资源,不过ClasspathResource不同的是,你可以传入ClassLoader或者Class来制定当前的类加载器,从而可以确定资源文件的BascDir
如果你不制定classLoader的话和Class的话,那么就会默认是当前线程的ClassLoader,而在这里,PATH和ClassLoader的预处理,都是经过了一个工具类来进行的,可以,在总段代码中,我们看见了很多的复用性和组织性,很多细节的方面的值得我们效仿和学习
posted @ 2016-06-17 16:27  青青子衿J  阅读(232)  评论(0)    收藏  举报