读Spring源码必备-资源访问

为什么读不懂Spring源码?到底如何去读?从哪开始读?

怎样阅读Spring源码

面试的时候,你肯定被问过,Spring的初始化过程、或者Bean的生命周。我相信大部分人都是死记硬背的,真正能自己读懂代码而说出整个过程的人寥寥无几。

造成这种局面的原因,尝试阅读Spring源码的人肯定深有感触,代码量是一部分原因,还有就是里面的各种抽象的接口,如果没有人或者书的指点,你很难知道它是起什么作用。

不是我们的能力不行,而是方法不对。

就像我们工作中,对于别人写的代码让你直接去阅读,没有当事人的帮助,那绝对是很痛苦的一件事,不论你的技术有多牛。

如下图所示,是Spring中加载Bean对象的一个简单过程:

图像看着很简单,但是对于不熟悉Spring的人来说,确实可以死记硬背,但是并不能理解图中说的是什么。因为里面的各种概念(Resource、BeanDefinition、BeanDefinitionRegistry )从来没见过。

因此,阅读源码我们应该从点到面。先了解Spring设计的各种概念、各种抽象的接口。然后在去整体串起来看,就会容易很多了。

这里打算从各个点开始详细介绍Spring相关的概念,和各位道友一起讨论交流,最后在串起来,真正读懂Spring。

第一步:资源访问Resource

Spring中喜欢把一切都看做资源(Resource)。除了我们认为的图片、css、js、配置文件(xml、yml),甚至我们定义的类都可以看做是资源。

Spring设计了一个Resource接口,它为应用提供了资源的访问能力,该接口拥有对应不同资源类型的实现类。

1、资源接口Resource

先看一下Resource接口的主要方法:

public interface InputStreamSource {
    //返回资源对应的输入流
	InputStream getInputStream() throws IOException;
}

public interface Resource extends InputStreamSource {
    //资源是否存在
	boolean exists();
    //资源是否打开
    default boolean isOpen() {
		return false;
	}
    //如果资源可以表示成Url,则返回对应的URL对象。
	URL getURL() throws IOException;

	URI getURI() throws IOException;
    //如果资源是一个文件,返回File对象
	File getFile() throws IOException;
}

Spring框架使用Resource装载各种资源,如下图为Resource的具体实现类:

  •  WritableResource:可写资源接口,用来写资源的。实现类有FileSystemResource、FileUrlResource、PathResource
  • ByteArrayResource: 读取二进制数组表示的资源
  • ClassPathResource: 类路径下的资源,资源以相对于类路径的方式表示

这里就不一一列举了,可以自己看看图片。

阅读各个实现类的办法:

我们知道Resource是用来读取资源的,所以最重要的一个实现方法就是getInputStream方法。从这个方法为入口阅读,你会看到最终会回到Jdk的IO流上去。

还需要了解一下Java的类加载器ClassLoader的相关知识。

2、Resource实现类的使用 

这里使用ClassPathResource和FileSystemResource来举例获取Spring的资源文件application.properties。

提示:我们常说的classpath,也就是类路径,就是代码编译后,会有一个target目录,里面的classes就是类路径。

public class Test {

    public static void main(String[] args) throws IOException {
        String systemFile = "/Users/xuezhendong/IdeaProjects/SpringLearn/src/main/resources/application.properties";
        FileSystemResource fileSystemResource = new FileSystemResource(systemFile);
        System.out.println(fileSystemResource.getFilename());
        InputStream inputStream = fileSystemResource.getInputStream();
        System.out.println(inputStream);

        String classPathFile = "application.properties";
        ClassPathResource resource = new ClassPathResource(classPathFile);
        System.out.println(resource.getFilename());
        System.out.println(resource.getInputStream());
    }
}

结果 

 结果中返回的均是JDK中的IO流。我们获取资源后,可以通过定义的方法获取File对象,获取InputStream、OutPutStream,然后就能进行我们想操作的一切。

3、资源加载

为了访问不同的资源,必须使用不通的Resource的实现类,这是比较麻烦的一件事。因此Spring提供了一个强大的资源加载机制,不但能够通过”classpath:“、”file:“等资源地址前缀识别不通的资源类型,还支持Ant风格带通配符的资源地址。

3.1资源地址表达

Ant风格:

?匹配文件名中的一个字符。 *匹配文件名中的任意多个字符。**配置多层路径。

资源类型地址前缀
地址前缀资源类型
classpath:类路径下的资源
file:

文件系统资源

http://从网络加载资源
ftp://从ftp服务器加载资源
没有前缀根据具体的实现类加载

定义好了资源如何表示,接下来看看Spring如何使用不同的表示来加载资源的。 

3.2资源加载器

Spring定义了一套资源加载的接口,并提供了实现类:

 ResourceLoader接口如下,最主要的接口就是获取资源Resource,该方法可以根据带资源类型前缀的地址去获取资源,但是不支持Ant风格的方式。

ResourcePatternResolver扩展了ResourceLoader接口,支持了Ant风格,PathMatchingResourcePatternResolver是Spring提供的该接口的标准实现类。

public interface ResourceLoader {
    //"classpath:"
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	Resource getResource(String location);
	@Nullable
	ClassLoader getClassLoader();
}

 阅读方式仍然就去从子类中的getResource方法入手,容易看出是根据不同的前缀来调用不通的Resource类。

 总结:

阅读Spring源码不是那么容易的事,里面概念很多,希望与众道友一起讨论交流。

大家在看文章的过程中,最好自己能打开代码,去查看和验证,这样记忆最深刻。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七号公园的忧伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值