我们经常把spring需要加载的properties文件放在java/resources下面,这样存放的问题导致properties在打包后就在jar的根目录下,所以我们的spring的配置路径就是classpath*:xxx.properties,但是这样的jar我们在被其他项目引用的时候会发现properties文件老是无法加载,就这个问题从spring的源码来找找为什么会这样.
首先properties是当做一个resource来加载的,实现加载的是org.springframework.core.io.ResourceLoader
接口的一个实现,其中org.springframework.core.io.support.PathMatchingResourcePatternResolver
用于解析classpath*:为前缀的资源定义.
PathMatchingResourcePatternResolver的getResources方法里面有以下内容
|
|
如果我们用classpath*:config-*.properties
来查找资源,会进入findPathMatchingResources
方法,我们看看这个方法前几行怎么写的
|
|
这里经过determineRootDir(locationPattern)
产生的rootDirPath会变成classpath*:然后就会调用到public Resource[] getResources(String locationPattern) throws IOException
这个方法里面,(看代码)
,接下来并不会再调用findPathMatchingResources
方法而是调用findAllClassPathResources
这个方法,参数会把classpath*:
这个subString掉,这个时候神奇的地方来了,我们看看findAllClassPathResources
这里面有什么神奇的,上代码:
代码很简单,关键就在
(注意这个时候path=“”)这一行,这里的classloader决定了我们能获取的资源,如果在tomcat下面.这个classloader是Tomcat的WebappClassloader,这个时候我们查找资源的path是一个空的字符串.这个class返回了两个URl,一个是${webapps}/WEB-INF/classes,还有一个就是${tomcat-home}/lib,奇怪了,居然${webapps}/WEB-INF/lib并不在返回的URL中,有点神奇了,let’s look!
这个方法实际是WebappClassloader直接继承了ClassLoad过来的,parentClassLoad实际查找的的时tomcat容器的classpath关键在于findResources(name)
这个调用,这个调用webappCLassPath有自己的实现,继续look:
我们可以看到这个for循环里面获取JarEntry这一句,JarEntry jarEntry = jarFiles[i].getJarEntry(name);
这个name其实是一个””字符串,所以返回的jarEntry就是null,这样所有WEB-INF/lib下jar包里面的配置文件全部都不会进入下一步的匹配过程中.
所以这个问题的根源在于classpath*:
这种配置,在tomecat下并不适用于文件放在根目录下匹配加载的情况,所以想加载lib/xxx.jar包里面的porpertis文件的话,需要将porperties文件放在一个包路径下,我是放在config这个包路径下解决,可以参考解决一下.
特别说明,在Jetty下面有没有这种情况出现我没有去实验,有兴趣的人可以去试试看.