Spring IoC实现

Spring对资源文件和资源的加载都做了统一的抽象,以下是资源文件的继承体系:

其中,顶层接口InputStreamSource只包含一个getInputStream()方法用于返回指定资源的InputStream;而Resource是对资源的一个抽象,里面提供了判断资源是否存在、资源是否可读、资源大小等常见接口,并且大部分接口由抽象子类AbstractResource提供了默认实现,而一些方法则由具体的子类如FileSystemResourceClassPathResource等覆写,以满足特定的场景需求。

接下来看看Spring对资源加载的统一抽象,同样从它的继承体系说起:

AbstractResource相似,DefaultResourceLoaderResourceLoader的默认实现。其中getResource()方法是其核心(两个子类都没覆盖该方法),它根据方法参数location的内容来决定到底是返回ClassPathResource还是FileSystemResource还是Resource其它的一些子类。由于在默认的实现策略中,凡是以/开头的都会返回ClassPathContextResource类型的资源,但对于/user/hecenjie/test.xml这样的路径我们更加希望是FileSystemResource类型的资源,因此在子类FileSystemResourceLoader中覆写了相关方法,使之可以从文件系统中获取资源;而另一个子类ClassRelativeResourceLoader则扩展了功能,可以根据给定的Class所在包或者所在包的子包下加载资源。

ResourceLoader的另一个重要实现是ResourcePatternResolver,与上面的ResourceLoader实现类不同的是,它支持根据指定的资源路径匹配模式每次返回多个Resource实例(也就是Resource数组),并且它也新增了一种新的协议前缀classpath*:,该前缀表示可以加载多个jar包中相同的资源文件,而classpath:只能加载找到的第一个文件。

PathMatchingResourcePatternResolver除了支持ResourceLoaderResourcePatternResolver新增的classpath*:前缀外,还支持Ant风格的路径匹配模式(类似于**/*.xml)。

Simple IoC实现

目前自己实现的IoC容器中,只实现了文件系统的资源与加载抽象,以下为它们各自的类图:

快速使用

我们可以尝试写一些简单的单元测试从文件系统中加载指定的资源,并对该资源做一些基本操作。首先,准备一个test.xml文件,然后编写以下测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testFileSystemResource() throws IOException {
Resource resource = new FileSystemResource("C:\\Users\\canjie\\Desktop\\test.xml");
assertTrue(resource.exists());
assertEquals(resource.contentLength(), 992);
}

@Test
public void testFileSystemResourceLoader() throws IOException {
ResourceLoader resourceLoader = new FileSystemResourceLoader();
Resource resource = resourceLoader.getResource("C:\\Users\\canjie\\Desktop\\test.xml");
assertTrue(resource.exists());
assertEquals(resource.contentLength(), 992);
}