diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java index de327d7e1c12c590293de656eb85c57e80fd5d10..2bee113bf790026f5aa6843fa73f5a1d8bacb9af 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java @@ -44,6 +44,8 @@ import org.springframework.util.ResourceUtils; * @author Juergen Hoeller * @author Sam Brannen * @since 28.12.2003 + * + * 如果想要自定义Resource类 只需要集成AbstractResource */ public abstract class AbstractResource implements Resource { @@ -51,12 +53,16 @@ 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. + * + * 判断文件是否存在,若判断过程产生异常(因为会调用SecurityManager来判断),就关闭对应的流 */ @Override public boolean exists() { // Try file existence: can we find the file in the file system? + //尝试判断文件是否存在:我们可以在文件系统中找到文件吗? if (isFile()) { try { + //基于File进行判断 return getFile().exists(); } catch (IOException ex) { @@ -67,6 +73,7 @@ public abstract class AbstractResource implements Resource { } } // Fall back to stream existence: can we open the stream? + // 判断流是否存在 基于inputStream判断 try { getInputStream().close(); return true; @@ -83,6 +90,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation always returns {@code true} for a resource * that {@link #exists() exists} (revised as of 5.1). + * + * 判断文件是否可读 如果文件存在 则可读 */ @Override public boolean isReadable() { @@ -91,6 +100,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation always returns {@code false}. + * + * 直接返回false 表示未打开 */ @Override public boolean isOpen() { @@ -99,6 +110,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation always returns {@code false}. + * + * 总是返回false 表示不是File */ @Override public boolean isFile() { @@ -108,6 +121,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation throws a FileNotFoundException, assuming * that the resource cannot be resolved to a URL. + * + * 抛出 FileNotFoundException 异常,交给子类实现 */ @Override public URL getURL() throws IOException { @@ -117,6 +132,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation builds a URI based on the URL returned * by {@link #getURL()}. + * + * 基于GetUrl返回的Url构建 Uri */ @Override public URI getURI() throws IOException { @@ -132,6 +149,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation throws a FileNotFoundException, assuming * that the resource cannot be resolved to an absolute file path. + * + * 抛出 FileNotFoundException 异常,交给子类实现 */ @Override public File getFile() throws IOException { @@ -143,6 +162,8 @@ public abstract class AbstractResource implements Resource { * with the result of {@link #getInputStream()}. *
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() 的返回结果构建 ReadableByteChannel */ @Override public ReadableByteChannel readableChannel() throws IOException { @@ -156,12 +177,16 @@ public abstract class AbstractResource implements Resource { * checking File length, or possibly simply returning -1 if the stream can * only be read once. * @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) { @@ -186,10 +211,14 @@ public abstract class AbstractResource implements Resource { * This implementation checks the timestamp of the underlying File, * if available. * @see #getFileForLastModifiedCheck() + * + * 返回资源最后一次修改时间 */ @Override public long lastModified() throws IOException { + //获取到文件 File fileToCheck = getFileForLastModifiedCheck(); + //获取最后一次修改时间 long lastModified = fileToCheck.lastModified(); if (lastModified == 0L && !fileToCheck.exists()) { throw new FileNotFoundException(getDescription() + @@ -205,6 +234,8 @@ public abstract class AbstractResource implements Resource { * @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 + * + * 通过getFile 获取文件 最后一次检查 */ protected File getFileForLastModifiedCheck() throws IOException { return getFile(); @@ -213,6 +244,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation throws a FileNotFoundException, assuming * that relative resources cannot be created for this resource. + * + * 抛出 FileNotFoundException 异常,交给子类实现 */ @Override public Resource createRelative(String relativePath) throws IOException { @@ -222,6 +255,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation always returns {@code null}, * assuming that this resource type does not have a filename. + * + * 获取资源名称,默认返回 null ,交给子类实现 */ @Override @Nullable @@ -233,6 +268,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation compares description strings. * @see #getDescription() + * + * 如果对象相等 或者 属于Resource类 并且描述一致 */ @Override public boolean equals(@Nullable Object other) { @@ -252,6 +289,8 @@ public abstract class AbstractResource implements Resource { /** * This implementation returns the description of this resource. * @see #getDescription() + * + * 返回资源的描述 */ @Override public String toString() { diff --git a/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java b/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java index c5989b8330dcdd7fd6b96d3e4c6b319a23437df0..84dbc4f2784749aee669b941b69a399e7f691d23 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ByteArrayResource.java @@ -39,6 +39,8 @@ import org.springframework.util.Assert; * @see java.io.ByteArrayInputStream * @see InputStreamResource * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource) + * + * 对字节数组提供的数据的封装。如果通过 InputStream 形式访问该类型的资源,该实现会根据字节数组的数据构造一个相应的 ByteArrayInputStream。 */ public class ByteArrayResource extends AbstractResource { diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java index 2ba871bbc1e80ad693f562eb831904964efc23b8..b955bf4a4ecddb3a034ef34fc54df45517e6e02c 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java @@ -40,6 +40,8 @@ import org.springframework.util.StringUtils; * @since 28.12.2003 * @see ClassLoader#getResourceAsStream(String) * @see Class#getResourceAsStream(String) + * + * ClassPathResource :class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源。 */ public class ClassPathResource extends AbstractFileResolvingResource { diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java index ddda6d4e120d9f8607789346e954af109ea78d11..d3a753f42e50139b474ed064d3a7d38934280b5b 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java @@ -27,6 +27,8 @@ import org.springframework.util.StringUtils; * @since 3.0 * @see Class#getResource(String) * @see ClassPathResource#ClassPathResource(String, Class) + * + * 实现将普通资源路径解释为相对于给定的java.lang.Class */ public class ClassRelativeResourceLoader extends DefaultResourceLoader { diff --git a/spring-core/src/main/java/org/springframework/core/io/ContextResource.java b/spring-core/src/main/java/org/springframework/core/io/ContextResource.java index 30f75e00c334033fad78a816b712812310374e94..3d5a4222d42fcca0e81b7711c0e6ad0743c49b28 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ContextResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ContextResource.java @@ -33,6 +33,8 @@ public interface ContextResource extends Resource { * Return the path within the enclosing 'context'. *
This is typically path relative to a context-specific root directory,
* e.g. a ServletContext root or a PortletContext root.
+ *
+ * 返回封闭的上下文环境 目的就是为了保存上下文环境
*/
String getPathWithinContext();
diff --git a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java
index 27ed3bf1a088a2b147a3abce917e6998596c6dd6..0a206d0f6d1188925f5eb5a0a896a79cd5d92373 100644
--- a/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java
+++ b/spring-core/src/main/java/org/springframework/core/io/DefaultResourceLoader.java
@@ -44,6 +44,8 @@ import org.springframework.util.StringUtils;
* @since 10.03.2004
* @see FileSystemResourceLoader
* @see org.springframework.context.support.ClassPathXmlApplicationContext
+ *
+ * 资源加载器的默认实现
*/
public class DefaultResourceLoader implements ResourceLoader {
@@ -69,6 +71,8 @@ public class DefaultResourceLoader implements ResourceLoader {
* Create a new DefaultResourceLoader.
* @param classLoader the ClassLoader to load class path resources with, or {@code null}
* for using the thread context class loader at the time of actual resource access
+ *
+ * 接受classload 作为参数
*/
public DefaultResourceLoader(@Nullable ClassLoader classLoader) {
this.classLoader = classLoader;
@@ -104,6 +108,10 @@ public class DefaultResourceLoader implements ResourceLoader {
* resolution rules. It may therefore also override any default rules.
* @since 4.3
* @see #getProtocolResolvers()
+ *
+ * 添加用户自定义协议
+ * DefaultResourceLoader 的spi 允许用户自定义加载协议 而不需要继承classLoader
+ *
*/
public void addProtocolResolver(ProtocolResolver resolver) {
Assert.notNull(resolver, "ProtocolResolver must not be null");
@@ -114,6 +122,8 @@ public class DefaultResourceLoader implements ResourceLoader {
* Return the collection of currently registered protocol resolvers,
* allowing for introspection as well as modification.
* @since 4.3
+ *
+ * 获取用户自定义策略
*/
public Collection This method performs a definitive existence check, whereas the
* existence of a {@code Resource} handle only guarantees a valid
* descriptor handle.
+ *
+ * 资源是否存在
*/
boolean exists();
@@ -69,6 +71,8 @@ public interface Resource extends InputStreamSource {
* that the resource content cannot be read.
* @see #getInputStream()
* @see #exists()
+ *
+ * 资源是否可读
*/
default boolean isReadable() {
return exists();
@@ -79,6 +83,9 @@ public interface Resource extends InputStreamSource {
* If {@code true}, the InputStream cannot be read multiple times,
* and must be read and closed to avoid resource leaks.
* Will be {@code false} for typical resource descriptors.
+ *
+ * 资源所代表的句柄 是否被一个steam资源打开
+ *
*/
default boolean isOpen() {
return false;
@@ -91,6 +98,8 @@ public interface Resource extends InputStreamSource {
* This is conservatively {@code false} by default.
* @since 5.0
* @see #getFile()
+ *
+ * 是否是File
*/
default boolean isFile() {
return false;
@@ -100,6 +109,8 @@ public interface Resource extends InputStreamSource {
* 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
+ *
+ * 返回资源的uri的句柄
*/
URL getURL() throws IOException;
@@ -108,6 +119,8 @@ public interface Resource extends InputStreamSource {
* @throws IOException if the resource cannot be resolved as URI,
* i.e. if the resource is not available as descriptor
* @since 2.5
+ *
+ * 回资源的uri的句柄
*/
URI getURI() throws IOException;
@@ -117,6 +130,8 @@ public interface Resource extends InputStreamSource {
* 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()
+ *
+ * 返回资源的File的句柄
*/
File getFile() throws IOException;
@@ -130,6 +145,9 @@ public interface Resource extends InputStreamSource {
* @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());
@@ -139,6 +157,8 @@ public interface Resource extends InputStreamSource {
* 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)
+ *
+ * 资源内容的长度
*/
long contentLength() throws IOException;
@@ -146,6 +166,8 @@ public interface Resource extends InputStreamSource {
* 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)
+ *
+ * 资源最后的修改时间
*/
long lastModified() throws IOException;
@@ -154,6 +176,8 @@ public interface Resource extends InputStreamSource {
* @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 createRelative(String relativePath) throws IOException;
@@ -162,6 +186,8 @@ public interface Resource extends InputStreamSource {
* part of the path: for example, "myfile.txt".
* Returns {@code null} if this type of resource does not
* have a filename.
+ *
+ * 资源的文件名
*/
@Nullable
String getFilename();
@@ -172,6 +198,8 @@ public interface Resource extends InputStreamSource {
* Implementations are also encouraged to return this value
* from their {@code toString} method.
* @see Object#toString()
+ *
+ * 资源的描述
*/
String getDescription();
diff --git a/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java b/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java
index f66befdd547d2f879e92b8c39cd034873dfa9216..4799cfc9d5dd1796c2c5abee31e826e43b8d20eb 100644
--- a/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java
+++ b/spring-core/src/main/java/org/springframework/core/io/ResourceLoader.java
@@ -38,10 +38,13 @@ import org.springframework.util.ResourceUtils;
* @see org.springframework.core.io.support.ResourcePatternResolver
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.ResourceLoaderAware
+ *
+ * 资源的加载则由 ResourceLoader 来统一定义。
*/
public interface ResourceLoader {
/** Pseudo URL prefix for loading from the class path: "classpath:". */
+ /** ClassPath url 的前缀 classpath:**/
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
@@ -63,6 +66,13 @@ public interface ResourceLoader {
* @see #CLASSPATH_URL_PREFIX
* @see Resource#exists()
* @see Resource#getInputStream()
+ *
+ * 根据所提供的的路径location 返回Resource实力 但他不一定保证资源存在所以需要调用exist判断资源
+ * 支持以下类型资源加载
+ * file:C:/test.dat
+ * classpath:test.dat
+ * WEB-INF/test.dat
+ * 这个过程主要是通过默认的DefaultResourceLoader实现的
*/
Resource getResource(String location);
@@ -75,6 +85,9 @@ public interface ResourceLoader {
* (only {@code null} if even the system {@code ClassLoader} isn't accessible)
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
* @see org.springframework.util.ClassUtils#forName(String, ClassLoader)
+ *
+ * 返回classLoader实力,对于想要获取clasloder的ResourceLoader
+ * 比如 ClasspathResource 主要是使用 classloader 加载指定资源
*/
@Nullable
ClassLoader getClassLoader();
diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
index 3f1dcc05ffe477de6b3175dcb497464508aa1dea..6dd1fc8a975f7c6f0940afe60150c7cc4322727a 100644
--- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
+++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java
@@ -39,6 +39,8 @@ import org.springframework.util.StringUtils;
* @author Juergen Hoeller
* @since 28.12.2003
* @see java.net.URL
+ *
+ * 对 java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作。
*/
public class UrlResource extends AbstractFileResolvingResource {
diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
index aef2476b0a55948d2724552502714706915e64dd..673b3af91384dd0b411a90e6210c39a8bfd8811b 100644
--- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
+++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
@@ -201,8 +201,14 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
}
+ /**
+ * 内置的 ResourceLoader 资源定位器
+ */
private final ResourceLoader resourceLoader;
+ /**
+ * 默认为 AntPathMatcher 对象,用于支持 Ant 类型的路径匹配。
+ */
private PathMatcher pathMatcher = new AntPathMatcher();
@@ -212,6 +218,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
* @see org.springframework.core.io.DefaultResourceLoader
*/
public PathMatchingResourcePatternResolver() {
+ //默认使用DefaultResourceLoader为资源解析器
this.resourceLoader = new DefaultResourceLoader();
}
@@ -277,28 +284,35 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
@Override
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
+ //如果以 classpath*: 开头
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
+ //路径包含通配符
// a class path resource (multiple resources for same name possible)
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
+ //路径不包含通配符
else {
// all class path resources with the given name
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
+ //不以 classpath*: 开头
else {
- // Generally only look for a pattern after a prefix here,
- // and on Tomcat only after the "*/" separator for its "war:" protocol.
+ // Generally only look for a pattern after a prefix here, 一般只在此处查找前缀后的模式
+ // and on Tomcat only after the "*/" separator for its "war:" protocol. 而在 Tomcat 上只有在 “*/ ”分隔符之后才为其 “war:” 协议
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
+ //路径包含通配符
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
+ //路径不包含通配符
else {
// a single resource with the given name
+ //则直接交给默认的ResourceLoader 进行加载
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
@@ -315,13 +329,16 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
*/
protected Resource[] findAllClassPathResources(String location) throws IOException {
String path = location;
+ //去除开头的/
if (path.startsWith("/")) {
path = path.substring(1);
}
+ //执行加载所有的classpath资源
Set