Spring框架資源訪問策略詳解(Resource接口)
一、Resource接口概述
Spring框架提供了一個強大的資源訪問抽象層,通過Resource接口統(tǒng)一了各種底層資源的訪問方式。這個接口位于org.springframework.core.io包中,是Spring資源加載策略的核心接口。
二、Resource接口的主要實現(xiàn)類
2.1 UrlResource
UrlResource封裝了java.net.URL,用于訪問通過URL表示的資源,如文件、HTTP目標、FTP目標等。
示例代碼:
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
public class UrlResourceExample {
public static void main(String[] args) {
try {
// 訪問HTTP資源
Resource httpResource = new UrlResource("https://www.example.com/index.html");
System.out.println("HTTP資源是否存在: " + httpResource.exists());
System.out.println("文件名: " + httpResource.getFilename());
// 訪問本地文件系統(tǒng)資源
Resource fileResource = new UrlResource("file:/path/to/local/file.txt");
System.out.println("文件資源長度: " + fileResource.contentLength());
// 讀取資源內(nèi)容
try (InputStream is = httpResource.getInputStream()) {
String content = new String(is.readAllBytes(), StandardCharsets.UTF_8);
System.out.println("資源內(nèi)容前100字符: " + content.substring(0, Math.min(100, content.length())));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2 ClassPathResource
ClassPathResource用于訪問類路徑下的資源。
示例代碼:
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class ClassPathResourceExample {
public static void main(String[] args) {
try {
// 訪問類路徑根目錄下的資源
Resource rootResource = new ClassPathResource("application.properties");
System.out.println("資源是否存在: " + rootResource.exists());
// 訪問包路徑下的資源
Resource packageResource = new ClassPathResource("com/example/config.xml");
System.out.println("文件名: " + packageResource.getFilename());
// 使用特定類加載器加載資源
ClassPathResource withClassLoader = new ClassPathResource("config.properties", getClass().getClassLoader());
// 使用特定類作為相對路徑基準
ClassPathResource withClazz = new ClassPathResource("config-override.properties", getClass());
// 讀取資源內(nèi)容
if (packageResource.exists()) {
try (InputStream is = packageResource.getInputStream()) {
Properties props = new Properties();
props.load(is);
System.out.println("加載的屬性: " + props);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 FileSystemResource
FileSystemResource用于訪問文件系統(tǒng)資源。
示例代碼:
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
public class FileSystemResourceExample {
public static void main(String[] args) {
try {
// 創(chuàng)建文件系統(tǒng)資源
Resource fileResource = new FileSystemResource("/path/to/file.txt");
System.out.println("文件是否存在: " + fileResource.exists());
System.out.println("文件大小: " + fileResource.contentLength() + " bytes");
// 轉(zhuǎn)換為WritableResource進行寫操作
if (fileResource instanceof WritableResource) {
WritableResource writableResource = (WritableResource) fileResource;
try (OutputStream os = writableResource.getOutputStream()) {
os.write("Hello, Spring Resource!".getBytes());
}
}
// 獲取File對象
File file = fileResource.getFile();
System.out.println("最后修改時間: " + new Date(file.lastModified()));
// 創(chuàng)建相對資源
Resource relativeResource = fileResource.createRelative("sibling-file.txt");
System.out.println("相對路徑資源: " + relativeResource.getDescription());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.4 ServletContextResource
ServletContextResource是WebApplicationContext的默認資源類型,用于訪問相對于Web應(yīng)用根目錄的資源。
示例代碼:
import org.springframework.core.io.Resource;
import org.springframework.web.context.support.ServletContextResource;
@Controller
public class ServletContextResourceExample {
@Autowired
private ServletContext servletContext;
@GetMapping("/load-resource")
public ResponseEntity<String> loadResource() {
try {
// 創(chuàng)建ServletContext資源
Resource resource = new ServletContextResource(servletContext, "/WEB-INF/web.xml");
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
// 讀取資源內(nèi)容
String content;
try (InputStream is = resource.getInputStream()) {
content = new String(is.readAllBytes(), StandardCharsets.UTF_8);
}
return ResponseEntity.ok()
.header("Content-Type", "text/xml")
.body(content);
} catch (IOException e) {
return ResponseEntity.internalServerError().body("Error reading resource");
}
}
}
三、ResourceLoader接口
ResourceLoader接口定義了資源加載策略,其核心方法是:
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
Spring提供了DefaultResourceLoader作為默認實現(xiàn),ApplicationContext都實現(xiàn)了ResourceLoader接口。
他與Resource的關(guān)系:
- ResourceLoader 是資源的加載器(工廠)
- Resource 是加載后的資源表示(產(chǎn)品)
層次結(jié)構(gòu):
ResourceLoader (接口)
├─ DefaultResourceLoader (默認實現(xiàn))
├─ ResourcePatternResolver (擴展接口)
│ └─ PathMatchingResourcePatternResolver (實現(xiàn))
└─ ApplicationContext (所有應(yīng)用上下文都實現(xiàn)ResourceLoader)
資源位置與Resource實現(xiàn)對應(yīng)關(guān)系:
位置前綴 | Resource 實現(xiàn)類 | 示例 |
classpath: | ClassPathResource | classpath:config.xml |
file: | FileSystemResource | file:/path/to/file.txt |
http: / https: | UrlResource | |
(無前綴) | 取決于實現(xiàn) | /WEB-INF/web.xml |
使用示例:
// 使用默認實現(xiàn)
ResourceLoader loader = new DefaultResourceLoader();
// 加載類路徑資源
Resource classpathResource = loader.getResource("classpath:app.properties");
// 加載文件系統(tǒng)資源
Resource fileResource = loader.getResource("file:/etc/app/config.properties");
// 加載URL資源
Resource urlResource = loader.getResource("https://example.com/config.json");
// 無前綴 - 行為取決于實現(xiàn)
Resource defaultResource = loader.getResource("/WEB-INF/web.xml");
@RestController
public class MyController {
// 注入ApplicationContext(也是ResourceLoader)
@Autowired
private ApplicationContext appContext;
@GetMapping("/resource")
public String loadResource() throws IOException {
Resource resource = appContext.getResource("classpath:data.json");
try (InputStream is = resource.getInputStream()) {
return new String(is.readAllBytes());
}
}
}
四、ResourcePatternResolver接口
ResourcePatternResolver是ResourceLoader的擴展,支持解析位置模式(如Ant風(fēng)格路徑模式)為多個Resource對象。
PathMatchingResourcePatternResolver是其默認實現(xiàn),支持:
- classpath*:前綴:加載所有匹配的類路徑資源
- Ant風(fēng)格模式:如/WEB-INF/*-context.xml
示例代碼:
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
public class ResourcePatternExample {
public static void main(String[] args) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
// 加載單個資源
Resource singleResource = resolver.getResource("classpath:application.properties");
System.out.println("單資源: " + singleResource.getFilename());
// 使用Ant風(fēng)格模式加載多個資源
Resource[] resources = resolver.getResources("classpath*:META-INF/*.xml");
System.out.println("找到 " + resources.length + " 個META-INF下的XML文件");
// 加載包下的所有屬性文件
Resource[] props = resolver.getResources("classpath*:com/example/config/*.properties");
for (Resource res : props) {
System.out.println("屬性文件: " + res.getURL());
}
// 加載WEB-INF下的所有XML文件
Resource[] webResources = resolver.getResources("/WEB-INF/*.xml");
System.out.println("WEB-INF下的XML文件數(shù)量: " + webResources.length);
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、自定義Resource實現(xiàn)示例
import org.springframework.core.io.AbstractResource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CustomResource extends AbstractResource {
private final String content;
private final String description;
public CustomResource(String content, String description) {
this.content = content;
this.description = description;
}
@Override
public String getDescription() {
return description;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(content.getBytes());
}
@Override
public boolean exists() {
return true;
}
@Override
public long contentLength() throws IOException {
return content.length();
}
}
// 使用自定義Resource
public class CustomResourceExample {
public static void main(String[] args) {
Resource customResource = new CustomResource("Custom data", "My custom resource");
try (InputStream is = customResource.getInputStream()) {
String readContent = new String(is.readAllBytes());
System.out.println("讀取自定義資源: " + readContent);
System.out.println("資源描述: " + customResource.getDescription());
System.out.println("資源大小: " + customResource.contentLength());
} catch (IOException e) {
e.printStackTrace();
}
}
}