docs
Package: org.springframework.boot.io
The io package provides support for loading resources with enhanced protocol resolution and file system integration.
Custom resource loader that supports additional protocol resolvers and prefers file system resources.
public class ApplicationResourceLoader extends DefaultResourceLoader {
@Override
protected Resource getResourceByPath(String path);
public static ResourceLoader get();
public static ResourceLoader get(ClassLoader classLoader);
public static ResourceLoader get(ClassLoader classLoader,
SpringFactoriesLoader springFactoriesLoader);
public static ResourceLoader get(ClassLoader classLoader,
SpringFactoriesLoader springFactoriesLoader,
Path workingDirectory);
public static ResourceLoader get(ResourceLoader resourceLoader);
public static ResourceLoader get(ResourceLoader resourceLoader,
boolean preferFileResolution);
public static ResourceLoader get(ResourceLoader resourceLoader,
SpringFactoriesLoader springFactoriesLoader);
}DefaultResourceLoader which resolves to classpath resourcesspring.factories// Get with default class loader
ResourceLoader loader = ApplicationResourceLoader.get();
// Get with specific class loader
ResourceLoader loader = ApplicationResourceLoader.get(classLoader);
// Get with custom SpringFactoriesLoader
ResourceLoader loader = ApplicationResourceLoader.get(
classLoader,
springFactoriesLoader
);
// Get with working directory
ResourceLoader loader = ApplicationResourceLoader.get(
classLoader,
springFactoriesLoader,
workingDirectory
);
// Wrap existing resource loader
ResourceLoader loader = ApplicationResourceLoader.get(existingLoader);
// Wrap with file resolution preference
ResourceLoader loader = ApplicationResourceLoader.get(
existingLoader,
true // prefer file resolution
);Strategy interface for determining file paths of resources.
public interface FilePathResolver {
String resolveFilePath(String location, Resource resource);
}Implementations can be registered in spring.factories to customize how resources are resolved to file system paths.
@Service
public class ConfigService {
private final ResourceLoader resourceLoader;
public ConfigService() {
// Get application resource loader
this.resourceLoader = ApplicationResourceLoader.get();
}
public Properties loadConfig(String path) throws IOException {
// Loads from file system by default
Resource resource = resourceLoader.getResource(path);
Properties props = new Properties();
try (InputStream is = resource.getInputStream()) {
props.load(is);
}
return props;
}
}public class ResourceLoadingExamples {
private final ResourceLoader loader = ApplicationResourceLoader.get();
public void loadResources() throws IOException {
// File system (default for plain paths)
Resource fileResource = loader.getResource("config/app.properties");
// Classpath
Resource classpathResource = loader.getResource("classpath:config/app.properties");
// URL
Resource urlResource = loader.getResource("https://example.com/config.json");
// File URL
Resource fileUrlResource = loader.getResource("file:/etc/config/app.properties");
}
}// DefaultResourceLoader behavior
DefaultResourceLoader defaultLoader = new DefaultResourceLoader();
Resource resource1 = defaultLoader.getResource("config.properties");
// → Returns ClassPathResource("config.properties")
// ApplicationResourceLoader behavior
ResourceLoader appLoader = ApplicationResourceLoader.get();
Resource resource2 = appLoader.getResource("config.properties");
// → Returns FileSystemResource("config.properties")
// Both loaders respect explicit prefixes
Resource cp1 = defaultLoader.getResource("classpath:config.properties");
Resource cp2 = appLoader.getResource("classpath:config.properties");
// → Both return ClassPathResourcepublic class WorkingDirectoryExample {
public ResourceLoader createLoader(String workingDir) {
Path workingDirectory = Paths.get(workingDir);
return ApplicationResourceLoader.get(
null, // use default class loader
SpringFactoriesLoader.forDefaultResourceLocation(null),
workingDirectory
);
}
public void loadRelativeResource() throws IOException {
ResourceLoader loader = createLoader("/app/config");
// Loads from /app/config/settings.yaml
Resource resource = loader.getResource("settings.yaml");
String content = new String(resource.getInputStream().readAllBytes());
System.out.println(content);
}
}@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApplication.class);
// Set custom resource loader
app.setResourceLoader(ApplicationResourceLoader.get());
app.run(args);
}
}// Implement ProtocolResolver
public class CustomProtocolResolver implements ProtocolResolver {
@Override
public Resource resolve(String location, ResourceLoader resourceLoader) {
if (location.startsWith("custom:")) {
String path = location.substring(7);
return new CustomResource(path);
}
return null;
}
}
// Register in META-INF/spring.factories
// org.springframework.core.io.ProtocolResolver=\
// com.example.CustomProtocolResolver
// Usage
ResourceLoader loader = ApplicationResourceLoader.get();
Resource resource = loader.getResource("custom:my-resource");// Implement FilePathResolver
public class CustomFilePathResolver implements ApplicationResourceLoader.FilePathResolver {
@Override
public String resolveFilePath(String location, Resource resource) {
if (location.startsWith("s3:")) {
// Download S3 resource to local cache and return path
String localPath = downloadFromS3(location);
return localPath;
}
return null;
}
private String downloadFromS3(String s3Url) {
// Implementation details
return "/tmp/cache/" + extractKey(s3Url);
}
private String extractKey(String s3Url) {
return s3Url.substring(3);
}
}
// Register in META-INF/spring.factories
// org.springframework.boot.io.ApplicationResourceLoader$FilePathResolver=\
// com.example.CustomFilePathResolver
// Usage with file resolution preference
ResourceLoader loader = ApplicationResourceLoader.get(
existingLoader,
true // prefer file resolution
);@Configuration
public class ResourceLoaderConfig {
@Bean
public ResourceLoader resourceLoader(ApplicationContext context) {
// Wrap application context's resource loader
return ApplicationResourceLoader.get(
context,
false // don't prefer file resolution
);
}
}
@Service
public class DataService {
private final ResourceLoader resourceLoader;
public DataService(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public String loadData(String location) throws IOException {
Resource resource = resourceLoader.getResource(location);
return new String(resource.getInputStream().readAllBytes());
}
}@SpringBootTest
class ResourceLoadingTest {
@Test
void testLoadApplicationResource() throws IOException {
ResourceLoader loader = ApplicationResourceLoader.get();
// Create test file
Path testFile = Files.createTempFile("test", ".txt");
Files.writeString(testFile, "test content");
// Load using absolute path
Resource resource = loader.getResource(testFile.toString());
assertTrue(resource.exists());
assertEquals("test content",
new String(resource.getInputStream().readAllBytes()));
// Cleanup
Files.delete(testFile);
}
@Test
void testLoadClasspathResource() throws IOException {
ResourceLoader loader = ApplicationResourceLoader.get();
// Load from test resources
Resource resource = loader.getResource("classpath:test-data.json");
assertTrue(resource.exists());
assertNotNull(resource.getInputStream());
}
}@Component
public class ResourcePatternService {
private final ResourceLoader resourceLoader;
public ResourcePatternService() {
this.resourceLoader = ApplicationResourceLoader.get();
}
public Resource loadConfig(String environment) {
// Load environment-specific config
String location = String.format("config/application-%s.yml", environment);
return resourceLoader.getResource(location);
}
public Resource loadFromProfile(String profile, String filename) {
// Load from profile directory
return resourceLoader.getResource(
String.format("profiles/%s/%s", profile, filename)
);
}
public Resource loadWithFallback(String primary, String fallback) {
Resource resource = resourceLoader.getResource(primary);
if (!resource.exists()) {
resource = resourceLoader.getResource(fallback);
}
return resource;
}
}@Service
public class ConfigurationLoader {
private final ResourceLoader resourceLoader;
private final Environment environment;
public ConfigurationLoader(Environment environment) {
this.resourceLoader = ApplicationResourceLoader.get();
this.environment = environment;
}
public Map<String, Object> loadConfiguration() {
Map<String, Object> config = new HashMap<>();
// Load base configuration
loadIntoMap(config, "config/base.properties");
// Load environment-specific configuration
String profile = environment.getProperty("spring.profiles.active", "default");
loadIntoMap(config, String.format("config/%s.properties", profile));
// Load local overrides if present
Resource localConfig = resourceLoader.getResource("config/local.properties");
if (localConfig.exists()) {
loadIntoMap(config, localConfig);
}
return config;
}
private void loadIntoMap(Map<String, Object> map, String location) {
Resource resource = resourceLoader.getResource(location);
loadIntoMap(map, resource);
}
private void loadIntoMap(Map<String, Object> map, Resource resource) {
if (!resource.exists()) {
return;
}
try (InputStream is = resource.getInputStream()) {
Properties props = new Properties();
props.load(is);
props.forEach((k, v) -> map.put(k.toString(), v));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}When using ApplicationResourceLoader:
spring.factoriesclasspath:, file:, http:, etc.preferFileResolution is enabled// Good - explicit
Resource resource = loader.getResource("classpath:config.properties");
Resource fileResource = loader.getResource("file:/etc/config.properties");
// Avoid ambiguity when intention is unclear
Resource ambiguous = loader.getResource("config.properties");Resource resource = loader.getResource("optional-config.properties");
if (resource.exists() && resource.isReadable()) {
// Use resource
} else {
// Use defaults or throw exception
}// Configure working directory for consistent relative path resolution
ResourceLoader loader = ApplicationResourceLoader.get(
classLoader,
springFactoriesLoader,
Paths.get("/app/data")
);import org.springframework.boot.io.ApplicationResourceLoader;
import org.springframework.boot.io.ApplicationResourceLoader.FilePathResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.ProtocolResolver;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.io.InputStream;