目录

■前言

■吐槽

■暂时解决策

■最终解决

■困惑和不解(含推测和补充说明)

■对应的java代码

■风险

隐患一:按类型注入(@Autowired)会直接启动失败

隐患二:按名称注入(@Resource(name = "user"))会取错对象

隐患三:MyBatis 层面的别名冲突依然存在


==

■前言

基盘代码貌似有问题呀。。。。
(工程里面 和 服务器使用的jar里面,有不同包,同名的类,即SpringBean同名。。。)

Project AAA中,有aaa.bbb.ccc.gen.mapper.TTBean

    Project AAA中,使用AAA-bb-main.jar

AAA-bb-main.jar中,有aaa.bbb.ccc.mapper.TTBean

TTBean重复了。。。。

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: 
             Annotation-specified bean name 'xxxx' for bean class [aaa.bbb.ccc.gen.mapper.TTBean] conflicts with existing, 
        non-compatible bean definition of same name and class [aaa.bbb.ccc.mapper.TTBean]

把这个基盘代码,Bean重复的问题提了出去,

那边的开发说什么使用 MyBatis的FQDN可以解决。

可是查了一下,MyBatis的FQDN解决不了Spring的同名Bean冲突问题。

====

===

■吐槽

===
NTT DATA 的 Imart 产品,

不用Maven管理第三方jar。。。
    (生成war包的时候,使用一个叫Juggling的东西)

是Resin的Accel PlateForm Library ,其中一个AAA-bb.jar还是后期修改的。

完全TMD不整合。。。。
     
(IMart.war   /WEB-INF/Lib/*.jar)

====


■暂时解决策

Resin的JVM启动参数中,添加下面内容:

spring.main.allow-bean-definition-overriding=true

-Dspring.main.allow-bean-definition-overriding=true

明天去试试。暂时先让服务启动起来。。。

没有用,设置了还是无法启动

■最终解决

Resin的Imart下面,的WEB-INF的Lib下面,

 有一个多余的 AAA-main.jar 

     把上面这个多余的 jar 删掉, 就能正常启动了

====

■困惑和不解(含推测和补充说明)

①AAA-bb-main.jar

② AAA-main.jar 

 重复的Bean在①中,

即使我去掉了②、JVM启动时,①的jar也是被加载了。。。
 

# JVM 启动时,添加下面的参数,查看类的加载
-verbose:class

也就是说,下面这两个类,都被加载了

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: 
             Annotation-specified bean name 'xxxx' for bean class
[aaa.bbb.ccc.gen.mapper.TTBean] conflicts with existing, 
        non-compatible bean definition of same name and class
[aaa.bbb.ccc.mapper.TTBean]
 

神奇的是,去掉②之后,可以正常启动了,不再报上面的错误了。

    【推测】继续调查
         已经被JVM加载的类,什么时候被Spring容器加载

         使用的时候加载。 难道使用了②, ①就会被Spring容器加载???

补充说明一下,
           ①和②都不是IMart制品原本的jar,而是现在要开发的这个Project相关の基盤のJar

====

■对应的java代码

===

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.setAllowBeanDefinitionOverriding(true);
        app.run(args);
    }

■风险

隐患一:按类型注入(@Autowired)会直接启动失败

如果你的某个 Service 需要注入 com.a.User,但容器里最终保留的是 com.b.User(因为后者包扫描顺序靠后)。此时 Spring 会提示:

NoSuchBeanDefinitionException: No qualifying bean of type 'com.a.User' available
因为 com.a.User 已经被覆盖并移除了,启动虽然过了,但运行到注入这个 Bean 的地方就会报错。

隐患二:按名称注入(@Resource(name = "user"))会取错对象

即使注入成功,你拿到手的很可能是 com.b.User 的实例,但你的业务逻辑是按 com.a.User 来写的。数据类型可能不同,调用方法时极大概率会抛出 ClassCastException 或 NullPointerException,这种运行时的诡异错误比启动报错更难排查。

隐患三:MyBatis 层面的别名冲突依然存在

请再次注意:这个 JVM 参数只管 Spring 容器,完全不管 MyBatis 的 typeAliasesPackage 扫描!
如果 XML 里你没有写 FQDN(全限定名),MyBatis 注册别名时依然会因为两个 User 同名而抛出 TypeException。既然你之前说“按照方案一配置了”(在 XML 中用了 FQDN),这个风险才被排除。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐