JAX-RS服务启动报错:Bean引用被非兼容代理实例覆盖求助
嘿,我之前在搭建Spring整合JAX-RS服务的时候也碰到过几乎一模一样的问题,咱们来一步步拆解这个异常的根源,然后搞定它!
首先先把异常信息读明白:
java.lang.IllegalStateException: @Bean method AppConfig.materialsRestService called as a bean reference for type [com.phoenixbv.rs.MaterialsRestService] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy159]. Overriding bean of same name declared in: com.example.config.AppConfig
简单说就是:Spring容器里出现了两个同名的materialsRestService bean——一个是你在AppConfig里用@Bean手动定义的,另一个是Spring自动生成的JDK动态代理对象,但这俩的类型不兼容,直接导致了冲突。
常见原因和解决办法
1. @Bean方法返回的是实现类而非接口类型
如果MaterialsRestService是一个接口,而你的@Bean方法返回的是它的实现类(比如MaterialsRestServiceImpl),那Spring生成的JDK动态代理是基于接口的,代理类和实现类本身不是同一个类型,自然会出现类型不兼容的问题。
解决办法:把@Bean方法的返回类型改成接口类型:
@Bean public MaterialsRestService materialsRestService() { return new MaterialsRestServiceImpl(); }
这样不管是原实例还是代理实例,都属于MaterialsRestService类型,类型冲突的问题就解决了。
2. 重复的组件扫描导致Bean被重复创建
看你的AppConfig里有两个@ComponentScan注解:
@ComponentScan("com.example.service") @ComponentScan("com.example.services")
很大概率是你的MaterialsRestService实现类同时被这两个扫描路径覆盖了,或者其中一个包包含了另一个,导致Spring自动扫描创建了一个bean,而你又用@Bean手动创建了一个同名的。这种情况下Spring会用后创建的bean覆盖前面的,但类型很可能不匹配。
解决办法:
- 合并或者调整
@ComponentScan的范围,确保只扫描一次需要的包,比如改成:
同时检查这两个包是否有重叠,避免重复扫描。@ComponentScan(basePackages = {"com.example.service", "com.example.services"}) - 如果你的服务类已经被
@Component(或@Service)标记并被扫描到了,那就不需要再用@Bean手动定义了,二选一即可,不要重复创建Bean。
3. 强制使用CGLIB代理(特殊场景)
如果你因为某些业务原因,必须让@Bean方法返回实现类,那可以配置Spring使用CGLIB代理。CGLIB是通过生成子类来实现代理的,代理类和原实现类是父子关系,类型自然兼容。
配置方式:
- 在你的
AppConfig类上添加注解:@EnableAspectJAutoProxy(proxyTargetClass = true) - 或者在XML配置里添加:
注意:这种方式需要确保项目里有CGLIB的依赖,而且不能代理final方法。<aop:aspectj-autoproxy proxy-target-class="true"/>
4. 排查Swagger2Feature的影响
有时候Swagger的自动配置也可能和Spring的Bean管理产生冲突,你可以先暂时注释掉Swagger2Feature的配置,看看异常是否消失。如果消失了,再调整Swagger的配置,比如手动指定要扫描的API类,避免和Spring的Bean扫描逻辑冲突。
总结
优先排查重复的Bean定义和**@Bean返回类型**这两个问题,这是触发这个异常最常见的原因。一般调整完这两点就能解决问题了。
内容的提问来源于stack exchange,提问作者F. Zamfirov

