之前看了很多的Spring的Resource定位的博客。今天自己分析了一下,分析如下:
我们先看一下继承关系图:
这张图片是AbstractApplicationContext的继承关系图,先看左部分,
在ResourcePatternResolver这个接口添加了一个函数,如下:
Resource[] | getResources(String locationPattern) |
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的定位。