一.理论


 

在spring中经常有读取配置文件的需求,这里就会用到一个Spring提供的Resource接口

Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。Resource 接口主要提供了如下几个方法:

  • getInputStream():定位并打开资源,返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。
  • exists():返回 Resource 所指向的资源是否存在。
  • isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束应该显式关闭,以防止资源泄漏。
  • getDescription():返回资源的描述信息,通常用于资源处理出错时输出该信息,通常是全限定文件名或实际 URL。
  • getFile:返回资源对应的 File 对象。
  • getURL:返回资源对应的 URL 对象。

Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。

Resource 和策略模式 Resource 接口就是策略模式的典型应用,Resource 接口就代表资源访问策略,但具体采用哪种策略实现,Resource 接口并不理会。客户端程序只和 Resource 接口耦合,并不知道底层采用何种资源访问策略,这样应用可以在不同的资源访问策略之间自由切换。

Spring 为 Resource 接口提供了如下实现类:

  • UrlResource:访问网络资源的实现类。
  • ClassPathResource:访问类加载路径里资源的实现类。
  • FileSystemResource:访问文件系统里资源的实现类。
  • ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:
  • InputStreamResource:访问输入流资源的实现类。
  • ByteArrayResource:访问字节数组资源的实现类。

这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。

 

spring 策略 模板 spring哪里用到策略模式_spring 策略 模板

 

二.源码


 

这里跟踪ClassPathXmlApplicationContext对象的创建,来了解Spring底层怎么使用Resource接口及其实现类达成策略模式

策略模式的优势 当 Spring 应用需要进行资源访问时,实际上并不需要直接使用 Resource 实现类,而是调用 ApplicationContext 实例的 getResource()方法来获得资源,ApplicationContext 将会负责选择 Resource 的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来,这就体现了策略模式的优势。



1 //1.根据传入的配置文件地址,创建容器对象  ClassPathXmlApplicationContext
2 public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
3     this(new String[] {configLocation}, true, null);
4 }


1 //2.1中代码调用到此处,此处调用父类构造函数  ClassPathXmlApplicationContext
 2 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
 3             throws BeansException {
 4 
 5     super(parent);
 6     setConfigLocations(configLocations);
 7     if (refresh) {
 8         refresh();
 9     }
10 }

1 //3.2中代码一步步调用到此处  AbstractApplicationContext
2 public AbstractApplicationContext(ApplicationContext parent) {
3     this();
4     setParent(parent);
5 }

1 //4.3中代码调用此处  AbstractApplicationContext
2 public AbstractApplicationContext() {
3     this.resourcePatternResolver = getResourcePatternResolver();
4 }

1 //5.返回能将1中传入的configLocation转换成Resource对象的ResourcePatternResolver  AbstractApplicationContext
2 protected ResourcePatternResolver getResourcePatternResolver() {
3     return new PathMatchingResourcePatternResolver(this);
4 }

1 //6.真正用到策略模式的地方,根据location的内容,决定返回对应的Resource实现,这个过程对客户来说是透明的  DefaultResourceLoader
 2 @Override
 3 public Resource getResource(String location) {
 4     Assert.notNull(location, "Location must not be null");
 5 
 6     for (ProtocolResolver protocolResolver : this.protocolResolvers) {
 7         Resource resource = protocolResolver.resolve(location, this);
 8         if (resource != null) {
 9             return resource;
10         }
11     }
12 
13     if (location.startsWith("/")) {
14         return getResourceByPath(location);
15     }
16     else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
17         return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
18     }
19     else {
20         try {
21             // Try to parse the location as a URL...
22             URL url = new URL(location);
23             return new UrlResource(url);
24         }
25         catch (MalformedURLException ex) {
26             // No URL -> resolve as resource path.
27             return getResourceByPath(location);
28         }
29     }
30 }


 

参考:https://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/