Spring Resource加载资源 本是古典 何须时尚 2022-07-24 10:15 156阅读 0赞 ## 1. Resource简介 ## 在Spring内部,针对于资源文件有一个统一的接口Resource表示。 其主要实现类有ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、ServletContextResource和InputStreamResource。 Resource接口中主要定义有以下方法: * exists():用于判断对应的资源是否真的存在。 * isReadable():用于判断对应资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读。 * isOpen():用于判断当前资源是否代表一个已打开的输入流,如果结果为true,则表示当前资源的输入流不可多次读取,而且在读取以后需要对它进行关闭,以防止内存泄露。该方法主要针对于InputStreamResource,实现类中只有它的返回结果为true,其他都为false。 * getURL():返回当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常。如ByteArrayResource就不能解析为一个URL。 * getFile():返回当前资源对应的File。如果当前资源不能以绝对路径解析为一个File则会抛出异常。如ByteArrayResource就不能解析为一个File。 * getInputStream():获取当前资源代表的输入流。除了InputStreamResource以外,其它Resource实现类每次调用getInputStream()方法都将返回一个全新的InputStream。 ### Resource接口的实现类 ### * ClassPathResource:通过 ClassPathResource 以类路径的方式进行访问; * FileSystemResource:通过 FileSystemResource 以文件系统绝对路径的方式进行访问。FileSystemResource还可以往对应的资源文件里面写内容,当然前提是当前资源文件是可写的,这可以通过其isWritable()方法来判断。FileSystemResource对外开放了对应资源文件的输出流,可以通过getOutputStream()方法获取到。 * ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。 * ServletContextResource是针对于ServletContext封装的资源,用于访问ServletContext环境下的资源。 ServletContextResource持有一个ServletContext的引用,通过 ServletContextResource 以相对于Web应用根目录的方式进行访问。其底层是通过ServletContext的getResource()方法和getResourceAsStream()方法来获取资源的。 * UrlResource可用来代表URL对应的资源,它对URL做了一个简单的封装。通过给定一个URL地址,我们就能构建一个UrlResource。其底层是通过java.net.URL来访问资源,当然它也支持File格式,如“file:”。 * ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。 * InputStreamResource是针对于输入流封装的资源,它的构建需要一个输入流。 最常用的有四个: * ClassPathResource * FileSystemResource * ServletContextResource * UrlResource ## 2. 通过ResourceLoader获取资源 ## ResourceLoader 接口是用来加载 Resource 对象的。它通过一个精确路径的地址信息进行加载Resource,也可以通过Ant风格的地址描述加载匹配的Resource。 ### Ant路径通配符加载Resource ### Ant路径通配符支持`?,*,**`。 注意通配符匹配不包括目录分隔符“/”。 <table> <thead> <tr> <th>通配符</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td>?</td> <td>匹配任何单字符</td> </tr> <tr> <td>*</td> <td>匹配0或者任意数量的字符</td> </tr> <tr> <td>**</td> <td>匹配0或者更多的目录</td> </tr> </tbody> </table> 匹配样例 <table> <thead> <tr> <th>URL路径</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td>/app/*.x</td> <td>匹配(Matches)所有在app路径下的.x文件</td> </tr> <tr> <td>/app/p?ttern</td> <td>匹配(Matches) /app/pattern 和 /app/pXttern,但是不包括/app/pttern</td> </tr> <tr> <td>/**/example</td> <td>匹配(Matches) /app/example, /app/foo/example, 和 /example</td> </tr> <tr> <td>/app/**/dir/file.</td> <td>匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java</td> </tr> <tr> <td>/<em>*/</em>.jsp</td> <td>匹配(Matches)任何的.jsp 文件</td> </tr> </tbody> </table> 属性: 最长匹配原则(has more characters) 说明,URL请求`/app/dir/file.jsp`,现在存在两个路径匹配模式`/**/*.jsp`和`/app/dir/*.jsp`,那么会根据模式`/app/dir/*.jsp`来匹配 ### 精确路径加载Resource ### 为了更加精确表示Resource类型,可以加入对应的前缀标识来说明。 如路径:`com/baobaotao/beanfactory/bean.xml` <table> <thead> <tr> <th>地址前缀</th> <th>示例</th> <th>对应资源类型</th> </tr> </thead> <tbody> <tr> <td>classpath:</td> <td>classpath:com/baobaotao/beanfactory/bean.xml</td> <td>从类路径中加载资源,资源文件可以在标准的文件系统中,也可以在jar或者zip的类包中</td> </tr> <tr> <td>file:</td> <td>file:/conf/com/baobaotao/beanfactory/bean.xml</td> <td>使用URLResource从文件系统目录中装载资源,可采用绝对或相对路径。</td> </tr> <tr> <td>file:</td> <td>file:/conf/com/baobaotao/beanfactory/bean.xml</td> <td>使用URLResource从文件系统目录中装载资源,可采用绝对或相对路径。</td> </tr> <tr> <td>http://</td> <td><a href="http://www.baobaotao/resource/bean.xml" rel="nofollow">http://www.baobaotao/resource/bean.xml</a></td> <td></td> </tr> <tr> <td>ftp:</td> <td><a href="ftp://www.baobaotao.com/resource/bean.xml" rel="nofollow">ftp://www.baobaotao.com/resource/bean.xml</a></td> <td>使用UrlResource从FTP服务器中装载资源</td> </tr> <tr> <td>com/baobaotao/beanfatory/beans.xml</td> <td>根据ApplicationContext具体实现类采用对应的类型的Resource</td> <td></td> </tr> </tbody> </table> #### classpath与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\*:”前缀; 对于匹配多个资源的情况下,会优先返回相对于本工程中下面的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); } ### 结论 ### 在声明资源地址路径的时候,可以混合使用Ant路径通配符和前缀标识。 如: `classpath:com/**/test.xml` : 匹配com路径下(当前目录及其子孙目录)的test.xml文件;
还没有评论,来说两句吧...