Spring如何实现资源文件的加载
Spring如何实现资源文件的加载
Spring资源文件的加载依赖于Resource与ResourceLoader这两个类,采用采用的是策略模式与工厂方法相结合实现的
其中Resource是所有资源类型的父类,可以通过继承该类实现其getInputStream方法,获取资源文件的输入流,之后用过该输入流对象就可以实现对文件内容的读取。
除此之外为了更好的获取不同资源文件的Resource对象,这里采用了策略模式来根据不同的location获取获取Resource
手下我们需要创建一个Resource作为资源实现的接口,在该类当中定义了一个getInputStream
方法,我们可以通过子类重写该方法,以实现不同类型资源的读取
public interface Resource {
/**
* 获取资源的输入流。
* @return 资源的输入流
*/
InputStream getInputStream() throws IOException;
}
ClassPathResource
public class ClassPathResource implements Resource{
// 文件相对路径
private final String path;
private final ClassLoader classLoader;
public ClassPathResource(String path) {
this.path = path;
this.classLoader = this.getClass().getClassLoader();
}
@Override
public InputStream getInputStream() throws FileNotFoundException {
InputStream inputStream = classLoader.getResourceAsStream(path);
if (inputStream == null){
throw new FileNotFoundException(String.format("%s,文件不存在",this.path));
}
return inputStream;
}
}
FileSystemResource
public class FileSystemResource implements Resource{
private final String filePath;
public FileSystemResource(String filePath) {
this.filePath = filePath;
}
/**
* 获取资源的输入流。
*
* @return 资源的输入流
*/
@Override
public InputStream getInputStream() throws FileNotFoundException {
try {
Path path = new File(this.filePath).toPath();
InputStream inputStream = Files.newInputStream(path);
return inputStream;
} catch (IOException e) {
throw new FileNotFoundException(String.format("%s,文件不存在",this.filePath));
}
}
}
URLResource
public class URLResource implements Resource{
private final URL url;
public URLResource(URL url) {
this.url = url;
}
/**
* 获取资源的输入流。
*
* @return 资源的输入流
*/
@Override
public InputStream getInputStream() throws IOException {
URLConnection urlConnection = this.url.openConnection();
InputStream inputStream = null;
inputStream = urlConnection.getInputStream();
return inputStream;
}
}
![[Pasted image 20250409155558.png]]
通过以上三者就可以实现对ClassPath,系统文件,URL文件的解析
现在文件的解析方法定义好了,那何时解析调用哪种方式解析又成为了一个问题。在这里我们就通过策略模式来实现
在这里我们定义了一个ResourceLoader接口,并定义了getResource的一个抽象方法
public interface ResourceLoader {
/**
* 根据指定的位置获取资源
*
* @param location 资源的位置,通常是一个路径或URL
* @return 返回一个Resource对象,表示加载的资源
*/
Resource getResource(String location);
}
在此之后,再次定义一个默认的资源文件加载器实现ResourceLoader,在getResource方法当中会根据传入的location格式动态匹配对应的解析方法。
public class DefaultResourceLoader implements ResourceLoader{
// Classpath前缀
private final String CLASSPATH_URL_PREFIX = "classpath:";
/**
* 根据指定的位置获取资源
* 目前只实现了Classpath,URL,File
* * @param location 资源的位置,通常是一个路径或URL
* @return 返回一个Resource对象,表示加载的资源
*/
@Override
public Resource getResource(String location) {
// 加载ClassPath路径下的资源文件
if (location.startsWith(CLASSPATH_URL_PREFIX)){
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
}
// 加载路径资源文件
else if (location.startsWith("/")){
return new FileSystemResource(location.substring(1));
}
// 加载URl资源文件
else {
try {
URL url = new URL(location);
return new URLResource(url);
} catch (MalformedURLException e) {
return new FileSystemResource(location);
}
}
}
}
现在我们就可以来测试一下
@Test
public void testClassPathResource() throws IOException {
DefaultResourceLoader defaultResourceLoader = new DefaultResourceLoader();
Resource resource = defaultResourceLoader.getResource("classpath:hello.txt");
InputStream inputStream = resource.getInputStream();
String read = IoUtil.readUtf8(inputStream);
System.out.println(read);
}