In this paper, the content

  1. ResourceInterface Definition
  2. ResourceA built-in implementation of the interface
  3. ResourceLoaderinterface
  4. ResourceLoaderAwareinterface

Definition of the Resource interface

Java’s standard java.net.URL class and standard handlers for various URL prefixes are not sufficient for all access to low-level resources. For example, there is no standardized URL implementation for accessing resources that need to be retrieved from the classpath or relative to the ServletContext. While it is possible to register new handlers for specialized URL prefixes (similar to existing prefix handlers such as HTTP :), this is usually quite complex, and the URL interface still lacks some desirable features, such as checking for the presence of a resource to which the method points.

To address this situation, Spring provides a more powerful interface, Resource, for abstract access to low-level resources, whose definition and main interface methods are described below.

package org.springframework.core.io;

public interface Resource extends InputStreamSource {

	// Whether the specific resource exists
	boolean exists(a);

    // Non-empty content can be read with #getInputStream()
	default boolean isReadable(a) {
		return exists();
	}

    // Check whether the InputStream corresponding to the resource has been opened. It cannot be read multiple times. Close the stream after reading to avoid resource leakage
	default boolean isOpen(a) {
		return false;
	}

    #getFile()
	default boolean isFile(a) {
		return false;
	}

	/ / get the URL
	URL getURL(a) throws IOException;

	/ / get a URI
	URI getURI(a) throws IOException;

	/ / get the File
	File getFile(a) throws IOException;

	// The length of the resource content
	long contentLength(a) throws IOException;

	// Last modified timestamp
	long lastModified(a) throws IOException;

	// Create a resource at the given path
	Resource createRelative(String relativePath) throws IOException;

	// The file name is not the full path
	@Nullable
	String getFilename(a);

	// Get the resource description
	String getDescription(a);

}
Copy the code

The Resource interface inherits InputStreamSource, as defined below.

package org.springframework.core.io;

public interface InputStreamSource {
	// Get the InputStream of the resource
	InputStream getInputStream(a) throws IOException;
}
Copy the code

The Resource interface is not intended to completely replace java.net.URL, but rather to wrap the URL as much as possible with its implementation classes, such as UrlResource wrapping a URL and using the wrapped URL to perform its functions. See the built-in implementation in the next section.

A built-in implementation of the Resource interface

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • ServletContextResource
  • InputStreamResource
  • ByteArrayResource

UrlResource

UrlResource wraps java.net.URL and can be used to access any object that is normally accessible through a URL, such as a file, HTTP target, FTP target, and so on. These resources are distinguished by standard prefixes: file: used to access the file system path, HTTP: used to access resources through HTTP, FTP: used to access resources through FTP, etc.

ClassPathResource

ClassPathResource indicates the resource that should be retrieved from the classpath. It uses a thread-context class loader, a given class loader, or a given class to load resources. This resource can be specified with the specific prefix CLASspath:.

If the classpath Resource resides in a File system, the Resource implementation supports resolution to java.io.File, but does not support classpath resources that are in jar packages and have not been unextracted.

FileSystemResource

This is the resource implementation of the java.io.File and java.nio.file.Path handles. It supports parsing as files and urls.

ServletContextResource

This is the Resource implementation of the ServletContext Resource, which explains the relative paths in the root directory of the relevant Web application.

It always supports stream access and URL access, but only allows java.io.file access if the Web application archive is extended and the resources are physically located on the File system. Whether it is decompressed and accessed on the file system or directly from a JAR or elsewhere (such as a database) really depends on the Servlet container.

ByteArrayResource

Resource implementation for a given byte array. It creates a ByteArrayInputStream for the given byte array. Useful for loading content from any given byte array without having to resort to single-use InputStreamResource.

InputStreamResource

InputStreamResource is the resource implementation of a given InputStream. Preferred ByteArrayResource or any file-based Resource implementation, which should only be used if no specific Resource implementation is available.

Compared to other Resource implementations, this is a descriptor for an open Resource, and the interface isOpen() returns true. Do not use the resource descriptor if you need to save it somewhere or if you need to read the stream multiple times.

ResourceLoaderinterface

ResourceLoader Policy interface for loading resources, such as classpath or file system resources.

package org.springframework.core.io;

public interface ResourceLoader {

	/** Pseudo URL prefix for loading from the class path: "classpath:". */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;


    // Returns the resource handle for the specified resource location
	Resource getResource(String location);
	
    / / for this
    // Clients that need to access the ClassLoader directly can access the ClassLoader in a unified manner through ResourceLoader, rather than relying on the following ClassLoader on the thread.
	@Nullable
	ClassLoader getClassLoader(a);

}

Copy the code

Source code for the description:

  • Handles should always be reusable Resource descriptors, allowing multiple resource-.getinputStream () calls.
  • Fully qualified urls must be supported, such as”File: C: / test. Dat“.
  • Classpath pseudo-urls must be supported, such as”classpath:test.dat“.
  • Relative file paths should be supported, such as”WEB-INF/test.dat“. (This will be implementation-specific, usually byApplicationContextImplementation provides.)
  • Resource handles do not imply existing resources; You need to callResource.exists()To check for presence.

All org. Springframework. Context. ApplicationContext must implement the ResourceLoader interface. The type of value returned by calling the getResource() interface depends on the type of the current context, which is automatically converted. Here’s an example.

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
Copy the code

Such as CTX is ClassPathXmlApplicationContext returned ClassPathResource;

Such as CTX is FileSystemXmlApplicationContext returned FileSystemResource;

Return ServletContextResource if CTX is WebApplicationContext

If you do not want to rely on the context type to determine the type of resource to be returned, you can specify a prefix to force a specific type of resource to be returned. Here’s an example.

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
/ / return ClassPathResource
Copy the code
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
/ / return UrlResource
Copy the code

The following table describes the impact of a specified prefix on the loading mode and return of resources.

The prefix example How to parse
classpath: classpath:com/myapp/config.xml Load from the classpath
file: `file:///data/config.xml As from the file systemURLloading
http: https://myserver/logo.png As from the file systemURLloading
(none) /data/config.xml Depends on the underlyingApplicationContext

ResourceLoaderAwareinterface

The ResourceLoaderAware interface is a special callback interface that identifies components that are expected to provide ResourceLoader references. Its definition is as follows.

package org.springframework.context;

public interface ResourceLoaderAware extends Aware {
    // Save a custom ResourceLoader reference for resource loading
	void setResourceLoader(ResourceLoader resourceLoader);
}
Copy the code

Due to org. Springframework. Context. Realized the ResourceLoader ApplicationContext, So beans can also implement the ApplicationContextAware interface and load resources directly using the provided application context. From the interface oriented programming and decoupling point of view, need ResourceLoader to load resources, more recommended to implement ‘ ‘ResourceLoaderAware interface.

If a bean in a container needs a ResourceLoader dependency to load resources, is there another way to implement ResourceLoaderAware?

The ResourceLoader instance is automatically injected into the IoC container. We can inject this dependency directly through constructors, setter methods, @autowire annotations, etc. See the previous IoC article for details.

Configuration file asResourceInjection into bean dependencies

If a bean depends on a particular Resource, how do we inject that dependency quickly and elegantly? Go straight to the code.

public class MyConfig {
    /** * Resources injected through the configuration file */
    private Resource template;

    public Resource getTemplate(a) {
        return template;
    }

    public void setTemplate(Resource template) {
        this.template = templa
    }
}
Copy the code

MyConfig depends on a configuration file in a class file path.

The corresponding XML file spring. XML and configuration file db.properties are as follows:


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myConfig" class="com.crab.spring.ioc.demo02.MyConfig">
        <property name="template" value="db.properties"></property>
    </bean>
</beans>
Copy the code
url=jdbc:mysql://localhost/test
username=root
password=456
max=1024
Copy the code

Run the main program as follows:

package com.crab.spring.ioc.demo02;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class ResourceTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring" +
                ".xml");
        MyConfig myConfig = context.getBean(MyConfig.class);
        Resource template = myConfig.getTemplate();
        System.out.println(template);
        System.out.println(template instanceofClassPathResource); }}Copy the code

Running results:

class path resource [db.properties]
true
class path resource [db.properties]
Copy the code
  • Successfully injectedResoureceResources toMyConfigThe bean
  • injectionResourceWe actually passClassPathXmlApplicationContextThe loadedClassPathResource

Extension: In conjunction with the relationship between resource-specific prefixes and ApplicationContext in the previous article, please check that we can also specify prefixes to load specific resources. I’m not going to show you the simple ones.

    <bean id="myConfig" class="com.crab.spring.ioc.demo02.MyConfig">
        <property name="template" value="classpath:db.properties"></property>
    </bean>file:///some/resource/path
Copy the code
    <bean id="myConfig" class="com.crab.spring.ioc.demo02.MyConfig">
        <property name="template" value="file:///some/resource/path"></property>
    </bean>
// 注入的是FileSystemResource
Copy the code

Use the resource path to configure the application context

To review, in the ResourceLoader section, we analyzed the effect of specifying resource path prefixes on the way resources are loaded, as shown in the following table. The following describes how to configure the application context with or without the prefix.

The prefix example How to parse
classpath: classpath:com/myapp/config.xml Load from the classpath
file: `file:///data/config.xml As from the file systemURLloading
http: https://myserver/logo.png As from the file systemURLloading
(none) /data/config.xml Depends on the underlyingApplicationContext
The resource path does not have a prefix
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");		
Copy the code

The above case resource path without a prefix, ClassPathXmlApplicationContext ClassPathResource loading will be used in the classpath resource file. Let’s do another example.

ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");
Copy the code

FileSystemXmlApplicationContext URLResouce will be used to load the file system in the configuration file, this case is a relative path.

The resource path is prefixed

When a Resource prefix is specified, the Resource corresponding to the specified prefix is used to load the Resource. Here’s an example.

ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
Copy the code

In contrast to the previous example, you will use the ClassPathResource to load the resource file under the classpath.

Resource paths are prefixed and wildcard characters

Specify a single resource file using the previous two methods. If you need to specify multiple resources, you can use wildcards and support ant-style and classpath*.

  1. Ant – style wildcards

    /WEB-INF/*-context.xml
    com/mycompany/**/applicationContext.xml
    file:C:/some/path/*-context.xml
    classpath:com/mycompany/**/applicationContext.xml
    Copy the code

    When using an ant-style wildcard, the parser follows a more complex process to try to resolve the wildcard. It generates a resource for the path up to the last non-wildcard segment and takes a URL from it. It generates a resource for the path up to the last non-wildcard segment and takes a URL from it.

    The path of the last non-wildcard segment is handled in two cases:

    • Generate java.io.File, such as classpath:com/mycompany/**/applicationContext. XML to classpath:com/ myCompany and traverse.

    • Special file jars: Path: As the classpath: com/mycompany / * * / applicationContext. XML, take to the classpath: com/mycompany, will generate java.net.JarURLConnection, Or manually parse the JAR URL and traverse the contents of the JAR file to parse the wildcards.

      Using JAR urls is strongly recommended for testing whether resources are normally accessed through wildcards

  2. The classpath * prefix

    The following case

    ApplicationContext ctx =
        new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
    Copy the code

    All resources that match conf/ AppContext.xml in the traversal classpath are loaded.

  3. The two methods can be used in combination

    As the classpath * : meta-inf / * – beans. XML

    The resolution strategy is fairly simple: use a classLoader.getResources () call on the last non-wildcard path segment to get all the matching resources in the ClassLoader hierarchy, and then for each resource, the PathMatcher resolution strategy is used for wildcard subpaths. If you’re interested, take a look at the PathMatcher class.

    Please note that 2 places that are easy to drop pits are used in combination:

    • classpath*:*.xml

      Files may not be retrieved from the root of the JAR file under the classpath, but only from the root of the extension directory.

    • classpath:com/mycompany/**/service-context.xml

      If the root package to be searched is available in more than one classpath location, there is no guarantee that the resource will find a match. Use ClassLoader#getResource(com/mycompany/) if multiple paths have it, then only the first one may be returned and the others may be missed. The safe way to do this is classpath*:com/mycompany/**/service-context.xml

eggs

For backward compatibility of historical reasons, FileSystemXmlApplicationContext associated FileSystemResource will all the resources of the prefix path unity as a relative path. In the case

// The two ways are the same
ApplicationContext ctx =new FileSystemXmlApplicationContext("conf/context.xml");
ApplicationContext ctx =new FileSystemXmlApplicationContext("/conf/context.xml");
// The two ways are the same
ctx.getResource("some/resource/path/myTemplate.txt");
ctx.getResource("/some/resource/path/myTemplate.txt");
// You can force the relative path not to be processed. Press URLResource processing
ctx = new FileSystemXmlApplicationContext("file:///conf/context.xml");

Copy the code

conclusion

This paper mainly describes in detail

  1. ResourceInterface definition and method description
  2. ResourceSix built-in implementations of the interface
  3. ResourceLoaderInterfaces and implementations
  4. ResourceLoaderAwareInterface to use
  5. How to useResourceconfigurationApplicationContext

In this article, basic Spring is generally clear about resource handling and related interfaces.

Knowledge sharing, reproduced please indicate the source. Learning has no priority, the first!