idae父子项目Test执行报Result Maps collection already contains value for xxx
现象:同一个springmvc工程使用eclipse和idea用Tomcat启动都没问题,但是如果走单元测试使用到了@ContextConfiguration这个spring的上下文注解idea出问题了,eclipse没问题;由于最近才使用idea;只能先百度一下根据现象,发现天下文章一大抄。。。还得自己慢慢追!
第一阶段:根据提示基本断定这个map的id被加载了两次,但是全文搜索了一下确实只有一个id,排除传统的手残;eclipse没问题也能证明这点,这里就猜测很大可能是idea哪里需要设置一下,但是网上没找到
第二阶段:看日志追源码,出错定位在parse map阶段,如图:

初步判断在idea执行test的时候,加载了2遍spring的相关mapper.xml,继续追,根据异常定位到 PathMatchingResourcePatternResolver 这个类,他主要进行资源的匹配,主要入口方法
他基本做了两个件事情,1)把所有的不重复的资源用set收集起来,2)针对收集的资源进行一次xml的筛选(set),再接下去就是解析parse不在这个类(根据这里提供的xml进行逐一(xml里面的相关id)解析并记录,如果出现重复的则报异常题目异常)
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
String rootDirPath = determineRootDir(locationPattern);
String subPattern = locationPattern.substring(rootDirPath.length());
//getResources()这个方法收集所有的资源
Resource[] rootDirResources = getResources(rootDirPath);
Set<Resource> result = new LinkedHashSet<Resource>(16);
for (Resource rootDirResource : rootDirResources) {
rootDirResource = resolveRootDirResource(rootDirResource);
URL rootDirURL = rootDirResource.getURL();
if (equinoxResolveMethod != null) {
if (rootDirURL.getProtocol().startsWith("bundle")) {
rootDirURL = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirURL);
rootDirResource = new UrlResource(rootDirURL);
}
}
if (rootDirURL.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirURL, subPattern, getPathMatcher()));
}
else if (ResourceUtils.isJarURL(rootDirURL) || isJarResource(rootDirResource)) {
result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirURL, subPattern));
}
else {
result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
}
}
if (logger.isDebugEnabled()) {
logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
}
return result.toArray(new Resource[result.size()]);
Resource[] rootDirResources = getResources(rootDirPath);发现在执行完这个方法的时候里面出现了2次相同的jar包,表现形式不一样而已,例如:
URL [jar:file:/E:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar!/]
URL [jar:file:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3\lib\idea_rt.jar!/]
看到这里傻眼了,为什么位置相同的包会都能加进去,这里就想:要么是我那里没注意到idea配置,要么就是spring4.3.8的bug;回过头来想,这两条居然都言中了
第三阶段:定位、分析,进入getResources看了一下,第一次通过classLoader(AppClasssLoader顶级的)得到的url集合((URLClassLoader) classLoader).getURLs()进行条件筛选,第二次通过判断是否是系统的calssloader进行再次的add结果,如下:
protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource> result) {
if (classLoader instanceof URLClassLoader) {
try {
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
try {
UrlResource jarResource = new UrlResource(
//url自动在文件根目录前加/,例如:file:/E:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar
ResourceUtils.JAR_URL_PREFIX + url.toString() + ResourceUtils.JAR_URL_SEPARATOR);
if (jarResource.exists()) {
result.add(jarResource);
}
}
catch (MalformedURLException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Cannot search for matching files underneath [" + url +
"] because it cannot be converted to a valid 'jar:' URL: " + ex.getMessage());
}
}
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Cannot introspect jar files since ClassLoader [" + classLoader +
"] does not support 'getURLs()': " + ex);
}
}
}
//如果是系统的loader继续添加
if (classLoader == ClassLoader.getSystemClassLoader()) {
// "java.class.path" manifest evaluation...
addClassPathManifestEntries(result);
}
。。。
protected void addClassPathManifestEntries(Set<Resource> result) {
try {
String javaClassPathProperty = System.getProperty("java.class.path");
for (String path : StringUtils.delimitedListToStringArray(
javaClassPathProperty, System.getProperty("path.separator"))) {
try {
File file = new File(path);
UrlResource jarResource = new UrlResource(ResourceUtils.JAR_URL_PREFIX +
ResourceUtils.FILE_URL_PREFIX + file.getAbsolutePath() +
ResourceUtils.JAR_URL_SEPARATOR);
if (jarResource.exists()) {
//继续添加,这里会判断hashCode,因为set底层是一个hashMap,UrlResource有一个cleanedurl,通过它获取hashcode
//能添加进去说明确实hashcode不一致,即他们的cleanedurl(就是一个文件路路径,类似jar:file:/E:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar)不一样
result.add(jarResource);
}
}
上面这两个方法都是先new一个UrlResource,然后放到result中去,但是有个细节这里决定了两个对象的hashcode不一样:url.toString()就想我注释里写得一样它会在路径开始加一个'/',最后导致出现以下的结果:
jar:file:/E:/Program Files/JetBrains/IntelliJ IDEA 2018.3/lib/idea_rt.jar
jar:file:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3\lib\idea_rt.jar
第四阶段:破局,好了,idea的原因找到了,为什么idea用tomcat启动没问题,eclipse怎么启动都没问题,先从简单入手,idea直接用tomcat启动发现他们的类加载器是tomcat自带的parallelxxX不属于系统类加载器,所以不执行addClassPathManifestEntries这个方法,
那eclipse又为什么test也能执行呢?继续追,发现eclipse在执行方法addClassPathManifestEntries中 String javaClassPathProperty = System.getProperty("java.class.path");代码的时候javaClassPathProperty这里面父类的路径居然是eclipse的路径(xxx/classs)而不是我的maven仓库的jar包路径(xxx/xx.jar),不是jar自然就不放到result中去了,到这里有点懵,但是知道有个方向,那就是去找eclipse和idea的管理项目的不同,eclipse父子项目是不需要打jar包的,但是我的idea是开了2个窗口,父项目必须打jar包才能运行,可不可以idea也不用打jar包,果然有解决方案(父子都在同一个窗口中),我就不写了随便找个说明(https://blog.csdn.net/nianbingsihan/article/details/82772801)这里注意一下,父项目如果是多个pom文件要全部引入,如果只引入最顶层的pom的话,其它的子项目是灰色表示没起作用,还是会走jar包,验证一下,把maven仓库中的jar包删除,果然不报错,运行test程序,终于见到了久违的通过!
idae父子项目Test执行报Result Maps collection already contains value for xxx的更多相关文章
- ssm 关于mybatis启动报Result Maps collection already contains value for ...的问题总结
Result Maps collection already contains value for com.zhaike.mapping.ChapterMapper.BaseResultMap Err ...
- java.lang.IllegalArgumentException: Result Maps collection already contains value for xxx
本人项目产生此问题的原因是: 本地备份了一份xxxmapper.xml的副本“xxxmapper - 副本.xml”,应该是系统会自动加载“mappe”目录下的所有xml文件. 参考:https:// ...
- MyBatis 中 Result Maps collection already contains value for xxx 错误原因
出现此类错误的原因是同一个DAO操作多个Mapper导致的,将Mapper配置文件的 ResultMap的ID修改成不相同即可解决
- mybatis(错误一) 项目启动时报“Result Maps collection already contains value forxxx”的解决方案
Result Maps collection already contains value for xyx.dsw.dao.mapper.admin.quotationwish.TempTestTab ...
- mybatis 异常Result Maps collection does not contain value for java.lang.String
Result Maps collection does not contain value for java.lang.String 以上是我报的错. 只要报Result Maps collectio ...
- mybatisGenerator 代码自动生成报错 Result Maps collection already contains value for BaseResultMap--转
转自:http://blog.csdn.net/tan3739/article/details/7555665 Exception in thread "main" Java.la ...
- mybatisGenerator 代码自动生成报错 Result Maps collection already contains value for BaseResultMap【转】
由于mybatis简单易学,比起Hibername来,更容易上手,代码也能自动生成.这几天研究了下代码自动生成的,参考: http://0609xiaohua.iteye.com/blog/14535 ...
- 使用mybatis报错【Result Maps collection already contains value for ...BaseResultMap】的解决方法
Result Maps collection already contains value for ...BaseResultMap ...... 这个问题,相信大家在使用mybatis的重新生成 d ...
- mybatis启动报错Result Maps collection already contains value forxxx
ssm搭建过程中启动tomcat,报错: Cause: java.lang.IllegalArgumentException: Result Maps collection already conta ...
随机推荐
- form 表单的name
form 中 的name 很重要, 1. 可以用来查找对应的input 2.form 提交之后 会用来作为参数列表的名字 3.enovia plm 中,name 会和 table 的field 进行对 ...
- js常用转义字符列表
转义字符 含义 \n 换行 \t 制表符 \b 空格 \r 回车 \f 换页符 \ 反斜杠 ' 单引号 '' 双引号 \0nnn 八进制代码 nnn 表示的字符( n 是 0 到 7 中的一个八进制数 ...
- go语言从例子开始之Example28.非阻塞通道操作
常规的通过通道发送和接收数据是阻塞的.然而,我们可以使用带一个 default 子句的 select 来实现非阻塞 的发送.接收,甚至是非阻塞的多路 select. Example: package ...
- EventBus总结(原)
1.EventBus的作用 EventBus is a publish/subscribe event bus for Android and Java. EventBus可以被用来在各种自定义的监听 ...
- 如何用Word制作斜线表头?
如何用Word制作斜线表头?遇到这种问题,你一般是如何操作?本期企业网盘坚果云干货分享与大家分享有关斜线表头的制作方法. 斜线表头分单斜线表头和多斜线表头,下面分情况来了解相关的解决办法. 单斜线表头 ...
- python print 连续输出变量加字符串
a=1 b=2 print(a,'+',b,'=',a+b) 输出:1+2=3
- hdu 4705 Y (树形dp)
Description Input 4 1 2 1 3 1 4 题目的意思是给你一棵树,让你找到所有不在一条路径上的三个点的情况个数.乍一看正向处理比较麻烦,我们从反方向考虑,如果是取在一条路径上的3 ...
- 微信小程序常用API组件开发
关于小程序 张小龙定义小程序: 1.不需要下载安装即可使用: 2.用完即走,不用关心是否安装太多应用: 3.应用无处不在,随时可用. 特点: 1.适合业务逻辑简单的应用: 2,.适合低频应用: 3.适 ...
- [Repost] 探寻C++最快的读取文件的方案
作者:BYVoid(https://www.byvoid.com/zhs/blog/fast-readfile) 版权协议:CC BY-NC-SA 3.0 Unported 在竞赛中,遇到大数据时,往 ...
- [Repost] 悬线法
<浅谈用极大化思想解决最大子矩形问题>作者:王知昆 首先,根据定理1:最大有效子矩形一定是一个极大子矩形.不过与前一种算法不同的是,我们不再要求每一次枚举的一定是极大子矩形而只要求所有的极 ...