在Sprng当中如何加载多个配置文件

第一种:

使用一个数组,将所有要加载的配置文件放入到数组当中

Java代码

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"a.xml","b.xml"});

第二种:

使用通配符,这种方法不知道对于不在同一个路径下的配置起不起作用,本人没试验过!

Java代码

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/*.xml");

spring的源码是如何实现同时加载两个以上的配置文件的?

我的意思是源码在何处判断是否有两个路径,以及怎么去加载。

最好能贴上源代码。困惑了很久,请高手解决,不胜感激。

1个回答

1、你疑惑的是classpath 加载方式
2、那就分析ClassPathXmlApplicationContext
*/
[url] public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}[/url]

调用了setConfigLocations(configLocations);设置路径

public void setConfigLocations(String[] locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}

resolvePath用于替换${} 占位符

这样就能解析出configLocations

3、接下来加载bean
[quote] protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}[/quote]

[quote] public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
[/quote]

到了重点
[quote]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 {
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            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;
    }
}[/quote]

3.1、重点
3.1.1、getResourceLoader() --->
在AbstractXmlApplicationContext(ClasspathXmlApplicationContext(继承它) beanDefinitionReader.setResourceLoader(this); 即ClasspathXmlApplicationContext本身 通过观察你会发现是DefaultResourceLoader

它的解释:根据不同的前缀返回不同的Resource (到此其实就把你的疑问差不多解决了)

  • Will return a {@link UrlResource} if the location value is a URL,

    • and a {@link ClassPathResource} if it is a non-URL path or a
    • "classpath:" pseudo-URL.

3.1.2、模式字符串的加载
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

如果是模式 能找到多个--继续找下去 //classpath:aa*
for (Resource resource : resources) {

actualResources.add(resource);
}

其实你现在再去看下ClasspathResource就可以了

具体使用可以参考
[url]http://jinnianshilongnian.iteye.com/blog/1416322[/url]

jinnianshilongnian
jinnianshilongnian 面向接口编程(多态) 和 继承复用 是一种策略模式
7 年多之前 回复
iteye_10284
iteye_10284 谢谢 ,还有点问题:是关于ResourceLoader接口设计的 ResourcePatternResolver 接口继承了 ResourceLoader 接口 PathMatchingResourcePatternResolver实现了ResourcePatternResolver ApplicationContext接口继承了ResourcePatternResolver 并且在其子类的实现中调用了PathMatchingResourcePatternResolver 这种设计是用到什么模式吗?只感觉设计的很秒,但不知道秒在哪里。还请帮忙解释下,谢谢了。
7 年多之前 回复
jinnianshilongnian
jinnianshilongnian 此处咱示例的是ClassPathXmlApplicationContext 比如可能有其他的实现方式那可能就不成立的 ClassPathXmlApplicationContext 由父类既继承了 DefaultResourceLoader 类 并且还实现了ResourcePatternResolver接口 这种设计的有啥好处? 因为常见的如classpath资源、文件、url等等资源都需要使用 所以继承下 这样子类就没必要挨着写了 复用
7 年多之前 回复
iteye_10284
iteye_10284 谢谢,确实是在loadBeanDefinitions(String location, Set<Resource> actualResources) 解决了 路径的解析问题。 不过 if (resourceLoader instanceof ResourcePatternResolver) 这个判断应该是一直成立的呀,应为ClassPathXmlApplicationContext 实际上是实现了 ResourcePatternResolver 接口的,所以else那行应该不会执行,那么是不是会无法使用DefaultResourceLoader 的getResource()方法。 不过还有一点不明白:ClassPathXmlApplicationContext 由父类既继承了 DefaultResourceLoader 类 并且还实现了ResourcePatternResolver接口 这种设计的有啥好处?
7 年多之前 回复
立即提问