Spring 源码第一篇开整!配置文件是怎么加载的?

resources 目录下创建配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>

然后去加载这个配置文件:

public static void main(String[] args) {

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(“beans.xml”));

User user = factory.getBean(User.class);

System.out.println("user = " + user);

}

这里为了展示数据的读取过程,我就先用这个已经过期的 XmlBeanFactory 来加载,这并不影响我们阅读源码。

上面这个是一个非常简单的 Spring 入门案例,相信很多小伙伴在第一次接触 Spring 的时候,写出来的可能都是这个 Demo。

在上面这段代码执行过程中,首先要做的事情就是先把 XML 配置文件加载到内存中,再去解析它,再去。。。。。

一步一步来吧,先来看 XML 文件如何被加入到内存中去。

3.文件读取


文件读取在 Spring 中很常见,也算是一个比较基本的功能,而且 Spring 提供的文件加载方式,不仅仅在 Spring 框架中可以使用,我们在项目中有其他文件加载需求也可以使用。

首先,Spring 中使用 Resource 接口来封装底层资源,Resource 接口本身实现自 InputStreamSource 接口:

我们来看下这两个接口的定义:

public interface InputStreamSource {

InputStream getInputStream() throws IOException;

}

public interface Resource extends InputStreamSource {

boolean exists();

default boolean isReadable() {

return exists();

}

default boolean isOpen() {

return false;

}

default boolean isFile() {

return false;

}

URL getURL() throws IOException;

URI getURI() throws IOException;

File getFile() throws IOException;

default ReadableByteChannel readableChannel() throws IOException {

return Channels.newChannel(getInputStream());

}

long contentLength() throws IOException;

long lastModified() throws IOException;

Resource createRelative(String relativePath) throws IOException;

@Nullable

String getFilename();

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(‘/’);

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

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。

image

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!!!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
32d36.jpg" alt=“img” style=“zoom: 33%;” />

最后

这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。

[外链图片转存中…(img-RgyMBgTM-1713303881117)]

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

你的支持,我的动力;祝各位前程似锦,offer不断!!!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值