Spring 源码第一篇开整!配置文件是怎么加载的?,2024年最新JAVA程序设计清华大学出版社

String getDescription();

}

代码倒不难,我来稍微解释下:

  1. InputStreamSource 类只提供了一个 getInputStream 方法,该方法返回一个 InputStream,也就是说,InputStreamSource 会将传入的 File 等资源,封装成一个 InputStream 再重新返回。

  2. Resource 接口实现了 InputStreamSource 接口,并且封装了 Spring 内部可能会用到的底层资源,如 File、URL 以及 classpath 等。

  3. exists 方法用来判断资源是否存在。

  4. isReadable 方法用来判断资源是否可读。

  5. isOpen 方法用来判断资源是否打开。

  6. isFile 方法用来判断资源是否是一个文件。

  7. getURL/getURI/getFile/readableChannel 分别表示获取资源对应的 URL/URI/File 以及将资源转为 ReadableByteChannel 通道。

  8. contentLength 表示获取资源的大小。

  9. lastModified 表示获取资源的最后修改时间。

  10. createRelative 表示根据当前资源创建一个相对资源。

  11. getFilename 表示获取文件名。

  12. getDescription 表示在资源出错时,详细打印出出错的文件。

当我们加载不同资源时,对应了 Resource 的不同实现类,来看下 Resource 的继承关系:

可以看到,针对不同类型的数据源,都有各自的实现,我们这里来重点看下 ClassPathResource 的实现方式。

ClassPathResource 源码比较长,我这里挑一些关键部分来和大家分享:

public class ClassPathResource extends AbstractFileResolvingResource {

private final String path;

@Nullable

private ClassLoader classLoader;

@Nullable

private Class<?> clazz;

public ClassPathResource(String path) {

this(path, (ClassLoader) null);

}

public ClassPathResource(String path, @Nullable ClassLoader classLoader) {

Assert.notNull(path, “Path must not be null”);

String pathToUse = StringUtils.cleanPath(path);

if (pathToUse.startsWith(“/”)) {

pathToUse = pathToUse.substring(1);

}

this.path = pathToUse;

this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());

}

public ClassPathResource(String path, @Nullable Class<?> clazz) {

Assert.notNull(path, “Path must not be null”);

this.path = StringUtils.cleanPath(path);

this.clazz = clazz;

}

public final String getPath() {

return this.path;

}

@Nullable

public final ClassLoader getClassLoader() {

return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);

}

@Override

public boolean exists() {

return (resolveURL() != null);

}

@Nullable

protected URL resolveURL() {

if (this.clazz != null) {

return this.clazz.getResource(this.path);

}

else if (this.classLoader != null) {

return this.classLoader.getResource(this.path);

}

else {

return ClassLoader.getSystemResource(this.path);

}

}

@Override

public InputStream getInputStream() throws IOException {

InputStream is;

if (this.clazz != null) {

is = this.clazz.getResourceAsStream(this.path);

}

else if (this.classLoader != null) {

is = this.classLoader.getResourceAsStream(this.path);

}

else {

is = ClassLoader.getSystemResourceAsStream(this.path);

}

if (is == null) {

throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");

}

return is;

}

@Override

public URL getURL() throws IOException {

URL url = resolveURL();

if (url == null) {

throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");

}

return url;

}

@Override

public Resource createRelative(String relativePath) {

String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);

return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :

new ClassPathResource(pathToUse, this.classLoader));

}

@Override

@Nullable

public String getFilename() {

return StringUtils.getFilename(this.path);

}

@Override

public String getDescription() {

StringBuilder builder = new StringBuilder(“class path resource [”);

String pathToUse = this.path;

if (this.clazz != null && !pathToUse.startsWith(“/”)) {

builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));

builder.append(‘/’);

}

if (pathToUse.startsWith(“/”)) {

pathToUse = pathToUse.substring(1);

}

builder.append(pathToUse);

builder.append(‘]’);

return builder.toString();

}

}

  1. 首先,ClassPathResource 的构造方法有四个,一个已经过期的方法我这里没有列出来。另外三个,我们一般调用一个参数的即可,也就是传入文件路径即可,它内部会调用另外一个重载的方法,给 classloader 赋上值(因为在后面要通过 classloader 去读取文件)。

  2. 在 ClassPathResource 初始化的过程中,会先调用 StringUtils.cleanPath 方法对传入的路径进行清理,所谓的路径清理,就是处理路径中的相对地址、Windows 系统下的 \\ 变为 / 等。

  3. getPath 方法用来返回文件路径,这是一个相对路径,不包含 classpath。

  4. resolveURL 方法表示返回资源的 URL,返回的时候优先用 Class.getResource 加载,然后才会用 ClassLoader.getResource 加载,关于 Class.getResource 和 ClassLoader.getResource 的区别,又能写一篇文章出来,我这里就大概说下,Class.getResource 最终还是会调用 ClassLoader.getResource,只不过 Class.getResource 会先对路径进行处理。

  5. getInputStream 读取资源,并返回 InputStream 对象。

  6. createRelative 方法是根据当前的资源,再创建一个相对资源。

这是 ClassPathResource,另外一个大家可能会接触到的 FileSystemResource ,小伙伴们可以自行查看其源码,比 ClassPathResource 简单。

如果不是使用 Spring,我们仅仅想自己加载 resources 目录下的资源,也可以采用这种方式:

ClassPathResource resource = new ClassPathResource(“beans.xml”);

InputStream inputStream = resource.getInputStream();

拿到 IO 流之后自行解析即可。

在 Spring 框架,构造出 Resource 对象之后,接下来还会把 Resource 对象转为 EncodedResource,这里会对资源进行编码处理,编码主要体现在 getReader 方法上,在获取 Reader 对象时,如果有编码,则给出编码格式:

public Reader getReader() throws IOException {

if (this.charset != null) {

return new InputStreamReader(this.resource.getInputStream(), this.charset);

}

else if (this.encoding != null) {

return new InputStreamReader(this.resource.getInputStream(), this.encoding);

}

else {

return new InputStreamReader(this.resource.getInputStream());

}

}

所有这一切搞定之后,接下来就是通过 XmlBeanDefinitionReader 去加载 Resource 了。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
img
img
img

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
img

计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。**
[外链图片转存中…(img-11doDLZe-1712534598345)]
[外链图片转存中…(img-458opHhB-1712534598345)]
[外链图片转存中…(img-P2YW11Hc-1712534598346)]

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-9ACEEppc-1712534598346)]

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值