Spring的Resource定位

本文深入分析了Spring框架中Resource的定位机制,详细介绍了从AbstractApplicationContext到PathMatchingResourcePatternResolver的继承关系及其工作流程,包括如何解析不同的资源路径模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前看了很多的Spring的Resource定位的博客。今天自己分析了一下,分析如下:

我们先看一下继承关系图:


这张图片是AbstractApplicationContext的继承关系图,先看左部分,

在ResourcePatternResolver这个接口添加了一个函数,如下:

Resource[]getResources(String locationPattern)
子类PathMatchResourcePatternResolver这个子类实现了这个方法,

public Resource[] getResources(String locationPattern) throws IOException {
		Assert.notNull(locationPattern, "Location pattern must not be null");
		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()));
			}
		}
		else {
			// Only look for a pattern after a prefix here
			// (to not get fooled by a pattern symbol in a strange prefix).
			int prefixEnd = 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)};
			}
		}
	}


比如使用FileSystemXmlApplicationContext这个容器,在IOC容器启动的时候调用了AbstractApplicationContext的refresh()函数------>调用AbstractApplicationContext的obtainFreshBeanFactory()------>AbstractApplicationContext的refreshBeanFactory()------->AbstractRefreshApplicationContext的refreshBeanFactory()------>AbstractRefreshApplicationContext的loadBeanDefinitions()----->AbstractXmlApplicationContext的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)------->AbstractXmlApplicationContext的loadBeanDefinitions(XmlBeanDefinitionReader reader)--------->

AbstractBeanDefinitionReader的loadBeanDefinitions(String[] locations)------>AbstractBeanDefinitionReader的loadBeanDefinitions(String location)--------->

AbstractBeanDefinitionReader的loadBeanDefinitions(String location, Set actualResources)

终于看到了这个函数了:

public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				//下面的resourceLoader这个局部变量是通过getResourceLoader()这个方法得到的,通过getResourceLoader()得到的AbstractBeanDefinitions
				//这个类的成员变量,这个变量其实是FileSystemXmlApplicationContext这个类的对象的本身,因为FileSystemApplicationContext这个类
				//间接的实现了ResourcePatternResolver,也就实现resourceLoader()这接口,那么就会实现Resource[] getResources(String locationPattern) throws IOException;
				//那么就可以用这个getResources(location);
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (int i = 0; i < resources.length; i++) {
						actualResources.add(resources[i]);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// Can only load single resources by absolute URL.
			Resource resource = resourceLoader.getResource(location);
			int loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}

上面代码中Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);这句执行的是AbstractApplicationContext这个函数中的getResources(),函数如下:

public Resource[] getResources(String locationPattern) throws IOException {
		//这个this.resourcepatternResolver这个属性是ResourcePatternResolver的子类PathMatchingResourcePatternResolver,那么就用子类的
		//getResources();
		//this.resourcePatternResolver = new PathMatchingResourcePatternResolver(this);
		return this.resourcePatternResolver.getResources(locationPattern);
	}

看到这里我们看到了最终执行的是PathMatchingResourcePatternResolver里的getResources(String locationPattern),这里用了一个装饰设计模式。接下来分析剩下的Resource的定位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值