在jdk的api中,资源访问基本上都是通过URL类和IO来完成的,首先我们来介绍一下jdk中的资源访问
在j2se中,我们一般通过ClassLoader的getResource()方法来定位查找资源:
public static void main(String[] args) throws IOException, URISyntaxException { URL url = Thread.currentThread().getContextClassLoader().getResource("format.properties"); Properties p = new Properties(); p.load(url.openStream()); System.out.println(p.get("chengan")); System.out.println(url.getProtocol()); }
ClassLoader的getResource()方法访问资源有一个限制,资源的位置只能在classpath路径下或者classpath的子路径下,如果format.properties文件的路径不在classpath路径下,getResource()方法是找不到文件的,比如我们再开发web项目的时候,jdbc.properties一般都会放到WEB-INF下新建一个文件保存,此时在使用ClassLoader获取,就获取不到,下面我们就需要使用servletContext提供的方法,getResource()方法参数可以使用"/"作为路径,比如format.properties位于classpath路径下的test包下(getResource()方法参数的起始路径为classpath):
URL url = Thread.currentThread().getContextClassLoader().getResource("test/format.properties");
在j2ee中,可以使用ServletContext提供的方法getResource()来访问资源:
response.setContentType("text/html"); URL url = request.getSession().getServletContext().getResource("/WEB-INF/config/jdbc.properties"); response.getWriter().print(url);
jdbc.properties文件放在WEB-INF的config文件下,servletContext的getResource方法以WebRoot为起始路径,上面代码运行的结果为:
jndi:/localhost/SpringDemo/WEB-INF/config/jdbc.properties
spring的资源访问提供了统一的接口:Resource
spring在设计上使用了策略模式,针对不同的资源访问,提供了不同的实现类,常用的实现类有:
UrlResource:对java.net.URL访问的封装
ServletContextResource:对servletContext访问资源的封装
FileSystemResource:访问文件系统资源的封装
InputStreamResource:流操作资源访问
ContextResource:该接口是对访问容器资源的接口,提供一系列实现该接口的类
在spring中,访问资源的入口在applicationContext中,applicationContext继承了ResourcePatternResolver接口
public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; Resource[] getResources(String locationPattern) throws IOException; }
ResourcePatternResolver又继承了ResourceLoader接口:
public interface ResourceLoader { /** Pseudo URL prefix for loading from the class path: "classpath:" */ String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; Resource getResource(String location); ClassLoader getClassLoader(); }
在访问资源时,可以指定访问资源的方式:
public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); //常量CLASSPATH_URL_PREFIX值为:classpath: 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); } } }
上面是ResourceLoader的方法getResource()的默认实现,由上述代码可知,在指定资源的位置时,如果前缀指定为“classpath:",那么会使用ClassPathResource,否则默认使用UrlResource,如果出错会使用ClassPathResource