【spring-core】DefaultResourceLoader

package org.springframework.core.io;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * {@link ResourceLoader}接口的默认实现。
 *
 * <p>由{@link ResourceEditor}使用,并作为{@link org.springframework.context.support.AbstractApplicationContext}的基类。
 * 也可以单独使用。
 *
 * <p>如果位置值是URL,将返回一个{@link UrlResource},
 * 如果它是非URL路径或“classpath:”伪URL,则将返回{@link ClassPathResource}。
 *
 * @author Juergen Hoeller
 * @since 10.03.2004
 * @see FileSystemResourceLoader
 * @see org.springframework.context.support.ClassPathXmlApplicationContext
 */
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);


	/**
	 * 创建一个新的DefaultResourceLoader。
	 * <p>ClassLoader访问将在实际资源访问时使用线程上下文类加载器进行(自5.3)。
	 * 要获得更多控制,请将特定的ClassLoader传递给{@link#DefaultResourceLoader(ClassLoader)}。
	 * @see java.lang.Thread#getContextClassLoader()
	 */
	public DefaultResourceLoader() {
	}

	/**
	 * 创建一个新的DefaultResourceLoader。
	 * @param classLoader 用于加载类路径资源的ClassLoader, or {@code null}
	 * 或{@code null}时使用在实际访问资源时的线程上下文类加载器。
	 */
	public DefaultResourceLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}


	/**
	 * 指定用于加载类路径资源的ClassLoader,
	 * 或{@code null}时使用在实际访问资源时的线程上下文类加载器。
	 * <p>默认情况下,ClassLoader访问将在实际资源访问时使用线程上下文类加载器(自5.3)。
	 */
	public void setClassLoader(@Nullable ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	/**
	 * 返回ClassLoader用以加载类路径资源。
	 * <p>将此资源加载器创建的所有ClassPathResource对象传递给ClassPathResource的构造函数。
	 * @see ClassPathResource
	 */
	@Override
	@Nullable
	public ClassLoader getClassLoader() {
		return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
	}

	/**
	 * 使用此资源加载器注册给定的解析器,以便处理其他协议。
	 * <p>任何此类解析器都将在此加载器的标准解析规则之前被调用。因此,它也可能覆盖任何默认规则。
	 * @since 4.3
	 * @see #getProtocolResolvers()
	 */
	public void addProtocolResolver(ProtocolResolver resolver) {
		Assert.notNull(resolver, "ProtocolResolver must not be null");
		this.protocolResolvers.add(resolver);
	}

	/**
	 * 返回当前注册的协议解析器的集合,允许自检和修改。
	 * @since 4.3
	 * @see #addProtocolResolver(ProtocolResolver)
	 */
	public Collection<ProtocolResolver> getProtocolResolvers() {
		return this.protocolResolvers;
	}

	/**
	 * Obtain a cache for the given value type, keyed by {@link Resource}.
	 * 获取以{@link Resource}为键的给定值类型的缓存。
	 * @param valueType 值类型,例如,ASM {@code MetadataReader}
	 * @return 缓存{@link Map},在{@code ResourceLoader}级别共享。
	 * @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<>());
	}

	/**
	 * 清除此资源加载器中的所有资源缓存。
	 * @since 5.0
	 * @see #getResourceCache
	 */
	public void clearResourceCaches() {
		this.resourceCaches.clear();
	}

	/**
	 * 返回指定资源位置的{@code Resource}句柄。
	 */
	@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		//协议解析器查找到Resource,直接返回
		for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}

		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...
				URL url = ResourceUtils.toURL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

	/**
	 * 返回给定路径上资源的Resource句柄。
	 * <p>默认实现支持类路径位置。 这应该适用于独立实现,但可以被覆盖,
	 * 例如用于针对Servlet容器的实现。
	 * @param path Resource的路径
	 * @return 相应的Resource句柄
	 * @see ClassPathResource
	 * @see org.springframework.context.support.FileSystemXmlApplicationContext#getResourceByPath
	 * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
	 */
	protected Resource getResourceByPath(String path) {
		return new ClassPathContextResource(path, getClassLoader());
	}


	/**
	 * ClassPathResource 通过实现ContextResource接口显式地表示上下文相关路径。
	 */
	protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

		public ClassPathContextResource(String path, @Nullable ClassLoader classLoader) {
			super(path, classLoader);
		}

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

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

}

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2025-03-16 23:43:33.925 ERROR 19808 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: An attempt was made to call a method that does not exist. The attempt was made from the following location: org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:177) The following method did not exist: 'javax.servlet.ServletContext org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContext()' The calling method's class, org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext, was loaded from the following location: jar:file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar!/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.class The called method's class, org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext, is available from the following locations: jar:file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar!/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.class The called method's class hierarchy was loaded from the following locations: org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext: file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/boot/spring-boot/2.6.13/spring-boot-2.6.13.jar org.springframework.web.context.support.GenericWebApplicationContext: file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/spring-web/6.0.11/spring-web-6.0.11.jar org.springframework.context.support.GenericApplicationContext: file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/spring-context/5.3.23/spring-context-5.3.23.jar org.springframework.context.support.AbstractApplicationContext: file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/spring-context/5.3.23/spring-context-5.3.23.jar org.springframework.core.io.DefaultResourceLoader: file:/C:/Users/%e5%b0%8f%e7%99%bd/.m2/repository/org/springframework/spring-core/5.3.23/spring-core-5.3.23.jar Action: Correct the classpath of your application so that it contains a single, compatible version of org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext Process finished with exit code 1
最新发布
03-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值