ioc 统一资源Resource

uml

先来张图看看Resouce接口的继承体系结构。类都来自spirng core包

Resource作为spirng的统一资源抽象接口,在AbstractResource类中提供了默认实现。类结构图中实现不少,都介绍下

  • FileSystemResource

    用来处理java.io.File,支持解析File和URL,并且从5.0版本开始使用NIO2进行读写交互

  • PathResource 用来处理java.nio.file.Path,支持解析File也可以解析URL

  • UrlResource

    作为java.net.URL的定位器,支持解析java.io.File也支持解析URL

  • ClassPathResource 用来处理classpath的资源,用ClassLoader或一个Class来加载资源,支持解析classpath下的java.io.File,也支持URL,但是不支持解析jar中的资源文件。

  • ByteArrayResource

    用来从给定的二进制数组加载内容

  • InputStreamResource

    用来处理给定的InputStream,通常用来处理一些特别的资源,不然最好使用一些专门的Resource,如ClassPathResource

  • VfsResource

    用来处理jboss vfs的资源

Resource接口

下面来看看Resource接口提供的能力,截图有点长,直接复制代码

public interface Resource extends InputStreamSource {

	/**
	 * Determine whether this resource actually exists in physical form.
	 * <p>This method performs a definitive existence check, whereas the
	 * existence of a {@code Resource} handle only guarantees a valid
	 * descriptor handle.
	 *
	 * 检查resource是否真实存在
	 */
	boolean exists();

	/**
	 * Indicate whether the contents of this resource can be read via
	 * {@link #getInputStream()}.
	 * <p>Will be {@code true} for typical resource descriptors;
	 * note that actual content reading may still fail when attempted.
	 * However, a value of {@code false} is a definitive indication
	 * that the resource content cannot be read.
	 * @see #getInputStream()
	 *
	 * resource是否可读取
	 */
	default boolean isReadable() {
		return true;
	}

	/**
	 * Indicate whether this resource represents a handle with an open stream.
	 * If {@code true}, the InputStream cannot be read multiple times,
	 * and must be read and closed to avoid resource leaks.
	 * <p>Will be {@code false} for typical resource descriptors.
	 * 资源代表的句柄是否被一个stream打开了
	 */
	default boolean isOpen() {
		return false;
	}

	/**
	 * Determine whether this resource represents a file in a file system.
	 * A value of {@code true} strongly suggests (but does not guarantee)
	 * that a {@link #getFile()} call will succeed.
	 * <p>This is conservatively {@code false} by default.
	 * @since 5.0
	 * @see #getFile()
	 *
	 * resource是否是一个File
	 */
	default boolean isFile() {
		return false;
	}

	/**
	 * Return a URL handle for this resource.
	 * @throws IOException if the resource cannot be resolved as URL,
	 * i.e. if the resource is not available as descriptor
	 * 返回resource的url的句柄
	 */
	URL getURL() throws IOException;

	/**
	 * Return a URI handle for this resource.
	 * @throws IOException if the resource cannot be resolved as URI,
	 * i.e. if the resource is not available as descriptor
	 * @since 2.5
	 *
	 * 返回resource的URL的句柄
	 */
	URI getURI() throws IOException;

	/**
	 * Return a File handle for this resource.
	 * @throws java.io.FileNotFoundException if the resource cannot be resolved as
	 * absolute file path, i.e. if the resource is not available in a file system
	 * @throws IOException in case of general resolution/reading failures
	 * @see #getInputStream()
	 *
	 * 返回resource的File的句柄
	 */
	File getFile() throws IOException;

	/**
	 * Return a {@link ReadableByteChannel}.
	 * <p>It is expected that each call creates a <i>fresh</i> channel.
	 * <p>The default implementation returns {@link Channels#newChannel(InputStream)}
	 * with the result of {@link #getInputStream()}.
	 * @return the byte channel for the underlying resource (must not be {@code null})
	 * @throws java.io.FileNotFoundException if the underlying resource doesn't exist
	 * @throws IOException if the content channel could not be opened
	 * @since 5.0
	 * @see #getInputStream()
	 *
	 * 返回ReadableByteChannel
	 */
	default ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}

	/**
	 * Determine the content length for this resource.
	 * @throws IOException if the resource cannot be resolved
	 * (in the file system or as some other known physical resource type)
	 *
	 * 返回resource内容的长度
	 */
	long contentLength() throws IOException;

	/**
	 * Determine the last-modified timestamp for this resource.
	 * @throws IOException if the resource cannot be resolved
	 * (in the file system or as some other known physical resource type)
	 *
	 * 返回resource最后修改的时间戳
	 */
	long lastModified() throws IOException;

	/**
	 * Create a resource relative to this resource.
	 * @param relativePath the relative path (relative to this resource)
	 * @return the resource handle for the relative resource
	 * @throws IOException if the relative resource cannot be determined
	 *
	 * 根据resource的相对路径创建新的resource
	 */
	Resource createRelative(String relativePath) throws IOException;

	/**
	 * Determine a filename for this resource, i.e. typically the last
	 * part of the path: for example, "myfile.txt".
	 * <p>Returns {@code null} if this type of resource does not
	 * have a filename.
	 *
	 * 返回resource的文件名
	 */
	@Nullable
	String getFilename();

	/**
	 * Return a description for this resource,
	 * to be used for error output when working with the resource.
	 * <p>Implementations are also encouraged to return this value
	 * from their {@code toString} method.
	 * @see Object#toString()
	 *
	 * 返回resource的描述
	 */
	String getDescription();

}

默认实现AbstractResource

public abstract class AbstractResource implements Resource {

	/**
	 * This implementation checks whether a File can be opened,
	 * falling back to whether an InputStream can be opened.
	 * This will cover both directories and content resources.
	 *
	 * 判断文件是否存在,若产生异常就关闭流
	 */
	@Override
	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 {
				getInputStream().close();
				return true;
			}
			catch (Throwable isEx) {
				return false;
			}
		}
	}

	/**
	 * This implementation always returns {@code true}.
	 *
	 * 默认返回true,表示可读
	 */
	@Override
	public boolean isReadable() {
		return true;
	}

	/**
	 * This implementation always returns {@code false}.
	 *
	 * 默认返回false,表示未被打开
	 */
	@Override
	public boolean isOpen() {
		return false;
	}

	/**
	 * This implementation always returns {@code false}.
	 *
	 * 默认返回false,表示不是 File
	 */
	@Override
	public boolean isFile() {
		return false;
	}

	/**
	 * This implementation throws a FileNotFoundException, assuming
	 * that the resource cannot be resolved to a URL.
	 *
	 * 抛出 FileNotFoundException 异常,交给子类实现
	 */
	@Override
	public URL getURL() throws IOException {
		throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
	}

	/**
	 * This implementation builds a URI based on the URL returned
	 * by {@link #getURL()}.
	 *
	 * 基于 getURL() 返回的url构造URI
	 */
	@Override
	public URI getURI() throws IOException {
		// getURL()默认实现会直接抛出 FileNotFoundException 异常
		URL url = getURL();
		try {
			return ResourceUtils.toURI(url);
		}
		catch (URISyntaxException ex) {
			throw new NestedIOException("Invalid URI [" + url + "]", ex);
		}
	}

	/**
	 * This implementation throws a FileNotFoundException, assuming
	 * that the resource cannot be resolved to an absolute file path.
	 *
	 * 抛出 FileNotFoundException 异常,交给子类实现
	 */
	@Override
	public File getFile() throws IOException {
		throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
	}

	/**
	 * This implementation returns {@link Channels#newChannel(InputStream)}
	 * with the result of {@link #getInputStream()}.
	 * <p>This is the same as in {@link Resource}'s corresponding default method
	 * but mirrored here for efficient JVM-level dispatching in a class hierarchy.
	 *
	 * 通过 getInputStream() 返回的 InputStream 构造 ReadableByteChannel
	 */
	@Override
	public ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}

	/**
	 * This implementation reads the entire InputStream to calculate the
	 * content length. Subclasses will almost always be able to provide
	 * a more optimal version of this, e.g. checking a File length.
	 * @see #getInputStream()
	 *
	 * 获取资源正文长度
	 *
	 * 实际就是资源正文的字节长度,通过循环读取一遍来计算
	 */
	@Override
	public long contentLength() throws IOException {
		InputStream is = getInputStream();
		try {
			long size = 0;
			// 构造一个256长度的字节数字
			byte[] buf = new byte[256];
			int read;
			// 循环读取,每次最多放满数组
			while ((read = is.read(buf)) != -1) {
				// 长度累加
				size += read;
			}
			return size;
		}
		finally {
			try {
				is.close();
			}
			catch (IOException ex) {
			}
		}
	}

	/**
	 * This implementation checks the timestamp of the underlying File,
	 * if available.
	 * @see #getFileForLastModifiedCheck()
	 *
	 * 返回资源的最后修改时间
	 */
	@Override
	public long lastModified() throws IOException {
		// 拿到要获取最后修改时间的资源File
		File fileToCheck = getFileForLastModifiedCheck();
		long lastModified = fileToCheck.lastModified();
		if (lastModified == 0L && !fileToCheck.exists()) {
			throw new FileNotFoundException(getDescription() +
					" cannot be resolved in the file system for checking its last-modified timestamp");
		}
		return lastModified;
	}

	/**
	 * Determine the File to use for timestamp checking.
	 * <p>The default implementation delegates to {@link #getFile()}.
	 * @return the File to use for timestamp checking (never {@code null})
	 * @throws FileNotFoundException if the resource cannot be resolved as
	 * an absolute file path, i.e. is not available in a file system
	 * @throws IOException in case of general resolution/reading failures
	 *
	 * 获取资源File(拿到要获取最后修改时间的资源File)
	 */
	protected File getFileForLastModifiedCheck() throws IOException {
		return getFile();
	}

	/**
	 * This implementation throws a FileNotFoundException, assuming
	 * that relative resources cannot be created for this resource.
	 *
	 * 根据相对路径构造Resource,默认实现抛出 FileNotFoundException 异常,交个子类实现
	 */
	@Override
	public Resource createRelative(String relativePath) throws IOException {
		throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
	}

	/**
	 * This implementation always returns {@code null},
	 * assuming that this resource type does not have a filename.
	 *
	 * 获取资源名称,默认返回null,交给子类实现
	 */
	@Override
	@Nullable
	public String getFilename() {
		return null;
	}


	/**
	 * This implementation compares description strings.
	 * @see #getDescription()
	 */
	@Override
	public boolean equals(Object other) {
		return (this == other || (other instanceof Resource &&
				((Resource) other).getDescription().equals(getDescription())));
	}

	/**
	 * This implementation returns the description's hash code.
	 * @see #getDescription()
	 */
	@Override
	public int hashCode() {
		return getDescription().hashCode();
	}

	/**
	 * This implementation returns the description of this resource.
	 * @see #getDescription()
	 *
	 * 返回资源描述
	 */
	@Override
	public String toString() {
		return getDescription();
	}

}

有没有注意到spring的Resource接口使用了策略模式呢!哈哈,Resource接口的实现类就是具体的策略类,而ApplicationContext就是策略的context。 注意:如果要实现自定义的资源策略,最好是直接继承AbstractResource而不是实现Resource接口(这句话是看别人写的,目前笔者不是很清楚原因-_-!)

转载于:https://my.oschina.net/u/3295680/blog/3068256

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它是一种设计模式,用于解耦和管理对象之间的依赖关系。在传统的编程模式中,对象的创建和依赖关系的管理通常由开发者手动完成,而在Spring IOC中,这些工作由Spring容器来完成。 在Spring IOC中,对象的创建和依赖关系的管理是通过配置文件或注解来实现的。开发者只需要定义好对象的类和依赖关系,然后交给Spring容器来管理。Spring容器会根据配置文件或注解的信息,自动创建对象并解决对象之间的依赖关系。 Spring IOC的主要优点包括: 1. 松耦合:通过IOC容器管理对象之间的依赖关系,减少了对象之间的直接依赖,提高了代码的灵活性和可维护性。 2. 可测试性:由于对象的创建和依赖关系的管理由IOC容器完成,可以方便地进行单元测试和集成测试。 3. 可扩展性:通过配置文件或注解,可以方便地添加、修改和删除对象及其依赖关系,而无需修改代码。 Spring IOC的实现方式有多种,包括XML配置、注解配置和Java配置等。其中,XML配置是最传统也是最常用的方式,通过在XML文件中定义Bean的配置信息来实现IOC。注解配置是一种更简洁和方便的方式,通过在类或方法上添加注解来实现IOCJava配置是一种基于Java代码的配置方式,通过编写Java类来配置Bean和依赖关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值