A
ResourcePatternResolver implementation that is able to resolve a
specified resource location path into one or more matching Resources.
The source path may be a simple path which has a one-to-one mapping to a
target
org.springframework.core.io.Resource, or alternatively
may contain the special "
classpath*:" prefix and/or
internal Ant-style regular expressions (matched using Spring's
org.springframework.util.AntPathMatcher utility).
Both of the latter are effectively wildcards.
No Wildcards:
In the simple case, if the specified location path does not start with the
"classpath*:" prefix, and does not contain a PathMatcher pattern,
this resolver will simply return a single resource via a
getResource() call on the underlying
ResourceLoader.
Examples are real URLs such as "
file:C:/context.xml", pseudo-URLs
such as "
classpath:/context.xml", and simple unprefixed paths
such as "
/WEB-INF/context.xml". The latter will resolve in a
fashion specific to the underlying
ResourceLoader (e.g.
ServletContextResource for a
WebApplicationContext).
Ant-style Patterns:
When the path location contains an Ant-style pattern, e.g.:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
the resolver follows a more complex but defined procedure to try to resolve
the wildcard. It produces a
Resource for the path up to the last
non-wildcard segment and obtains a
URL from it. If this URL is
not a "
jar:" URL or container-specific variant (e.g.
"
zip:" in WebLogic, "
wsjar" in WebSphere", etc.),
then a
java.io.File is obtained from it, and used to resolve the
wildcard by walking the filesystem. In the case of a jar URL, the resolver
either gets a
java.net.JarURLConnection from it, or manually parses
the jar URL, and then traverses the contents of the jar file, to resolve the
wildcards.
Implications on portability:
If the specified path is already a file URL (either explicitly, or
implicitly because the base
ResourceLoader is a filesystem one,
then wildcarding is guaranteed to work in a completely portable fashion.
If the specified path is a classpath location, then the resolver must
obtain the last non-wildcard path segment URL via a
Classloader.getResource() call. Since this is just a
node of the path (not the file at the end) it is actually undefined
(in the ClassLoader Javadocs) exactly what sort of a URL is returned in
this case. In practice, it is usually a
java.io.File representing
the directory, where the classpath resource resolves to a filesystem
location, or a jar URL of some sort, where the classpath resource resolves
to a jar location. Still, there is a portability concern on this operation.
If a jar URL is obtained for the last non-wildcard segment, the resolver
must be able to get a
java.net.JarURLConnection from it, or
manually parse the jar URL, to be able to walk the contents of the jar,
and resolve the wildcard. This will work in most environments, but will
fail in others, and it is strongly recommended that the wildcard
resolution of resources coming from jars be thoroughly tested in your
specific environment before you rely on it.
classpath*: Prefix:
There is special support for retrieving multiple class path resources with
the same name, via the "
classpath*:" prefix. For example,
"
classpath*:META-INF/beans.xml" will find all "beans.xml"
files in the class path, be it in "classes" directories or in JAR files.
This is particularly useful for autodetecting config files of the same name
at the same location within each jar file. Internally, this happens via a
ClassLoader.getResources() call, and is completely portable.
The "classpath*:" prefix can also be combined with a PathMatcher pattern in
the rest of the location path, for example "classpath*:META-INF/*-beans.xml".
In this case, the resolution strategy is fairly simple: a
ClassLoader.getResources() call is used on the last non-wildcard
path segment to get all the matching resources in the class loader hierarchy,
and then off each resource the same PathMatcher resolution strategy described
above is used for the wildcard subpath.
Other notes:
WARNING: Note that "
classpath*:" when combined with
Ant-style patterns will only work reliably with at least one root directory
before the pattern starts, unless the actual target files reside in the file
system. This means that a pattern like "
classpath*:*.xml" will
not retrieve files from the root of jar files but rather only from the
root of expanded directories. This originates from a limitation in the JDK's
ClassLoader.getResources() method which only returns file system
locations for a passed-in empty String (indicating potential roots to search).
This
ResourcePatternResolver implementation is trying to mitigate the
jar root lookup limitation through
URLClassLoader introspection and
"java.class.path" manifest evaluation; however, without portability guarantees.
WARNING: Ant-style patterns with "classpath:" resources are not
guaranteed to find matching resources if the root package to search is available
in multiple class path locations. This is because a resource such as
com/mycompany/package1/service-context.xml
may be in only one location, but when a path such as
classpath:com/mycompany/**/service-context.xml
is used to try to resolve it, the resolver will work off the (first) URL
returned by
getResource("com/mycompany");. If this base package node
exists in multiple classloader locations, the actual end resource may not be
underneath. Therefore, preferably, use "
classpath*:" with the same
Ant-style pattern in such a case, which will search
all class path
locations that contain the root package.