精华内容
下载资源
问答
  • 解析Resource格式

    2016-02-03 15:25:59
    Android中解析编译之后的
  • vue-resource.js

    千次下载 热门讨论 2016-04-20 12:47:03
    vue-resource.js,其他地方还没有找到可以下载的
  • Spring ClassPathResource详解

    万次阅读 2019-08-07 17:43:47
    org.springframework.core.io.ClassPathResource位于Spring核心core下,用以表达类路径下的资源。

            org.springframework.core.io.ClassPathResource位于Spring核心core下,用以表达类路径下的资源。
            首先简要说明一下什么是classpath,顾名思义,就是存放*.class类文件的路径,或者说ClassLoader加载类时为找到 *.class文件的路径。我们以一个WEB项目为例,发布后的目录结构大致如下:

            然后以Tomcat为例,看一下WEB项目类加载时候的目录,参考 Tomcat Class Loader How-To 中的说明:

    WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes directory of your web application, plus classes and resources in JAR files under the /WEB-INF/lib directory of your web application, are made visible to this web application, but not to other ones.

            因此,对于部署在Tomcat上的WEB应用来说,/WEB-INF/classes和/WEB-INF/lib目录就是我们所指的classpath。

            ClassPathResource是org.springframework.core.io.Resource接口的实现类。可以使用ClassLoader或Class类加载资源。支持转换为java.io.File对象(在Jar文件中的资源除外)。其继承实现关系图如下:

            ClasspathResource类的属性变量和构造方法如下:

    	private final String path;
    	@Nullable
    	private ClassLoader classLoader;// 通过ClassLoader加载资源文件
    	@Nullable
    	private Class<?> clazz; // 通过Class类加载资源文件
    	
    	// 通过类路径创建resource
    	public ClassPathResource(String path){...}
    	
    	// 通过类路径和给定的ClassLoader创建resource
    	public ClassPathResource(String path, @Nullable ClassLoader classLoader){...}
    	
    	// 通过类路径和给定的Class类创建resource
    	public ClassPathResource(String path, @Nullable Class<?> clazz){...}
    	
    	// 通过类路径和给定的ClassLoader或Class创建resource
    	protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz){...}
    
    

            在类继承关系中,每个类定义的方法如下:

    ResourceAbstractResourceAbstractFileResolvingResourceClassPathResource
    对底层资源的抽象描述
    比如文件或类路径资源
    对资源接口描述的基础实现
    预先实现特定的行为
    将URL解析为文件资源引用的抽象基类,尤其对JBOOS的vfs文件协议的支持类路径资源的Resource实现
    boolean exists()
    判断该资源是否存在
    public boolean exists()
    实现父接口方法,检查资源(文件或目录)File对象或资源(文件)InputStream对象是否打开
    public boolean exists()
    重写父类方法,getURL后如果URL的文件协议是file:vfsfile:vfs则返回getFile().exists()直接判断该文件是否存在,如果非上述文件协议则尝试判断是否网络资源,通过HTTP请求看是否返回HTTP Status-Code=200,如果扔非上述,则尝试getInputStream().close()看文件流是否可打开
    public boolean exists()
    重写父类方法,判断是否能获取到该资源的URL对象
    boolean isReadable()
    是否可通过InputStreamSource.getInputStream()读取,这里注意返回true仍然可能读取失败,但返回false一定是不能读取
    默认返回exists()
    public boolean isReadable()
    实现父接口方法,该方法在当资源存在的情况下始终返回true,返回值与父接口方法中定义的默认返回值一致,即返回exists()
    public boolean isReadable()
    重写父类方法,getURL后如果URL的文件协议是file:vfsfile:vfs则getFile得到该资源File对象,判断该File资源是否非目录且canRead可读,如果非上述文件协议则尝试调用网络资源,判断是否可成功调用且返回内容长度大于0,如果扔非上述,则尝试getInputStream().close()看文件流是否可打开
    boolean isOpen()
    表明该资源是否有打开的stream流,如果返回true则InputStream无法多次读取,且读完之后关闭流以防止内存泄露
    默认返回false
    public boolean isOpen()
    实现父接口方法,与接口方法中定义的默认返回值一致,即始终返回false
    boolean isFile()
    判断该文件是否是系统文件中的文件,true值表示(但不保证)可以成功调用getFile()方法
    默认返回false
    public boolean isFile()
    实现父接口方法,与接口方法中定义的默认返回值一致,即始终返回false
    public boolean isFile()
    重写父类方法,getURL后如果url为vfs开头协议(vfs/vfsfile)则交给VfsResourceDelegate类判断,如果url为file协议则返回true
    protected boolean isFile(URI uri)
    重载isFile方法,根据指定的URI判断该资源是否是一个文件引用,如果URI的scheme以vfs开头则交给VfsResourceDelegate类判断,否则判断如果URI的scheme等于file则返回true
    URL getURL()
    返回该资源对应的URL
    public URL getURL()
    实现父接口方法,这里假设资源不能解析为URL,直接返回了FileNotFoundException异常
    public URL getURL()
    重写父类方法,根据类路径参数获取该资源的URL对象
    URI getURI()
    返回该资源对应的URI
    public URI getURI()
    实现父接口方法,基于getURL返回的URL构建一个URI
    File getFile()
    返回该资源的File对象
    public File getFile()
    实现父接口方法,这里假设资源无法解析为文件绝对路径,直接返回了FileNotFoundException异常
    public File getFile()
    重写父类方法,父类直接返回FileNotFoundException异常,在这里通过getURL获取到URL对象(具体URL由其子类确定,比如ClasspathResource重写了getURL通过类加载器获取到了类路径资源的URL),如果url为vfs开头协议(vfs/vfsfile)则交给VfsResourceDelegate类获取File对象,否则通过得到url获取File对象
    protected File getFile(URI uri)
    重载getFile方法,根据指定的URI获取资源File对象,如果URI的scheme以vfs开头则交给VfsResourceDelegate类获取
    ReadableByteChannel readableChannel()
    默认返回Channels.newChannel(getInputStream())
    public ReadableByteChannel readableChannel()
    实现父接口方法,与父接口的默认返回值相同
    public ReadableByteChannel readableChannel()
    根据指定的URI调用FileChannel.open 返回一个ReadableByteChannel对象
    long contentLength()
    返回该资源内容的长度
    public long contentLength()
    根据getInputStream()返回的InputStream,读取并计算资源的内容长度
    public long contentLength()
    根据getURL获得URL对象,如果是文件(file/vfsfile/vfs)URL返回文件长度,否则尝试网络连接获取资源并返回长度
    long lastModified()
    返回该资源最后一次修改的时间戳
    public long lastModified()
    获取并返回该资源文件的时间戳
    public long lastModified()
    根据getURL获取URL对象,如果是文件(file/vfsfile/vfs)或归档文件(jar/war/zip/vfszip/wsjar)则获取文件的最后修改时间戳,否则获取网络连接并获取最后修改时间戳
    Resource createRelative(String relativePath)
    根据相对于该资源的相对路径,创建一个Resource资源,比如classpath资源目录conf下有A.xml和B.xml,Resource a = new ClassPathResource("conf/A.xml"); 那么在创建b资源的时候就可以以a为参照Resource b = a.createRelative("B.xml");
    public Resource createRelative(String relativePath)
    实现父接口方法,这里假设改相对资源未被创建,直接返回了FileNotFoundException异常
    public Resource createRelative(String relativePath)
    重写父类方法,根据参照资源的类路径得到relativePath参数的真实classpath路径,并创建Resource资源对象
    String getFilename()
    返回该资源的文件名,通常是路径的最后一部分,比如:myfile.txt
    public String getFilename()
    实现父接口方法,这里假设该资源无文件名,直接返回了null
    public String getFilename()
    重写父类方法,根据classpath截取后面的文件名并返回
    String getDescription()
    返回该资源的描述,用于该资源在处理时的错误输出
    public String getDescription()
    重写父类方法,返回格式如class path resource [...]的内容
    protected File getFileForLastModifiedCheck()
    获取用于时间戳检查的文件,这里默认返回了getFile()
    protected File getFileForLastModifiedCheck()
    重写父类方法,扩展了父类方法,在getFile之前先判断url协议是否为jar/war/zip/vfszip/wsjar,如果是则获取最外层的文件URL对应的File对象,比如嵌套在war中的jar文件,则返回war文件File对象。这里判断vfs开头协议扔交给VfsResourceDelegate类来处理
    public boolean equals(Object other)
    重写Object的equals方法,用于比较两个Resource的Description是否相同
    public boolean equals(Object other)
    重写Object方法,比较类路径的值是否相同
    public int hashCode()
    重写Object的hashCode方法,用于获取Resource的Description值的hashCode值
    public int hashCode()
    重写Object方法,获取类路径classpath的hashCode值
    public String toString()
    重写Object的toString方法,返回Resource的Description信息
    public final String getPath()
    返回该资源的classpath,构造函数的path参数经过规范化处理的结果
    public final ClassLoader getClassLoader()
    如果指定了Class,则通过该Class获取ClassLoader,否则返回属性变量的ClassLoader参数
    public InputStream getInputStream()
    Resource继承了InputStreamSource接口,在ClassPathResource中得到了具体的实现,根据资源路径得到文件流

            在AbstractFileResolvingResource类中由于增加了对JBOOS的vfs文件协议的支持,因此包含了一个`VfsResourceDelegate`内部类用于获取`VfsResource`类型资源对象,该资源对象同样继承自`AbstractResource`抽象类,并针对vfs文件的特点对方法进行了重写。如下:
    /**
     * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
     */
    private static class VfsResourceDelegate {
    
    	public static Resource getResource(URL url) throws IOException {
    		return new VfsResource(VfsUtils.getRoot(url));
    	}
    
    	public static Resource getResource(URI uri) throws IOException {
    		return new VfsResource(VfsUtils.getRoot(uri));
    	}
    }
    

    ClassPathResource的使用:

    Resource resource = new ClassPathResource("conf/custom-beans.xml");
    

    参数path应在类路径下能够被ClassLoader所加载。

            获取到了Resource对象也就等于获取到了该资源文件,后面可以根据方法的定义对文件进行相关操作。

    System.out.println(resource.getURL());
    System.out.println(resource.getFilename());
    System.out.println(resource.getFile().getPath());
    // ... ....
    
    展开全文
  • 1、spring之Resource加载

    千次阅读 2019-04-10 20:37:38
    也就是说,不管什么格式的文件,也不管文件在哪里,到Spring 底层,都只有一个访问接口,Resource。 1.1 类结构图 1.2 类和接口分析 1、可以看到有四个比较重要的接口 InputStreamSource、Resource、...

    一、对资源的抽象

    Spring把其资源做了一个抽象,底层使用统一的资源访问接口来访问Spring的所有资源。也就是说,不管什么格式的文件,也不管文件在哪里,到Spring 底层,都只有一个访问接口,Resource。

    1.1 类结构图

    在这里插入图片描述

    1.2 类和接口分析

    1、可以看到有四个比较重要的接口 InputStreamSource、Resource、WritableResource、ContextResource。
    a 、InputStreamSource接口

    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;
    }
    

    b、Resource接口
    接口中定义了对于资源的判断、对资源的获取、对资源描述的获取。通过该接口可以对资源进行有效的操作。但是Resource接口注重于对资源的读取。

    public interface Resource extends InputStreamSource {
    
    	/**
    	 * 判断是否存在
    	 */
    	boolean exists();
    
    	/**
    	 * 判断是否可读
    	 */
    	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.
    	 * 判断流是否可以重复读取,如果为true的话表示不可以重复读取,在读取完成后需要关闭流
    	 */
    	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();
    
    }
    

    C、WritableResource
    因为Resource接口主要是注重对资源的读取,当我们对资源进行写入的时候,需要获取对应的判断和输出流。WritableResource接口主要定义了对写入的支持。

    public interface WritableResource extends Resource {
    
    	/**
    	 * 返回资源是否可以被写入
    	 */
    	boolean isWritable();
    
    	/**
    	 * 获取资源的写入流
    	 */
    	OutputStream getOutputStream() throws IOException;
    
    }
    

    D、ContextResource
    有些资源是相对于当前的容器的,用来获取容器中的资源。

    public interface ContextResource extends Resource {
    
    	/**
    	 * Return the path within the enclosing 'context'.
    	 * <p>This is typically path relative to a context-specific root directory,
    	 * e.g. a ServletContext root or a PortletContext root.
    	 */
    	String getPathWithinContext();
    
    }
    

    2、存在一个AbstractResource的抽象类,所有的对于资源获取都继承自AbstractResource抽象类。

    3、其余的都是具体的实现类
    用来加载指定的资源

    二、对资源的加载

    Spring框架为了更方便的获取资源,尽量弱化程序员对各个Resource接口的实现类的感知,定义了另一个ResourceLoader接口。 接口有一个特别重要的方法:Resource getResource(String location),返回Resource实例。因此程序员在使用Spring容器时,可以不去过于计较底层Resource的实现,也不需要自己创建Resource实现类,而是直接使用ReourceLoader,获取到bean容器本身的Resource,进而取到相关的资源信息。

    2.1 类继承图

    在这里插入图片描述

    2.2 类和接口分析

    1. 接口ResourceLoader和ResourcePatternResolver
      a、ResourceLoader接口
      只能对classpath路径下面的资源进行加载,并且只会加载指定的文件的
    public interface ResourceLoader {
    
    	/** Pseudo URL prefix for loading from the class path: "classpath:" */
    	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
    
    
    	/**
    	 * 用来根据location来获取对应的资源
    	 */
    	Resource getResource(String location);
    
    	/**
    	 * 获取类加载器
    	 */
    	ClassLoader getClassLoader();
    
    }
    

    b、ResourcePatternResolver接口
    表示会加载所有路径下面的文件,包括jar包中的文件。同时locationPattern可以设置为表达式来加载对应的文件。

    public interface ResourcePatternResolver extends ResourceLoader {
    
    	/**
    	 * 表示会加载所有路径下面的文件,包括jar包中
    	 */
    	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    
    	/**
    	 * 根据
    	 */
    	Resource[] getResources(String locationPattern) throws IOException;
    
    }
    

    区别
    classpath: :表示从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。资源文件库标准的在文件系统中,也可以在JAR或ZIP的类包中。

    classpath:*:假设多个JAR包或文件系统类路径都有一个相同的配置文件,classpath:只会在第一个加载的类路径下查找,而classpath*:会扫描所有这些JAR包及类路径下出现的同名文件。

    1. DefaultResourceLoader
      spring实现的默认的加载器,一般其他的加载器会继承该类,并重写getResourceByPath方法
    public Resource getResource(String location) {
    		Assert.notNull(location, "Location must not be null");
    		// 以/开头,那么根据path去查找
    		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 {
    			try {
    				// 其他情况采用UrlResource来进行加载
    				URL url = new URL(location);
    				return new UrlResource(url);
    			}
    			catch (MalformedURLException ex) {
    				// No URL -> resolve as resource path.
    				return getResourceByPath(location);
    			}
    		}
    	}
    
    1. PathMatchingResourcePatternResolver
      Spring提供了一个ResourcePatternResolver实现PathMatchingResourcePatternResolver,它是基于模式匹配的,默认使用AntPathMatcher进行路径匹配,它除了支持ResourceLoader支持的前缀外,还额外支持“classpath*:”用于加载所有匹配的类路径Resource,ResourceLoader不支持前缀“classpath*:”:

    三、Resource的一些工具类

    3.1 工具类截图

    在这里插入图片描述

    3.2 详解

    1、EncodedResource
    当您使用 Resource 实现类加载文件资源时,它默认采用操作系统的编码格式。
    如果文件资源采用了特殊的编码格式(如 UTF-8),则在读取资源内容时必须事先通过 EncodedResource 指定编码格式,否则将会产生中文乱码的问题。

    public class EncodedResource {
    
    	private final Resource resource;
    
    	private final String encoding;
    
    	private final Charset charset;
    
    	/**
    	 * 根据encoding和charset是否存在来判断是否可以获取Reader
    	 */
    	public boolean requiresReader() {
    		return (this.encoding != null || this.charset != null);
    	}
    
    	/**
    	 * 根据EncodedResource信息获取Reader信息
    	 */
    	public Reader getReader() throws IOException {
    		if (this.charset != null) {
    			return new InputStreamReader(this.resource.getInputStream(), this.charset);
    		}
    		else if (this.encoding != null) {
    			return new InputStreamReader(this.resource.getInputStream(), this.encoding);
    		}
    		else {
    			return new InputStreamReader(this.resource.getInputStream());
    		}
    	}
    
    	/**
    	 * Open a {@code java.io.InputStream} for the specified resource, ignoring any
    	 * specified {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}.
    	 * @throws IOException if opening the InputStream failed
    	 * @see #requiresReader()
    	 * @see #getReader()
    	 */
    	public InputStream getInputStream() throws IOException {
    		return this.resource.getInputStream();
    	}
    
    }
    

    2、ResourcePatternUtils

    /**
    	 * Return whether the given resource location is a URL: either a
    	 * special "classpath" or "classpath*" pseudo URL or a standard URL
    	 */
    	public static boolean isUrl(String resourceLocation) {
    		return (resourceLocation != null &&
    				(resourceLocation.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX) ||
    						ResourceUtils.isUrl(resourceLocation)));
    	}
    
    	/**
    	 * 根据ResourceLoader构建一个ResourcePatternResolver
    	 */
    	public static ResourcePatternResolver getResourcePatternResolver(ResourceLoader resourceLoader) {
    		Assert.notNull(resourceLoader, "ResourceLoader must not be null");
    		if (resourceLoader instanceof ResourcePatternResolver) {
    			return (ResourcePatternResolver) resourceLoader;
    		}
    		else if (resourceLoader != null) {
    			return new PathMatchingResourcePatternResolver(resourceLoader);
    		}
    		else {
    			return new PathMatchingResourcePatternResolver();
    		}
    	}
    

    3、PropertiesLoaderUtils
    根据提供的Resource或者EncodedResource,将其中的内容转换为Property内容。

    展开全文
  • Spring中Resource接口详解

    千次阅读 2018-02-22 10:49:15
    createRelative:用于创建相对于当前Resource代表的底层资源的资源,比如当前Resource代表文件资源“d:/test/”则createRelative(“test.txt”)将返回表文件资源“d:/test/test.txt”Resource资源。 getFilename...

    原本地址:https://www.cnblogs.com/yw0219/p/7255522.html
    在日常程序开发中,处理外部资源是很繁琐的事情,我们可能需要处理URL资源、File资源资源、ClassPath相关资源、服务器相关资源(JBoss AS 5.x上的VFS资源)等等很多资源。因此处理这些资源需要使用不同的接口,这就增加了我们系统的复杂性;而且处理这些资源步骤都是类似的(打开资源、读取资源、关闭资源),因此如果能抽象出一个统一的接口来对这些底层资源进行统一访问,是不是很方便,而且使我们系统更加简洁,都是对不同的底层资源使用同一个接口进行访问。
    Spring 提供一个Resource接口来统一这些底层资源一致的访问,而且提供了一些便利的接口,从而能提供我们的生产力。
    4.1.2 Resource接口
    Spring的Resource接口代表底层外部资源,提供了对底层外部资源的一致性访问接口。

    Java代码

    public interface InputStreamSource { 
    InputStream getInputStream() throws IOException; 
    } 

    Java代码

    public interface Resource extends InputStreamSource { 
    boolean exists(); 
    boolean isReadable(); 
    boolean isOpen(); 
    URL getURL() throws IOException; 
    URI getURI() throws IOException; 
    File getFile() throws IOException; 
    long contentLength() throws IOException; 
    long lastModified() throws IOException; 
    Resource createRelative(String relativePath) throws IOException; 
    String getFilename(); 
    String getDescription(); 
    }

    1)InputStreamSource接口解析:
    getInputStream:每次调用都将返回一个新鲜的资源对应的java.io. InputStream字节流,调用者在使用完毕后必须关闭该资源。
    2)Resource接口继承InputStreamSource接口,并提供一些便利方法:
    exists:返回当前Resource代表的底层资源是否存在,true表示存在。
    isReadable:返回当前Resource代表的底层资源是否可读,true表示可读。
    isOpen:返回当前Resource代表的底层资源是否已经打开,如果返回true,则只能被读取一次然后关闭以避免资源泄露;常见的Resource实现一般返回false。
    getURL:如果当前Resource代表的底层资源能由java.util.URL代表,则返回该URL,否则抛出IOException。
    getURI:如果当前Resource代表的底层资源能由java.util.URI代表,则返回该URI,否则抛出IOException。
    getFile:如果当前Resource代表的底层资源能由java.io.File代表,则返回该File,否则抛出IOException。
    contentLength:返回当前Resource代表的底层文件资源的长度,一般是值代表的文件资源的长度。
    lastModified:返回当前Resource代表的底层资源的最后修改时间。
    createRelative:用于创建相对于当前Resource代表的底层资源的资源,比如当前Resource代表文件资源“d:/test/”则createRelative(“test.txt”)将返回表文件资源“d:/test/test.txt”Resource资源。
    getFilename:返回当前Resource代表的底层文件资源的文件路径,比如File资源“file://d:/test.txt”将返回“d:/test.txt”,而URL资源http://www.javass.cn将返回“”,因为只返回文件路径。
    getDescription:返回当前Resource代表的底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)。

    Resource接口提供了足够的抽象,足够满足我们日常使用。而且提供了很多内置Resource实现:ByteArrayResource、InputStreamResource 、FileSystemResource 、UrlResource 、ClassPathResource、ServletContextResource、VfsResource等。
    4.2 内置Resource实现

    4.2.1 ByteArrayResource
    ByteArrayResource代表byte[]数组资源,对于“getInputStream”操作将返回一个ByteArrayInputStream。
    首先让我们看下使用ByteArrayResource如何处理byte数组资源:

    Java代码 收藏代码

    package cn.javass.spring.chapter4; 
    import java.io.IOException; 
    import java.io.InputStream; 
    import org.junit.Test; 
    import org.springframework.core.io.ByteArrayResource; 
    import org.springframework.core.io.Resource; 
    public class ResourceTest { 
    @Test 
    public void testByteArrayResource() { 
    Resource resource = new ByteArrayResource("Hello World!".getBytes()); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    } 
    } 

    是不是很简单,让我们看下“dumpStream”实现:

    Java代码

    private void dumpStream(Resource resource) { 
    InputStream is = null; 
    try { 
    //1.获取文件资源 
    is = resource.getInputStream(); 
    //2.读取资源 
    byte[] descBytes = new byte[is.available()]; 
    is.read(descBytes); 
    System.out.println(new String(descBytes)); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 
    finally { 
    try { 
    //3.关闭资源 
    is.close(); 
    } catch (IOException e) { 
    } 
    } 
    }

    让我们来仔细看一下代码,dumpStream方法很抽象定义了访问流的三部曲:打开资源、读取资源、关闭资源,所以dunpStrean可以再进行抽象从而能在自己项目中使用;byteArrayResourceTest测试方法,也定义了基本步骤:定义资源、验证资源存在、访问资源。

    ByteArrayResource可多次读取数组资源,即isOpen ()永远返回false。

    1.2.2 InputStreamResource
    InputStreamResource代表java.io.InputStream字节流,对于“getInputStream ”操作将直接返回该字节流,因此只能读取一次该字节流,即“isOpen”永远返回true。
    让我们看下测试代码吧:

    Java代码

    @Test 
    public void testInputStreamResource() { 
    ByteArrayInputStream bis = new ByteArrayInputStream("Hello World!".getBytes()); 
    Resource resource = new InputStreamResource(bis); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    Assert.assertEquals(true, resource.isOpen()); 
    } 

    测试代码几乎和ByteArrayResource测试完全一样,注意“isOpen”此处用于返回true。

    4.2.3 FileSystemResource
    FileSystemResource代表java.io.File资源,对于“getInputStream ”操作将返回底层文件的字节流,“isOpen”将永远返回false,从而表示可多次读取底层文件的字节流。
    让我们看下测试代码吧:

    Java代码

    @Test 
    public void testFileResource() { 
    File file = new File("d:/test.txt"); 
    Resource resource = new FileSystemResource(file); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    Assert.assertEquals(false, resource.isOpen()); 
    } 
    

    注意由于“isOpen”将永远返回false,所以可以多次调用dumpStream(resource)。

    4.2.4 ClassPathResource
    ClassPathResource代表classpath路径的资源,将使用ClassLoader进行加载资源。classpath 资源存在于类路径中的文件系统中或jar包里,且“isOpen”永远返回false,表示可多次读取资源。
    ClassPathResource加载资源替代了Class类和ClassLoader类的“getResource(String name)”和“getResourceAsStream(String name)”两个加载类路径资源方法,提供一致的访问方式。
    ClassPathResource提供了三个构造器:
    public ClassPathResource(String path):使用默认的ClassLoader加载“path”类路径资源;
    public ClassPathResource(String path, ClassLoader classLoader):使用指定的ClassLoader加载“path”类路径资源;
    比如当前类路径是“cn.javass.spring.chapter4.ResourceTest”,而需要加载的资源路径是“cn/javass/spring/chapter4/test1.properties”,则将加载的资源在“cn/javass/spring/chapter4/test1.properties”;
    public ClassPathResource(String path, Class

    @Test 
    public void testClasspathResourceByDefaultClassLoader() throws IOException { 
    Resource resource = new ClassPathResource("cn/javass/spring/chapter4/test1.properties"); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    System.out.println("path:" + resource.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource.isOpen()); 
    } 

    2)使用指定的ClassLoader进行加载资源,将加载指定的ClassLoader类路径上相对于根路径的资源:

    Java代码

    @Test 
    public void testClasspathResourceByClassLoader() throws IOException { 
    ClassLoader cl = this.getClass().getClassLoader(); 
    Resource resource = new ClassPathResource("cn/javass/spring/chapter4/test1.properties" , cl); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    System.out.println("path:" + resource.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource.isOpen()); 
    } 

    3)使用指定的类进行加载资源,将尝试加载相对于当前类的路径的资源:

    Java代码

    @Test 
    public void testClasspathResourceByClass() throws IOException { 
    Class clazz = this.getClass(); 
    Resource resource1 = new ClassPathResource("cn/javass/spring/chapter4/test1.properties" , clazz); 
    if(resource1.exists()) { 
    dumpStream(resource1); 
    } 
    System.out.println("path:" + resource1.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource1.isOpen()); 
    
    Resource resource2 = new ClassPathResource("test1.properties" , this.getClass()); 
    if(resource2.exists()) { 
    dumpStream(resource2); 
    } 
    System.out.println("path:" + resource2.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource2.isOpen()); 
    } 

    “resource1”将加载cn/javass/spring/chapter4/cn/javass/spring/chapter4/test1.properties资源;“resource2”将加载“cn/javass/spring/chapter4/test1.properties”;

    4)加载jar包里的资源,首先在当前类路径下找不到,最后才到Jar包里找,而且在第一个Jar包里找到的将被返回:

    Java代码

    @Test 
    public void classpathResourceTestFromJar() throws IOException { 
    Resource resource = new ClassPathResource("overview.html"); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    System.out.println("path:" + resource.getURL().getPath()); 
    Assert.assertEquals(false, resource.isOpen()); 
    } 

    如果当前类路径包含“overview.html”,在项目的“resources”目录下,将加载该资源,否则将加载Jar包里的“overview.html”,而且不能使用“resource.getFile()”,应该使用“resource.getURL()”,因为资源不存在于文件系统而是存在于jar包里,URL类似于“file:/C:/…/*.jar!/overview.html”。
    类路径一般都是相对路径,即相对于类路径或相对于当前类的路径,因此如果使用“/test1.properties”带前缀“/”的路径,将自动删除“/”得到“test1.properties”。

    4.2.5 UrlResource
    UrlResource代表URL资源,用于简化URL资源访问。“isOpen”永远返回false,表示可多次读取资源。
    UrlResource一般支持如下资源访问:
    http:通过标准的http协议访问web资源,如new UrlResource(“http://地址”);
    ftp:通过ftp协议访问资源,如new UrlResource(“ftp://地址”);
    file:通过file协议访问本地文件系统资源,如new UrlResource(“file:d:/test.txt”);
    具体使用方法在此就不演示了,可以参考cn.javass.spring.chapter4.ResourceTest中urlResourceTest测试方法。

    4.2.6 ServletContextResource
    ServletContextResource代表web应用资源,用于简化servlet容器的ServletContext接口的getResource操作和getResourceAsStream操作;在此就不具体演示了。

    4.2.7 VfsResource
    VfsResource代表Jboss 虚拟文件系统资源。

    Jboss VFS(Virtual File System)框架是一个文件系统资源访问的抽象层,它能一致的访问物理文件系统、jar资源、zip资源、war资源等,VFS能把这些资源一致的映射到一个目录上,访问它们就像访问物理文件资源一样,而其实这些资源不存在于物理文件系统。
    在示例之前需要准备一些jar包,在此我们使用的是Jboss VFS3版本,可以下载最新的Jboss AS 6x,拷贝lib目录下的“jboss-logging.jar”和“jboss-vfs.jar”两个jar包拷贝到我们项目的lib目录中并添加到“Java Build Path”中的“Libaries”中。
    让我们看下示例(cn.javass.spring.chapter4.ResourceTest):

    Java代码

    @Test 
    public void testVfsResourceForRealFileSystem() throws IOException { 
    //1.创建一个虚拟的文件目录 
    VirtualFile home = VFS.getChild("/home"); 
    //2.将虚拟目录映射到物理的目录 
    VFS.mount(home, new RealFileSystem(new File("d:"))); 
    //3.通过虚拟目录获取文件资源 
    VirtualFile testFile = home.getChild("test.txt"); 
    //4.通过一致的接口访问 
    Resource resource = new VfsResource(testFile); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    System.out.println("path:" + resource.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource.isOpen()); 
    } 
    @Test 
    public void testVfsResourceForJar() throws IOException { 
    //1.首先获取jar包路径 
    File realFile = new File("lib/org.springframework.beans-3.0.5.RELEASE.jar"); 
    //2.创建一个虚拟的文件目录 
    VirtualFile home = VFS.getChild("/home2"); 
    //3.将虚拟目录映射到物理的目录 
    VFS.mountZipExpanded(realFile, home, 
    TempFileProvider.create("tmp", Executors.newScheduledThreadPool(1))); 
    //4.通过虚拟目录获取文件资源 
    VirtualFile testFile = home.getChild("META-INF/spring.handlers"); 
    Resource resource = new VfsResource(testFile); 
    if(resource.exists()) { 
    dumpStream(resource); 
    } 
    System.out.println("path:" + resource.getFile().getAbsolutePath()); 
    Assert.assertEquals(false, resource.isOpen()); 
    } 

    通过VFS,对于jar里的资源和物理文件系统访问都具有一致性,此处只是简单示例,如果需要请到Jboss官网深入学习。
    4.3.1 ResourceLoader接口
    ResourceLoader接口用于返回Resource对象;其实现可以看作是一个生产Resource的工厂类。

    Java代码

    public interface ResourceLoader { 
    Resource getResource(String location); 
    ClassLoader getClassLoader(); 
    } 

    getResource接口用于根据提供的location参数返回相应的Resource对象;而getClassLoader则返回加载这些Resource的ClassLoader。

    Spring提供了一个适用于所有环境的DefaultResourceLoader实现,可以返回ClassPathResource、UrlResource;还提供一个用于web环境的ServletContextResourceLoader,它继承了DefaultResourceLoader的所有功能,又额外提供了获取ServletContextResource的支持。

    ResourceLoader在进行加载资源时需要使用前缀来指定需要加载:“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource资源,如果不加前缀则需要根据当前上下文来决定,DefaultResourceLoader默认实现可以加载classpath资源,如代码所示(cn.javass.spring.chapter4.ResourceLoaderTest):

    Java代码

    @Test 
    public void testResourceLoad() { 
    ResourceLoader loader = new DefaultResourceLoader(); 
    Resource resource = loader.getResource("classpath:cn/javass/spring/chapter4/test1.txt"); 
    //验证返回的是ClassPathResource 
    Assert.assertEquals(ClassPathResource.class, resource.getClass()); 
    Resource resource2 = loader.getResource("file:cn/javass/spring/chapter4/test1.txt"); 
    //验证返回的是ClassPathResource 
    Assert.assertEquals(UrlResource.class, resource2.getClass()); 
    Resource resource3 = loader.getResource("cn/javass/spring/chapter4/test1.txt"); 
    //验证返默认可以加载ClasspathResource 
    Assert.assertTrue(resource3 instanceof ClassPathResource); 
    } 

    对于目前所有ApplicationContext都实现了ResourceLoader,因此可以使用其来加载资源。
    ClassPathXmlApplicationContext:不指定前缀将返回默认的ClassPathResource资源,否则将根据前缀来加载资源;
    FileSystemXmlApplicationContext:不指定前缀将返回FileSystemResource,否则将根据前缀来加载资源;
    WebApplicationContext:不指定前缀将返回ServletContextResource,否则将根据前缀来加载资源;
    其他:不指定前缀根据当前上下文返回Resource实现,否则将根据前缀来加载资源。

    4.3.2 ResourceLoaderAware接口
    ResourceLoaderAware是一个标记接口,用于通过ApplicationContext上下文注入ResourceLoader。

    Java代码

    public interface ResourceLoaderAware { 
    void setResourceLoader(ResourceLoader resourceLoader); 
    } 

    让我们看下测试代码吧:

    1) 首先准备测试Bean,我们的测试Bean还简单只需实现ResourceLoaderAware接口,然后通过回调将ResourceLoader保存下来就可以了:

    Java代码

    package cn.javass.spring.chapter4.bean; 
    import org.springframework.context.ResourceLoaderAware; 
    import org.springframework.core.io.ResourceLoader; 
    public class ResourceBean implements ResourceLoaderAware { 
    private ResourceLoader resourceLoader; 
    @Override 
    public void setResourceLoader(ResourceLoader resourceLoader) { 
    this.resourceLoader = resourceLoader; 
    } 
    public ResourceLoader getResourceLoader() { 
    return resourceLoader; 
    } 
    } 
    

    2) 配置Bean定义(chapter4/resourceLoaderAware.xml):

    Java代码

    <bean class="cn.javass.spring.chapter4.bean.ResourceBean"/> 

    3)测试(cn.javass.spring.chapter4.ResoureLoaderAwareTest):

    Java代码

    @Test 
    public void test() { 
    ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter4/resourceLoaderAware.xml"); 
    ResourceBean resourceBean = ctx.getBean(ResourceBean.class); 
    ResourceLoader loader = resourceBean.getResourceLoader(); 
    Assert.assertTrue(loader instanceof ApplicationContext); 
    } 

    注意此处“loader instanceof ApplicationContext”,说明了ApplicationContext就是个ResoureLoader。
    由于上述实现回调接口注入ResourceLoader的方式属于侵入式,所以不推荐上述方法,可以采用更好的自动注入方式,如“byType”和“constructor”,此处就不演示了。

    4.3.3 注入Resource
    通过回调或注入方式注入“ResourceLoader”,然后再通过“ResourceLoader”再来加载需要的资源对于只需要加载某个固定的资源是不是很麻烦,有没有更好的方法类似于前边实例中注入“java.io.File”类似方式呢?

    Spring提供了一个PropertyEditor “ResourceEditor”用于在注入的字符串和Resource之间进行转换。因此可以使用注入方式注入Resource。

    ResourceEditor完全使用ApplicationContext根据注入的路径字符串获取相应的Resource,说白了还是自己做还是容器帮你做的问题。

    接下让我们看下示例:
    1)准备Bean:

    Java代码

    package cn.javass.spring.chapter4.bean; 
    import org.springframework.core.io.Resource; 
    public class ResourceBean3 { 
    private Resource resource; 
    public Resource getResource() { 
    return resource; 
    } 
    public void setResource(Resource resource) { 
    this.resource = resource; 
    } 
    } 

    2)准备配置文件(chapter4/ resourceInject.xml):

    Java代码

    <bean id="resourceBean1" class="cn.javass.spring.chapter4.bean.ResourceBean3"> 
    <property name="resource" value="cn/javass/spring/chapter4/test1.properties"/> 
    </bean> 
    <bean id="resourceBean2" class="cn.javass.spring.chapter4.bean.ResourceBean3"> 
    <property name="resource" 
    value="classpath:cn/javass/spring/chapter4/test1.properties"/> 
    </bean> 
    

    注意此处“resourceBean1”注入的路径没有前缀表示根据使用的ApplicationContext实现进行选择Resource实现。

    3)让我们来看下测试代码(cn.javass.spring.chapter4.ResourceInjectTest)吧:

    Java代码

    @Test 
    public void test() { 
    ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter4/resourceInject.xml"); 
    ResourceBean3 resourceBean1 = ctx.getBean("resourceBean1", ResourceBean3.class); 
    ResourceBean3 resourceBean2 = ctx.getBean("resourceBean2", ResourceBean3.class); 
    Assert.assertTrue(resourceBean1.getResource() instanceof ClassPathResource); 
    Assert.assertTrue(resourceBean2.getResource() instanceof ClassPathResource); 
    } 

    接下来一节让我们深入ApplicationContext对各种Resource的支持,及如何使用更便利的资源加载方式。
    4.4.1 使用路径通配符加载Resource
    前面介绍的资源路径都是非常简单的一个路径匹配一个资源,Spring还提供了一种更强大的Ant模式通配符匹配,从能一个路径匹配一批资源。

    Ant路径通配符支持“?”、“”、“*”,注意通配符匹配不包括目录分隔符“/”:

    “?”:匹配一个字符,如“config?.xml”将匹配“config1.xml”;
    ”:匹配零个或多个字符串,如“cn//config.xml”将匹配“cn/javass/config.xml”,但不匹配匹配“cn/config.xml”;而“cn/config-*.xml”将匹配“cn/config-dao.xml”;
    ”:匹配路径中的零个或多个目录,如“cn//config.xml”将匹配“cn /config.xml”,也匹配“cn/javass/spring/config.xml”;而“cn/javass/config-.xml”将匹配“cn/javass/config-dao.xml”,即把“”当做两个“*”处理。

    Spring提供AntPathMatcher来进行Ant风格的路径匹配。具体测试请参考cn.javass.spring.chapter4. AntPathMatcherTest。

    Spring在加载类路径资源时除了提供前缀“classpath:”的来支持加载一个Resource,还提供一个前缀“classpath*:”来支持加载所有匹配的类路径Resource。

    Spring提供ResourcePatternResolver接口来加载多个Resource,该接口继承了ResourceLoader并添加了“Resource[] getResources(String locationPattern)”用来加载多个Resource:

    public interface ResourcePatternResolver extends ResourceLoader {
    String CLASSPATH_ALL_URL_PREFIX = “classpath*:”;
    Resource[] getResources(String locationPattern) throws IOException;
    }

    Spring提供了一个ResourcePatternResolver实现PathMatchingResourcePatternResolver,它是基于模式匹配的,默认使用AntPathMatcher进行路径匹配,它除了支持ResourceLoader支持的前缀外,还额外支持“classpath*:”用于加载所有匹配的类路径Resource,ResourceLoader不支持前缀“classpath*:”:

    首先做下准备工作,在项目的“resources”创建“META-INF”目录,然后在其下创建一个“INDEX.LIST”文件。同时在“org.springframework.beans-3.0.5.RELEASE.jar”和“org.springframework.context-3.0.5.RELEASE.jar”两个jar包里也存在相同目录和文件。然后创建一个“LICENSE”文件,该文件存在于“com.springsource.cn.sf.cglib-2.2.0.jar”里。

    一、“classpath”: 用于加载类路径(包括jar包)中的一个且仅一个资源;对于多个匹配的也只返回一个,所以如果需要多个匹配的请考虑“classpath*:”前缀;

    @Test 
    public void testClasspathPrefix() throws IOException { 
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 
    //只加载一个绝对匹配Resource,且通过ResourceLoader.getResource进行加载 
    Resource[] resources=resolver.getResources("classpath:META-INF/INDEX.LIST"); 
    Assert.assertEquals(1, resources.length); 
    //只加载一个匹配的Resource,且通过ResourceLoader.getResource进行加载 
    resources = resolver.getResources("classpath:META-INF/*.LIST"); 
    Assert.assertTrue(resources.length == 1); 
    } 

    二、“classpath*”: 用于加载类路径(包括jar包)中的所有匹配的资源。带通配符的classpath使用“ClassLoader”的“Enumeration getResources(String name)”方法来查找通配符之前的资源,然后通过模式匹配来获取匹配的资源。如“classpath:META-INF/*.LIST”将首先加载通配符之前的目录“META-INF”,然后再遍历路径进行子路径匹配从而获取匹配的资源。

    @Test 
    public void testClasspathAsteriskPrefix () throws IOException { 
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 
    //将加载多个绝对匹配的所有Resource 
    //将首先通过ClassLoader.getResources("META-INF")加载非模式路径部分 
    //然后进行遍历模式匹配 
    Resource[] resources=resolver.getResources("classpath*:META-INF/INDEX.LIST"); 
    Assert.assertTrue(resources.length > 1); 
    //将加载多个模式匹配的Resource 
    resources = resolver.getResources("classpath*:META-INF/*.LIST"); 
    Assert.assertTrue(resources.length > 1); 
    } 

    注意“resources.length >1”说明返回多个Resource。不管模式匹配还是非模式匹配只要匹配的都将返回。

    在“com.springsource.cn.sf.cglib-2.2.0.jar”里包含“asm-license.txt”文件,对于使用“classpath*: asm-*.txt”进行通配符方式加载资源将什么也加载不了“asm-license.txt”文件,注意一定是模式路径匹配才会遇到这种问题。这是由于“ClassLoader”的“getResources(String name)”方法的限制,对于name为“”的情况将只返回文件系统的类路径,不会包换jar包根路径。

    @Test 
    public void testClasspathAsteriskPrefixLimit() throws IOException { 
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //将首先通过ClassLoader.getResources("")加载目录, 
    //将只返回文件系统的类路径不返回jar的跟路径 
    //然后进行遍历模式匹配 
    Resource[] resources = resolver.getResources("classpath*:asm-*.txt"); 
    Assert.assertTrue(resources.length == 0); 
    //将通过ClassLoader.getResources("asm-license.txt")加载 
    //asm-license.txt存在于com.springsource.net.sf.cglib-2.2.0.jar 
    resources = resolver.getResources("classpath*:asm-license.txt"); 
    Assert.assertTrue(resources.length > 0); 
    //将只加载文件系统类路径匹配的Resource 
    resources = resolver.getResources("classpath*:LICENS*"); 
    Assert.assertTrue(resources.length == 1); 
    }

    对于“resolver.getResources(“classpath*:asm-.txt”);”,由于在项目“resources”目录下没有所以应该返回0个资源;“resolver.getResources(“classpath:asm-license.txt”);”将返回jar包里的Resource;“resolver.getResources(“classpath*:LICENS*”);”,因为将只返回文件系统类路径资源,所以返回1个资源。

    因此加载通配符路径时(即路径中包含通配符),必须包含一个根目录才能保证加载的资源是所有的,而不是部分。

    三、“file”:加载一个或多个文件系统中的Resource。如“file:D:/*.txt”将返回D盘下的所有txt文件;

    四、无前缀:通过ResourceLoader实现加载一个资源。

    AppliacationContext提供的getResources方法将获取资源委托给ResourcePatternResolver实现,默认使用PathMatchingResourcePatternResolver。所有在此就无需介绍其使用方法了。

    4.4.2 注入Resource数组
    Spring还支持注入Resource数组,直接看配置如下:

    <bean id="resourceBean1" class="cn.javass.spring.chapter4.bean.ResourceBean4"> 
    <property name="resources"> 
    <array> 
    <value>cn/javass/spring/chapter4/test1.properties</value> 
    <value>log4j.xml</value> 
    </array> 
    </property> 
    </bean> 
    <bean id="resourceBean2" class="cn.javass.spring.chapter4.bean.ResourceBean4"> 
    <property name="resources" value="classpath*:META-INF/INDEX.LIST"/> 
    </bean> 
    <bean id="resourceBean3" class="cn.javass.spring.chapter4.bean.ResourceBean4"> 
    <property name="resources"> 
    <array> 
    <value>cn/javass/spring/chapter4/test1.properties</value> 
    <value>classpath*:META-INF/INDEX.LIST</value> 
    </array> 
    </property> 
    </bean> 
    

    “resourceBean1”就不用多介绍了,传统实现方式;对于“resourceBean2”则使用前缀“classpath*”,看到这大家应该懂的,加载匹配多个资源;“resourceBean3”是混合使用的;测试代码在“cn.javass.spring.chapter4.ResourceInjectTest.testResourceArrayInject”。
    Spring通过ResourceArrayPropertyEditor来进行类型转换的,而它又默认使用“PathMatchingResourcePatternResolver”来进行把路径解析为Resource对象。所有大家只要会使用“PathMatchingResourcePatternResolver”,其它一些实现都是委托给它的,比如AppliacationContext的“getResources”方法等。

    4.4.3 AppliacationContext实现对各种Resource的支持
    一、ClassPathXmlApplicationContext:默认将通过classpath进行加载返回ClassPathResource,提供两类构造器方法:

    public class ClassPathXmlApplicationContext { 
    //1)通过ResourcePatternResolver实现根据configLocation获取资源 
    public ClassPathXmlApplicationContext(String configLocation); 
    public ClassPathXmlApplicationContext(String... configLocations); 
    public ClassPathXmlApplicationContext(String[] configLocations, ……); 
    
    //2)通过直接根据path直接返回ClasspathResource 
    public ClassPathXmlApplicationContext(String path, Class clazz); 
    public ClassPathXmlApplicationContext(String[] paths, Class clazz); 
    public ClassPathXmlApplicationContext(String[] paths, Class clazz, ……); 
    } 

    第一类构造器是根据提供的配置文件路径使用“ResourcePatternResolver ”的“getResources()”接口通过匹配获取资源;即如“classpath:config.xml”
    第二类构造器则是根据提供的路径和clazz来构造ClassResource资源。即采用“public ClassPathResource(String path, Class

    **public class FileSystemXmlApplicationContext{ 
    public FileSystemXmlApplicationContext(String configLocation); 
    public FileSystemXmlApplicationContext(String... configLocations,……); 
    } 
    
    **

    //linux系统,以下全是相对于当前vm路径进行加载
    new FileSystemXmlApplicationContext(“chapter4/config.xml”);
    new FileSystemXmlApplicationContext(“/chapter4/confg.xml”);

    //windows系统,第一个将相对于当前vm路径进行加载;
    //第二个则是绝对路径方式加载
    new FileSystemXmlApplicationContext(“chapter4/config.xml”);
    new FileSystemXmlApplicationContext(“d:/chapter4/confg.xml”);

    此处还需要注意:在linux系统上,构造器使用的是相对路径,而ctx.getResource()方法如果以“/”开头则表示获取绝对路径资源,而不带前导“/”将返回相对路径资源。如下:

    //linux系统,第一个将相对于当前vm路径进行加载;
    //第二个则是绝对路径方式加载
    ctx.getResource (“chapter4/config.xml”);
    ctx.getResource (“/root/confg.xml”);
    //windows系统,第一个将相对于当前vm路径进行加载;
    //第二个则是绝对路径方式加载
    ctx.getResource (“chapter4/config.xml”);
    ctx.getResource (“d:/chapter4/confg.xml”);

    因此如果需要加载绝对路径资源最好选择前缀“file”方式,将全部根据绝对路径加载。如在linux系统“ctx.getResource (“file:/root/confg.xml”);”

    展开全文
  • @Autowired 与@Resource的区别(详细)

    万次阅读 多人点赞 2018-06-10 19:44:00
    这个时候@AutoWire没有@Resource好用,因为@Resource可以根据名字来搜索,是这样写的@Resource("userService")。这个@Autowired @Qualifie("userService") 也可以用名字啊,为什么不用呢,原因很简单,这个有点长,...

    参考博文:

    http://www.cnblogs.com/happyyang/articles/3553687.html

    http://blog.csdn.net/revent/article/details/49203619

    http://blog.csdn.net/ad921012/article/details/49679745

    spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
      @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
      @Resource装配顺序
      1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
      2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
      3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
      4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

    @Autowired 与@Resource的区别:

     

    1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。

    2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

    1
    2
    @Autowired () @Qualifier ( "baseDao" )
    private BaseDao baseDao;

    3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    1
    2
    @Resource (name= "baseDao" )
    private BaseDao baseDao;

    推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

     

    spring @Qualifier注解

     

    @Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个UserDao类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在UserDao类型的bean,也会抛出BeanCreationException异常。我们可以使用@Qualifier配合@Autowired来解决这些问题。如下:

    ①可能存在多个UserDao实例

     

    [java]  view plain copy 在CODE上查看代码片 派生到我的代码片
     
     
    1. @Autowired   
    2. @Qualifier("userServiceImpl")   
    3. public IUserService userService;   

     

    或者

    [java]  view plain copy 在CODE上查看代码片 派生到我的代码片
     
     
    1. @Autowired   
    2. public void setUserDao(@Qualifier("userDao") UserDao userDao) {   
    3.     this.userDao = userDao;   
    4. }  

     

    这样Spring会找到id为userServiceImpl和userDao的bean进行装配。

     

    ②可能不存在UserDao实例

     

    [java]  view plain copy 在CODE上查看代码片 派生到我的代码片
     
     
    1. @Autowired(required = false)   
    2. public IUserService userService  

     

    个人总结:

    @Autowired//默认按type注入
    @Qualifier("cusInfoService")//一般作为@Autowired()的修饰用
    @Resource(name="cusInfoService")//默认按name注入,可以通过name和type属性进行选择性注入

     

    一般@Autowired和@Qualifier一起用,@Resource单独用。

    当然没有冲突的话@Autowired也可以单独用

     

     

    -----------常用注解--------

     

    --定义Bean的注解

     

    @Controller

    @Controller("Bean的名称")

    定义控制层Bean,如Action

     

    @Service          

    @Service("Bean的名称")

    定义业务层Bean

     

    @Repository   

    @Repository("Bean的名称")

    定义DAO层Bean

     

    @Component  

    定义Bean, 不好归类时使用.

     

    --自动装配Bean (选用一种注解就可以)

    @Autowired  (Srping提供的)

    默认按类型匹配,自动装配(Srping提供的),可以写在成员属性上,或写在setter方法上

     

    @Autowired(required=true)  

    一定要找到匹配的Bean,否则抛异常。 默认值就是true 

     

    @Autowired

    @Qualifier("bean的名字") 

    按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。

     

    @Resource   JSR-250提供的

    默认按名称装配,当找不到名称匹配的bean再按类型装配.

    可以写在成员属性上,或写在setter方法上

    可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.

    @Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.

     

    @Inject   是JSR-330提供的

    按类型装配,功能比@Autowired少,没有使用的必要。

     

    --定义Bean的作用域和生命过程

    @Scope("prototype")

    值有:singleton,prototype,session,request,session,globalSession

     

    @PostConstruct 

    相当于init-method,使用在方法上,当Bean初始化时执行。

     

    @PreDestroy 

    相当于destory-method,使用在方法上,当Bean销毁时执行。

     

    --声明式事务

    @Transactional  

    @Autowired @Resource @Qualifier的区别

    实用理解:@Autowired @Resource 二选其一,看中哪个就用哪个。

     

    简单理解:

    @Autowired 根据类型注入, 

    @Resource 默认根据名字注入,其次按照类型搜索

    @Autowired @Qualifie("userService") 两个结合起来可以根据名字和类型注入

     

    复杂理解:

    比如你有这么一个Bean

    @Service(“UserService”)

    public Class UserServiceImpl implements UserService{};

    现在你想在UserController 里面使用这个UserServiceImpl 

    public Class UserController {

    @AutoWire   //当使用这个注入的时候上面的 UserServiceImpl 只需要这样写 @Service,这样就会自动找到UserService这个类型以及他的子类型。UserServiceImpl 实现了UserService,所以能够找到它。不过这样有一个缺点,就是当UserService实现类有两个以上的时候,这个时候会找哪一个呢,这就造成了冲突,所以要用@AutoWire注入的时候要确保UserService只有一个实现类。

    @Resource 默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,有人可能会想了,这下好了,用这个是万能的了,不用管名字了,也不用管类型了,但这里还是有缺点。首先,根据这个注解的匹配效果可以看出,它进行了两次匹配,也就是说,如果你在UserService这个类上面这样写注解,@Service,它会怎么找呢,首先是找相同名字的,如果没有找到,再找相同类型的,而这里的@Service没有写名字,这个时候就进行了两次搜索,显然,速度就下降了许多。也许你还会问,这里的@Service本来就没有名字,肯定是直接进行类型搜索啊。其实不是这样的,UserServiceImpl 上面如果有@Service默认的名字 是这个userServiceImpl,注意看,就是把类名前面的大写变成小写,就是默认的Bean的名字了。 @Resource根据名字搜索是这样写@Resource("userService"),如果你写了这个名字叫userService,那么UserServiceImpl上面必须也是这个名字,不然还是会报错。

     

    @Autowired @Qualifie("userService") 是直接按照名字进行搜索,也就是说,对于UserServiceImpl 上面@Service注解必须写名字,不写就会报错,而且名字必须是@Autowired @Qualifie("userService") 保持一致。如果@Service上面写了名字,而@Autowired @Qualifie() ,一样会报错。


    private UserService userService;

     

    说了这么多,可能你有些说晕了,那么怎么用这三个呢,要实际的工作是根据实际情况来使用的,通常使用AutoWire和@Resource多一些,bean的名字不用写,而UserServiceImpl上面能会这样写 @Service("userService")。这里的实际工作情况,到底是什么情况呢?说白了就是整个项目设计时候考虑的情况,如果你的架构设计师考虑的比较精细,要求比较严格,要求项目上线后的访问速度比较好,通常是考虑速度了。这个时候@AutoWire没有@Resource好用,因为@Resource可以根据名字来搜索,是这样写的@Resource("userService")。这个@Autowired @Qualifie("userService") 也可以用名字啊,为什么不用呢,原因很简单,这个有点长,不喜欢,增加工作量。因为根据名字搜索是最快的,就好像查数据库一样,根据Id查找最快。因为这里的名字与数据库里面的ID是一样的作用。这个时候,就要求你多写几个名字,工作量自然就增加了。而如果你不用注解,用xml文件的时候,对于注入Bean的时候要求写一个Id,xml文件时候的id就相当于这里的名字。

     

    说了那么多没用,你能做的就是简单直接,什么最方便就用什么,

    你就直接用@Resource得了,如果你喜欢用@AutoWire也行,不用写名字。

     

    通常情况一个Bean的注解写错了,会报下面这些错误,最为常见,

    No bean named 'user' is defined,这个表示没有找到被命名为user的Bean,通俗的说,就是名字为user的类型,以及它的子类型,出现这个错误的原因就是注入时候的类型名字为user,而搜索的时候找不到,也就是说可能那个搜索的类型,并没有命令为user,解决办法就是找到这个类型,去命令为user,

     

    下面这个错误也常见,

    No qualifying bean of type [com.service.UserService] found for dependency:

    这个错误的原因就是类型上面没有加@Service这个注入,不仅仅是@Service,如果是其他层也会出现这个错误,这里我是以Service为例子说明,如果是DAO层就是没有加@Repository,Controller层,则是没有加@Controller。

    还有,如果你还是想再简单点,无论是DAO,Controller,Service三个层,都可以用这个注解,@Component,这个注解通用所有的Bean,这个时候你可能会说了,有通常的为什么用的人少呢,那是因为MVC这个分层的设计原则,用@Repository,@Service,@Controller,这个可以区别MVC原则中的DAO,Service,Controller。便于识别。

     

     

    博客2:

     在使用Spring框架中@Autowired标签时默认情况下使用
    Java代码 
    1. @Autowired  
     @Autowired
    注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。

    @Autowired 默认是按照byType进行注入的,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常。

    例子:

    @Autowired
    private ExamUserMapper examUserMapper;  - ExamUserMapper是一个接口

     

    1. spring先找类型为ExamUserMapper的bean

    2. 如果存在且唯一,则OK;

    3. 如果不唯一,在结果集里,寻找name为examUserMapper的bean。因为bean的name有唯一性,所以,到这里应该能确定是否存在满足要求的bean了

     

    @Autowired也可以手动指定按照byName方式注入,使用@Qualifier标签,例如:
    @Autowired  ()  @Qualifier  (  "baseDao"  )


      Spring 允许我们通过
    Java代码 
    1. @Qualifier  
    @Qualifier
    注释指定注入 Bean 的名称,这样歧义就消除了,可以通过下面的方法解决异常。 

      
    Java代码 
    1. @Qualifier("XXX")  
    @Qualifier("XXX")
    中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。 

      @Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。 

        Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。 

      
    Java代码 
    1. @Resource  
    @Resource
    的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。 

      @Resource装配顺序 
      1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 
      2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常 
      3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 
      4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配
    展开全文
  • javax.naming.NamingException: Cannot create resource instance类加载异常,希望可以帮助跟我一样错误的人。
  • 关于资源,在linux中有如下定义  /* * IO resources have these defined flags. */ #define IORESOURCE_BITS 0x000000ff /* Bus-...#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ #define I...
  • 只不过Class.getResource是先调用Class 的 getResource 方法,在这个getResource 方法中,再去调用ClassLoader 类的getResource方法 那么Class类中的getResource方法做了什么呢,主要的一句是 name = resolve...
  • resource failed to call close

    千次阅读 2021-05-26 11:27:30
    在运行Android项目时,日志中会出现A resource failed to call close告警信息: 2021-05-26 11:26:52.564 11386-11401/com.xxx.example W/System: A resource failed to call close. 这是由于文件输入和输出流在...
  • 程序员升职记 Human Resource Machine 1 – HUMAN RESOURCE MACHINE PROGRAM – INBOX OUTBOX INBOX OUTBOX INBOX OUTBOX 2 – HUMAN RESOURCE MACHINE PROGRAM – a: INBOX OUTBOX JUMP a 3 – HUMAN RESOURCE ...
  • Oracle 资源管理(resource manager) 假如管理一下具有如下问题的产品数据库: 后台批作业占用了大量的资源,将会阻碍了其他要同时运行的更重要的作业。 如要调度大型作业,但不能预计它们何时才能完成。 作业的...
  • @Autowired 和 @Resource 这两个注解大家想必都有在项目里面出现过,但是真的清楚这俩玩意的用法或者说是区别么? 一直用的都是@Autowired ? 别人代码用什么就copy用什么,反正他没错,俺也不会错? 它们都是...
  • C:\CodeForAndroid\XTCWatch\XTCWatch\XTCWatch\basiclib\build\intermediates\packaged_res\debug\drawable\progressbar_drawable_whitebg.xml:11: error: resource drawable/shape_progressbar_yellow ...
  • Java基础之try-with-resource语法糖

    万次阅读 多人点赞 2020-12-22 11:41:20
    } } } } 运行之后我们发现: basic.exception.MyException: close at basic.exception.Connection.close(Connection.java:10) at basic.exception.TryWithResource.test(TryWithResource.java:82) at basic....
  • Spring Resource接口进行资源访问

    千次阅读 2018-08-12 15:50:24
    } Resource接口其他的方法: ● exists:返回Resource所指向的底层资源是否存在 ● isReadable:返回当前Resource代表的底层资源是否可读 ● isOpen:返回Resource资源文件是否已经打开,如果返回true,则...
  • Android resource compilation failed

    千次阅读 2019-06-24 14:53:07
    错误: D:\android\EasySports\app\build\intermediates\incremental\mergeOfficialDebugResources\merged.dir\values\values.xml:490: error: <... inner element must either be a resource reference or e...
  • SpringBoot : 注解@Resource

    千次阅读 2020-01-08 23:08:15
    1.美图 2.概述 在项目开发中,@Autowired和@Resource之争,一直搞不清楚,反正也不想搞清楚到底什么时候用@Autowired,什么场景下用@Resource,就一直用@Autowired得了。 ...
  • OAuth 2.0是安全授权的工业标准协议,我们了解它需要理解下面的专用术语: 交互参与方: Client:需要访问Resource Sever受保护资源的应用; Resource Owner :终端用户...Resource Sever:包含受保护资源的应用,
  • Error: Rule can only have one resource source (provided resource and test + include + exclude) 问题:Error: Rule can only have one resource source (provided resource and test + include + exclude) ...
  • @Resource

    千次阅读 2019-08-04 11:07:09
    @Autowired 与@Resource的区别: 1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。 2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象...
  • java resource ClassPathResource

    千次阅读 2018-08-07 01:10:22
    spring 中定义了资源接口,部分类关系如下: 这个类包含加载的path 和类加载器classloader 还有class&lt;?&...public ClassPathResource(String path, ClassLoader classLoader) { As...
  • 出现的问题 ... Resource stopwords not found. Please use the NLTK Downloader to obtain the resource: 具体如下所示: Watching for file changes with StatReloader Performing system ch...
  • 在.exe中当前load的resource即为.exe中的resource,因此在使用FindResource,LoadResource时,参数hModule可以为NULL。具体使用如下:   [c-sharp]   view plain   copy // string 方式   HRSRC hr = ::...
  • 如果我们读取resources文件夹注意:直接使用`ClassPathResource classPathResource = new ClassPathResource("resourcetest.txt");`会提示文件找不到的错误。2.如果读取磁盘上的文件的话,方式就有很多种,直接使用...
  • @Resource与@Autowired用法区别

    万次阅读 多人点赞 2018-09-11 09:32:14
    spring中,@Resource和@Autowired都是做bean的注入时使用。使用过程中,有时候@Resource 和 @Autowired可以替换使用;有时,则不可以。  下面,根据自己的学习,整理下这两个注解使用中的共同点和不同点,及用法上...
  • device or resource busy问题处理

    千次阅读 2020-04-09 11:40:24
    DEVICE OR RESOURCE BUSY 1、umount -lf 挂载点 2、fuser -m 挂载磁盘,找到进程后杀死 3、lsof 挂载磁盘 4、dmsetup remove 挂载磁盘(尽量不要用dmsetup remove_all) 5、已经umount并且没有找到相应的进程 通过...
  • getResource和getResourceAsStream

    千次阅读 2019-06-30 00:10:14
    在java获取资源路径存在一定的差异,常用的有getResource和getResourceAsStream 1.Class.getResource(String path) path不以'/'开头时,默认是从此类所在的包下取资源; path以'/'开头时,则是从项目的...
  • 创建一个私有pod,里面分别resourceresource_bundles字段。 Pod::Spec.new do | s | s.name = "TestResource" s.version = "0.0.1" s.summary = "TestResource" s.homepage = ...
  • String path = this.getClass().getResource("/").getPath() + fileName; System.out.println(path);// D:/example/exam01/target/classes/config/zh.md 在IDE工具中开发及Debug时一切都正常,但是打

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,118,827
精华内容 447,530
关键字:

resource