org.springframework.core.io.Resource gives Spring APIs one handle for content
that may reside in a file, classpath entry, URL, servlet context, byte array, or
already-open stream. The abstraction describes access capabilities; it does not
make every resource seekable, repeatable, writable, or backed by a file.
The Resource Contract
#
Resource extends InputStreamSource. getInputStream() is the fundamental
operation, while methods such as exists(), isReadable(), isOpen(),
isFile(), contentLength(), lastModified(), and getDescription() expose
capabilities or metadata.
Important implementations include:
ClassPathResourcefor class-loader or class-relative entries;FileSystemResourceandPathResourcefor filesystem content;UrlResourcefor URLs supported by the JVM;ServletContextResourcefor web-application paths;ByteArrayResourcefor repeatable in-memory bytes; andInputStreamResourcefor an already-open, normally single-use stream.
Callers own every stream returned by getInputStream() and must close it.
isOpen() is especially important: an InputStreamResource wraps an open
handle and cannot safely be read repeatedly, while file and byte-array resources
can open a fresh stream for each call.
Loading and Relative Resolution #
ResourceLoader.getResource(String) converts a location into one resource.
Every ApplicationContext is a resource loader. Prefixes select explicit
semantics:
classpath:com/example/report.htmlselects a classpath resource.file:/srv/app/report.htmlselects a filesystem URL.https://example.net/schema.jsonselects a URL resource.
An unprefixed location is context-relative. A
ClassPathXmlApplicationContext interprets it as a classpath location,
FileSystemXmlApplicationContext as a filesystem location, and a web
application context as a servlet-context location. Library code should request
a Resource or ResourceLoader rather than assume one default.
ResourcePatternResolver extends loading to location patterns and multiple
matches. classpath*: searches all matching classpath roots; Ant-style
wildcards apply through pattern resolution, not through the single-resource
ResourceLoader contract.
Injecting Resources #
Spring can convert a location string to Resource using the surrounding
application context as the loader:
@Component
final class ReportRenderer {
private final Resource template;
ReportRenderer(@Value("${report.template:classpath:reports/daily.html}")
Resource template) {
this.template = template;
}
}Constructor injection makes the dependency visible and lets a test supply a
ByteArrayResource. Inject ResourceLoader when the location varies per
operation, and inject Resource[] or a ResourcePatternResolver only when the
application intentionally accepts multiple matches.
Existence, Repeatability, and Writing #
exists() is a probe, not a reservation; content can disappear before it is
opened. Prefer opening the resource and handling the resulting IOException
when correctness depends on access. Metadata operations can also require I/O,
and a remote URL can be slow or unavailable.
WritableResource adds isWritable() and getOutputStream().
FileSystemResource and PathResource implement it, while classpath resources
inside a packaged JAR do not. Code that writes should require
WritableResource rather than downcast based on a location string.
Repeatability depends on the implementation. A parser that needs two passes can
buffer a one-shot resource into a ByteArrayResource, with an explicit size
limit. APIs should document whether they open once, reopen, retain, or close
streams so resource ownership remains unambiguous.
Comments
Read or comment on GitHub (sign-in required to comment)