Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the Resource and ResourceLoader system in Spring

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces "how to understand the Resource and ResourceLoader system in Spring". In the daily operation, I believe many people have doubts about how to understand the Resource and ResourceLoader system in Spring. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful for you to answer the questions of "how to understand the Resource and ResourceLoader system in Spring". Next, please follow the editor to study!

One Resources system

These Resources are mainly divided into two main categories: read-only and read-write.

From the above class diagram, we can see that FileSystemResource implements WritableResource, so only this class is readable and writable, while the others are read-only Resource.

Resources interface

Public interface Resource extends InputStreamSource {/ / determines whether the resource exists boolean exists (); / / determines whether the resource is readable. Only when true is returned, the getInputStream method can use boolean isReadable (); / / determine whether the resource is open. If it is open, the resource cannot be read or written multiple times, and the resource should be closed after the read is completed. Boolean isOpen (); / / gets the URL of the resource object. If the resource cannot be represented as URL, an exception URL getURL () throws IOException; / / gets the URI of the resource object; if the resource cannot be represented as URI, an exception URI getURI () throws IOException; / / gets the resource's File representation object; if the resource cannot be represented as a File object, an exception File getFile () throws IOException is thrown / / get the file name of the current resource, return null String getFilename () if the current resource does not have a file name; / / get the description information of the resource String getDescription ();}

The methods defined in the Resource interface do not need to be implemented for every actual resource type, and each actual resource type decides which methods to implement according to its own situation. For example, file-based resources generally implement the getFile method, while non-file-based resources generally do not implement the getFile method.

1.1 WriteableResource interface

For most resource files, they are not necessarily writable but generally readable. Therefore, the WritableResource interface is defined specifically for writable resource types, and two write-related methods are defined in this interface:

Boolean isWritable (); OutputStream getOutputStream () throws IOException;1.2 AbstractResource class public abstract class AbstractResource implements Resource {public boolean exists () {/ / Try file existence: can we find the file in the file system? Try {return getFile () .exists ();} catch (IOException ex) {/ / Fall back to stream existence: can we open the stream? Try {InputStream is = getInputStream (); is.close (); return true;} catch (Throwable isEx) {return false;}} public boolean isReadable () {return true;} public boolean isOpen () {return false Assert.state (is! = null, "resource input stream must not be null"); try {/ / the default implementation is to read all the data in inputStream to get the length long size = 0; byte [] buf = new byte [255]; int read While (read = is.read (buf))! =-1) {size + = read;} return size;} finally {try {is.close () } catch (IOException ex) {}} public long lastModified () throws IOException {long lastModified = getFileForLastModifiedCheck () .lastModified (); if (lastModified = = 0L) {throw new FileNotFoundException (getDescription () + "cannot be resolved in the file system for resolving its last-modified timestamp");} return lastModified } protected File getFileForLastModifiedCheck () throws IOException {return getFile ();} public Resource createRelative (String relativePath) throws IOException {/ / creation of relative path resource throw new FileNotFoundException ("Cannot create a relative resource for" + getDescription ()) is not supported by default;} public String getFilename () {return null }}

In the implementation of AbstractResource, it is assumed that resources cannot be represented as URL and File by default, and such resources such as ByteArrayResource and InputStreamResource can be adapted, because these resource types are not based on files but wrapped in byte arrays or input streams, so only read operations are generally supported for this type of operation.

1.2.1 FileSystemResource class

As you can see from the inheritance diagram above, FileSystemResource not only inherits the AbstractResource but also implements the WritableResource interface, that is, the resource type based on the file system, which generally supports read and write operations, as well as relative path resources.

1.2.2 AbstractFileResolvingResource class

AbstractFileResolvingResource represents the resources that need to be obtained by parsing the URL. For example, the implementation of its exists method:

@ Override public boolean exists () {try {URL url = getURL (); if (ResourceUtils.isFileURL (url)) {/ / Proceed with file system resolution return getFile () .exists () / / if it is a file, directly detect whether the file exists} else {/ / Try a URL connection content-length header URLConnection con = url.openConnection (); customizeConnection (con) HttpURLConnection httpCon = (con instanceof HttpURLConnection? (HttpURLConnection) con: null); if (httpCon! = null) {/ / if it is http url, detect whether the resource corresponding to url exists int code = httpCon.getResponseCode () If (code = = HttpURLConnection.HTTP_OK) {return true } else if (code = = HttpURLConnection.HTTP_NOT_FOUND) {return false }} if (con.getContentLength () > = 0) {return true } if (httpCon! = null) {/ / No HTTP OK status, and no content-length header: give up httpCon.disconnect (); return false } else {/ / Fall back to stream existence: can we open the stream? GetInputStream () .close (); return true;}} catch (IOException ex) {return false;}}

And it has two subclasses: UrlResource and ClassPathResouce, where the ClassPathResource type is the resource type that we use very often in Spring.

(1) UrlResource

As far as UrlResource is concerned, it is basically done by parsing URL, and any format that conforms to the URL specification can be represented as a UrlResource object.

(2) ClassPathResoucepublic class ClassPathResource extends AbstractFileResolvingResource {private final String path; private ClassLoader classLoader; private Class clazz; public ClassPathResource (String path) {this (path, (ClassLoader) null);} public ClassPathResource (String path, ClassLoader classLoader) {Assert.notNull (path, "Path must not be null"); String pathToUse = StringUtils.cleanPath (path) If (pathToUse.startsWith ("/")) {pathToUse = pathToUse.substring (1);} this.path = pathToUse; / / if ClassLoader is null, use the default ClassLoader this.classLoader = (classLoader! = null? ClassLoader: ClassUtils.getDefaultClassLoader ();} public ClassPathResource (String path, Class clazz) {Assert.notNull (path, "Path must not be null"); this.path = StringUtils.cleanPath (path); this.clazz = clazz / / use Class to load resources, or use ClassLoader to load} protected ClassPathResource (String path, ClassLoader classLoader, Class clazz) {this.path = StringUtils.cleanPath (path); / / use both Clss and ClassLoader this.classLoader = classLoader; this.clazz = clazz } public final String getPath () {return this.path;} public final ClassLoader getClassLoader () {return (this.clazz! = null? This.clazz.getClassLoader (): this.classLoader);} @ Override public boolean exists () {return (resolveURL ()! = null) } protected URL resolveURL () {/ / whether a resource exists or not. Judge if (this.clazz! = null) {return this.clazz.getResource (this.path) by Class and ClassLoader. } else if (this.classLoader! = null) {return this.classLoader.getResource (this.path);} else {return ClassLoader.getSystemResource (this.path);} @ Override public InputStream getInputStream () throws IOException {InputStream is / / the acquisition of InputStream is also determined by Class and ClassLoader to determine if (this.clazz! = null) {is = this.clazz.getResourceAsStream (this.path);} else if (this.classLoader! = null) {is = this.classLoader.getResourceAsStream (this.path) } else {is = ClassLoader.getSystemResourceAsStream (this.path);} if (is = = null) {throw new FileNotFoundException (getDescription () + "cannot be opened because it does not exist");} return is } @ Override public URL getURL () throws IOException {URL url = resolveURL (); if (url = = null) {throw new FileNotFoundException (getDescription () + "cannot be resolved to URL because it does not exist");} return url } @ Override public Resource createRelative (String relativePath) {String pathToUse = StringUtils.applyRelativePath (this.path, relativePath); return (this.clazz! = null? New ClassPathResource (pathToUse, this.clazz): new ClassPathResource (pathToUse, this.classLoader);} @ Override public String getFilename () {return StringUtils.getFilename (this.path);} @ Override public String getDescription () {StringBuilder builder = new StringBuilder ("class path resource [") String pathToUse = path; if (this.clazz! = null & &! pathToUse.startsWith ("/")) {builder.append (ClassUtils.classPackageAsResourcePath (this.clazz)); builder.append ('/') } if (pathToUse.startsWith ("/")) {pathToUse = pathToUse.substring (1);} builder.append (pathToUse); builder.append (']'); return builder.toString () } @ Override public boolean equals (Object obj) {if (obj = = this) {return true;} if (obj instanceof ClassPathResource) {ClassPathResource otherRes = (ClassPathResource) obj Return (this.path.equals (otherRes.path) & & ObjectUtils.nullSafeEquals (this.classLoader, otherRes.classLoader) & & ObjectUtils.nullSafeEquals (this.clazz, otherRes.clazz);} return false @ Override public int hashCode () {return this.path.hashCode ();}}

Although both ClassPathContextResource and ClassPathRelaticeContextResource inherit from ClassPathResource, there is a difference between the former using ClassLoader to load resources and the latter using Class to load resources:

ClassLoader to load resources, and the path is based on the root of the classpath (such as WEB-INF/classes).

Class comes to shelf resources, which are based on the package path where Class is shrunk (such as Web-INF/classes/com/test/resource/)

1.3 Summary

Resources are abstracted in Spring so as to unify the API of resource operations and shield the differences between different resources. So that other components can not care about the implementation of specific resource types, use a unified API to operate, and define different behaviors of resources through different interfaces, and then give a general implementation in the form of abstract classes. The underlying concrete implementation only needs to inherit this abstract class and override the methods that need special handling with the current resource type. In addition, when defining an interface, a pair of methods (such as isReadable and getInputStream) are given to separate conditional detection and execution logic.

Two ResourceLoader system

The Resource system in Spring only abstracts the resource type and unifies the interface, but if you need to use different types of Resource, you still have to get it through the new specific resource type. In order to simplify the search and loading of Resource in Spring, ResourceLoader is provided to load Resource. Using this, you don't need to care about how to load specific resources, you only need to give the definition of resources (schame), and the rest will be handled by ResourceLoader.

ResourceLoader interface:

Public interface ResourceLoader {/ / ClassPathResource corresponding Url protocol header (prefix) String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; / / get the corresponding Resource object Resource getResource (String location) according to the given resource Url; / / get the ClassLoader ClassLoader getClassLoader () used by the current ResourceLoader;}

From the interface definition, the main behavior of ResourceLoader is getResource operation. The getResource method receives a string type parameter and returns the corresponding Resource object through the parsing and processing of the string parameter, where the location parameter can contain a certain protocol header or prefix to indicate the source information of the parameter.

2.1 DefaultResourceLoader Class

The default implementation, DefaultResourceLoader, can be created using ClassLoader as a parameter. The getResource method is implemented as follows:

Public Resource getResource (String location) {Assert.notNull (location, "Location must not be null"); if (location.startsWith (CLASSPATH_URL_PREFIX)) {/ / classpath: Class or ClassLoader is required for the prefix / / ClassPathResource, where ClassLoader return new ClassPathResource (location.substring (CLASSPATH_URL_PREFIX.length ()), getClassLoader ()) is passed;} else {try {/ / Try to parse the location as a URL... URL url = new URL (location); return new UrlResource (url);} catch (MalformedURLException ex) {/ / No URL-> resolve as resource path. Return getResourceByPath (location); / / if it does not comply with the URL specification, it will be treated as a normal path (such as test/resource.xml)}

For the passed location parameter, it is shown that it determines whether the classpath: prefix is included. If so, the ClassPathResource object is returned. If not, the location parameter is parsed by parsing URL. If the parameter conforms to the URL specification, a UrlResource is created. If the resource contains neither the classpath: special prefix nor the URL form, it is passed to getResourceByPath as a normal resource path for processing:

Protected Resource getResourceByPath (String path) {return new ClassPathContextResource (path, getClassLoader ());} private static class ClassPathContextResource extends ClassPathResource implements ContextResource {public ClassPathContextResource (String path, ClassLoader classLoader) {super (path, classLoader);} public String getPathWithinContext () {return getPath ();} @ Override public Resource createRelative (String relativePath) {String pathToUse = StringUtils.applyRelativePath (getPath (), relativePath); return new ClassPathContextResource (pathToUse, getClassLoader ());}}

GetResourceByPath returns a ClassPathContextResource type, which can actually be ClassPathResource. As you can see, ResourceLoader does not judge whether the resource really exists or can be read or written, but only returns different Resource implementations by parsing out the passed location parameters. Whether the resource exists or is readable needs to be judged by the caller through the method provided by Resource after getting the Resource object.

2.2 ResourcePatternResolver

In addition to providing ResourceLoader, Spring also provides ResourcePatternResolver to extend ResourceLoader. A new prefix: classpath*: has been introduced. The difference with classpath: is that classpath*: can search for all resources under classpath that meet the criteria (including resources with the same name), while classpath: can only return one resource (even if there are multiple).

At this point, the study on "how to understand the Resource and ResourceLoader system in Spring" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report