SpringIOC源码阅读笔记(1)

刚看完springMVC的源码,感觉spring的容器源码还是掌握不到位,所以打算写一点笔记再理一遍思路。

一.Resource

spring给资源提供了封装,根据不同的资源类型有不同的实现类,首先先看下UML图:
在这里插入图片描述
1.org.springframework.core.io.InputStreamSource
顶层接口,其中就定义了一个方法获取输入流:
InputStream getInputStream() throws IOException
2.org.springframework.core.io.Resource
Spring 框架所有资源的抽象和访问接口,定义了一些通用的方法。

public interface Resource extends InputStreamSource {
	//资源是否存在
	boolean exists();
	//资源是否可读
	default boolean isReadable() {
		return true;
	}
	 // 资源所代表的句柄是否被一个 stream 打开了
	default boolean isOpen() {
		return false;
	}
	 // 是否为 File
	default boolean isFile() {
		return false;
	}
	 //返回资源的 URL 的句柄
	URL getURL() throws IOException;
	 // 返回资源的 URI 的句柄
	URI getURI() throws IOException;
	// 返回资源的 File 的句柄
	File getFile() throws IOException;
	//返回 ReadableByteChannel
	default ReadableByteChannel readableChannel() throws IOException {
		return java.nio.channels.Channels.newChannel(getInputStream());
	}
	 //资源内容的长度
	long contentLength() throws IOException;
	 // 资源最后的修改时间
	long lastModified() throws IOException;
	 // 根据资源的相对路径创建新资源
	Resource createRelative(String relativePath) throws IOException;
	 // 资源的文件名
	@Nullable
	String getFilename();
	 //资源的描述
	String getDescription();
}

3.org.springframework.core.io.AbstractResource,是Resource接口的默认抽象实现:

public abstract class AbstractResource implements Resource {
	@Override
	public boolean exists() {
		try {
		//基于File进行判断
			return getFile().exists();
		}
		catch (IOException ex) {
			try {
			//基于inputStream进行判断
				InputStream is = getInputStream();
				is.close();
				return true;
			}
			catch (Throwable isEx) {
				return false;
			}
		}
	}
	//表示可读
	@Override
	public boolean isReadable() {
		return true;
	}
	//没有被打开
	@Override
	public boolean isOpen() {
		return false;
	}
	//不是File
	@Override
	public boolean isFile() {
		return false;
	}
	//抛出 FileNotFoundException 异常,交给子类实现
	@Override
	public URL getURL() throws IOException {
		throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
	}
	//基于 getURL() 返回的 URL 构建 URI
	@Override
	public URI getURI() throws IOException {
		URL url = getURL();
		try {
			return ResourceUtils.toURI(url);
		}
		catch (URISyntaxException ex) {
			throw new NestedIOException("Invalid URI [" + url + "]", ex);
		}
	}
	//不是File,自然不能返回File
	@Override
	public File getFile() throws IOException {
		throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
	}
	//根据 getInputStream() 的返回结果构建 ReadableByteChannel
	@Override
	public ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}
	//这个资源内容长度实际就是资源的字节长度
	@Override
	public long contentLength() throws IOException {
		InputStream is = getInputStream();
		try {
			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) {
			}
		}
	}

	//返回资源的最后修改时间
	@Override
	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();
	}
	//子类实现相对路径
	@Override
	public Resource createRelative(String relativePath) throws IOException {
		throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
	}
	//得到文件名
	@Override
	@Nullable
	public String getFilename() {
		return null;
	}

	@Override
	public String toString() {
		return getDescription();
	}

	//资源的描述相同也可以成立
	@Override
	public boolean equals(Object obj) {
		return (obj == this ||
			(obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
	}
	@Override
	public int hashCode() {
		return getDescription().hashCode();
	}

}

其余子类就不分析了,大同小异。

二.ResourceLoader

在这里插入图片描述
1.资源的加载都是通过ResourceLoader来完成的:

public interface ResourceLoader {
//classpath前缀,默认是“classpath:”
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
	//根据路径获取资源:URL位置资源、ClassPath位置资源、相对路径资源等,主要实现是在DefaultResourceLoader
	Resource getResource(String location);
	//返回 ClassLoader 实例,对于想要获取 ResourceLoader 使用的 ClassLoader 用户来说,可以直接调用该方法来获取。
	@Nullable
	ClassLoader getClassLoader();

}

2、DefaultResourceLoader

public class DefaultResourceLoader implements ResourceLoader {

	@Nullable
	private ClassLoader classLoader;
	//用户自定义协议资源解决策略
	private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet<>(4);
	//资源缓存
	private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);

	//默认的无参构造
	public DefaultResourceLoader() {
		this.classLoader = ClassUtils.getDefaultClassLoader();
	}
//传入构造函数classLoader
	public DefaultResourceLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
	public void setClassLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
	@Override
	@Nullable
	public ClassLoader getClassLoader() {
		return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
	}

	public void addProtocolResolver(ProtocolResolver resolver) {
		Assert.notNull(resolver, "ProtocolResolver must not be null");
		this.protocolResolvers.add(resolver);
	}

	/**
	 * Return the collection of currently registered protocol resolvers,
	 * allowing for introspection as well as modification.
	 * @since 4.3
	 */
	public Collection<ProtocolResolver> getProtocolResolvers() {
		return this.protocolResolvers;
	}

	/**
	 * Obtain a cache for the given value type, keyed by {@link Resource}.
	 * @param valueType the value type, e.g. an ASM {@code MetadataReader}
	 * @return the cache {@link Map}, shared at the {@code ResourceLoader} level
	 * @since 5.0
	 */
	@SuppressWarnings("unchecked")
	public <T> Map<Resource, T> getResourceCache(Class<T> valueType) {
		return (Map<Resource, T>) this.resourceCaches.computeIfAbsent(valueType, key -> new ConcurrentHashMap<>());
	}

	/**
	 * Clear all resource caches in this resource loader.
	 * @since 5.0
	 * @see #getResourceCache
	 */
	public void clearResourceCaches() {
		this.resourceCaches.clear();
	}

	@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		//首先,通过 ProtocolResolver 来加载资源,这个类就是自定义的解析方法,自己定义location与资源的对应关系
		for (ProtocolResolver protocolResolver : this.protocolResolvers) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}
		//如果路径是以“/”开始的,返回ClassPathContextResource(DefaultResourceLoader的内部类,继承了ClassPathResource)
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		//如果是以“classpath:”开头的,返回 ClassPathResource 类型的资源
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// 根据是否为文件 URL ,是则返回 FileUrlResource 类型的资源,否则返回 UrlResource 类型的资源
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}
	protected Resource getResourceByPath(String path) {
	//构造 ClassPathContextResource 类型资源并返回
		return new ClassPathContextResource(path, getClassLoader());
	}

	protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

		public ClassPathContextResource(String path, @Nullable ClassLoader classLoader) {
			super(path, classLoader);
		}
		//重写ContextResource接口方法
		@Override
		public String getPathWithinContext() {
			return getPath();
		}

		@Override
		public Resource createRelative(String relativePath) {
			String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
			return new ClassPathContextResource(pathToUse, getClassLoader());
		}
	}

}

3.FileSystemResourceLoader

public class FileSystemResourceLoader extends DefaultResourceLoader {
	@Override
	//在DefaultResourceLoader中,这个方法直接返回创建ClassPathContextResource,在这个类中重写了该方法,可以得到我们想要的资源类型
	protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemContextResource(path);
	}

	private static class FileSystemContextResource extends FileSystemResource implements ContextResource {

		public FileSystemContextResource(String path) {
			super(path);
		}

		@Override
		public String getPathWithinContext() {
			return getPath();
		}
	}
}

4.ClassRelativeResourceLoader

//可以根据给定的class 所在包或者所在包的子包下加载资源。
public class ClassRelativeResourceLoader extends DefaultResourceLoader {

	private final Class<?> clazz;
	public ClassRelativeResourceLoader(Class<?> clazz) {
		Assert.notNull(clazz, "Class must not be null");
		this.clazz = clazz;
		setClassLoader(clazz.getClassLoader());
	}

	@Override
	protected Resource getResourceByPath(String path) {
		return new ClassRelativeContextResource(path, this.clazz);
	}


	/**
	 * ClassPathResource that explicitly expresses a context-relative path
	 * through implementing the ContextResource interface.
	 */
	private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource {

		private final Class<?> clazz;

		public ClassRelativeContextResource(String path, Class<?> clazz) {
			super(path, clazz);
			this.clazz = clazz;
		}

		@Override
		public String getPathWithinContext() {
			return getPath();
		}

		@Override
		public Resource createRelative(String relativePath) {
			String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
			return new ClassRelativeContextResource(pathToUse, this.clazz);
		}
	}

}

5.ResourcePatternResolver

//它支持根据指定的资源路径匹配模式每次返回多个 Resource 实例
public interface ResourcePatternResolver extends ResourceLoader {
	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
	Resource[] getResources(String locationPattern) throws IOException;
}

6.PathMatchingResourcePatternResolver

//内置的资源加载器
	private final ResourceLoader resourceLoader;
//Ant路径匹配器
	private PathMatcher pathMatcher = new AntPathMatcher();
	//默认构造
	public PathMatchingResourcePatternResolver() {
	this.resourceLoader = new DefaultResourceLoader();
}
//传入资源定位器
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
	Assert.notNull(resourceLoader, "ResourceLoader must not be null");
	this.resourceLoader = resourceLoader;
}
//传入类加载器
public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {
	this.resourceLoader = new DefaultResourceLoader(classLoader);

@Override
//委托给指定的资源定位器
public Resource getResource(String location) {
	return getResourceLoader().getResource(location);
}

public ResourceLoader getResourceLoader() {
	return this.resourceLoader;
}
@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)) {
        // 路径包含通配符
        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. 而在 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
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
        }
    }
}
其余方法不做分析,综上主要讲的是Spring中资源以及资源的定位器。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值