现象:同一个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的更多相关文章

  1. ssm 关于mybatis启动报Result Maps collection already contains value for ...的问题总结

    Result Maps collection already contains value for com.zhaike.mapping.ChapterMapper.BaseResultMap Err ...

  2. java.lang.IllegalArgumentException: Result Maps collection already contains value for xxx

    本人项目产生此问题的原因是: 本地备份了一份xxxmapper.xml的副本“xxxmapper - 副本.xml”,应该是系统会自动加载“mappe”目录下的所有xml文件. 参考:https:// ...

  3. MyBatis 中 Result Maps collection already contains value for xxx 错误原因

    出现此类错误的原因是同一个DAO操作多个Mapper导致的,将Mapper配置文件的  ResultMap的ID修改成不相同即可解决

  4. mybatis(错误一) 项目启动时报“Result Maps collection already contains value forxxx”的解决方案

    Result Maps collection already contains value for xyx.dsw.dao.mapper.admin.quotationwish.TempTestTab ...

  5. 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 ...

  6. mybatisGenerator 代码自动生成报错 Result Maps collection already contains value for BaseResultMap--转

    转自:http://blog.csdn.net/tan3739/article/details/7555665 Exception in thread "main" Java.la ...

  7. mybatisGenerator 代码自动生成报错 Result Maps collection already contains value for BaseResultMap【转】

    由于mybatis简单易学,比起Hibername来,更容易上手,代码也能自动生成.这几天研究了下代码自动生成的,参考: http://0609xiaohua.iteye.com/blog/14535 ...

  8. 使用mybatis报错【Result Maps collection already contains value for ...BaseResultMap】的解决方法

    Result Maps collection already contains value for ...BaseResultMap ...... 这个问题,相信大家在使用mybatis的重新生成 d ...

  9. mybatis启动报错Result Maps collection already contains value forxxx

    ssm搭建过程中启动tomcat,报错: Cause: java.lang.IllegalArgumentException: Result Maps collection already conta ...

随机推荐

  1. NULL合并操作符??

    参考官方手册: /** * NULL合并操作符 ?? */ // $a, $b, $c都未声明和定义 var_dump($a??$b??$c); // NULL // $a为数组,$b为100,$c为 ...

  2. js确认末尾字符算法挑战

    检查一个字符串(str)是否以指定的字符串(target)结尾. 如果是,返回true;如果不是,返回false. 这个挑战可以通过在ES2015中引入的.endsWith()方法来解决.但是出于这个 ...

  3. Oracle update 两表及以上关联更新,出现多值情况,不是一对一更新

    为了方便起见,建立了以下简单模型,和构造了部分测试数据:在某个业务受理子系统BSS中, SQL 代码--客户资料表 create table customers ( customer_id numbe ...

  4. 迷你redux实现,redux是如何进行实现的?

    export function createStore(reducer){ let currentState={} let currentListeners=[] function getState( ...

  5. eclipse中创建的spring-boot项目在启动时指定加载那一个配置文件的设置

    步骤如下:鼠标点击项目右键—>Run As—>Run Configurations—>Java Application (如下图) 鼠标右键点击Java Application——— ...

  6. go语言从例子开始之Example2.类型

    Go 拥有各值类型,包括字符串,整形,浮点型,布尔型等.下面是一些基本的例子. Example: values.go package main import "fmt" func ...

  7. SVN连接不上仓库,问题之一

    如果之前用过SVN,在新的地址上用,发现一直连不上,报错.有可能是因为默认使用了之前的地址,所以没弹出输账号和密码的弹框. 解决方法就是:把之前的链接地址全部清除掉. 右键找到SVN里面的  Sett ...

  8. oracle 数据恢复

    闪回表删除之前 flashback table t1 to before drop; 如果彻底删除表此方法无效 若要彻底删除表,则使用语句:drop table <table_name> ...

  9. jsp详解(3个指令、6个动作、9个内置对象、11个隐式对象)

    jsp概述SP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术.JSP实际上就是Servlet.    jsp=html+jav ...

  10. MariaDB 创建表

    在本章中,我们将学习如何创建表. 在创建表之前,首先确定其名称,字段名称和字段定义. 以下是表创建的一般语法: CREATE TABLE table_name (column_name column_ ...