CDI Scope注解失效:所有Bean表现为Application Scope问题求助
排查Request Scope CDI Bean表现为单例的问题
看起来你遇到了CDI与Spring上下文冲突导致作用域注解失效的典型场景,结合你描述的跨标签页/浏览器都保留数据的现象,咱们一步步来排查:
1. 先确认注解是否混用
最常见的坑就是CDI注解和Spring注解搞混了:
- 检查你的Bean用的是哪个
@RequestScoped:- CDI的正确注解是
javax.enterprise.context.RequestScoped - Spring的注解是
org.springframework.web.context.annotation.RequestScope
如果你的Bean同时加了Spring的@Component/@Controller和CDI的@RequestScoped,Spring会接管这个Bean的生命周期,CDI的作用域直接被忽略,默认变成Spring的单例(除非你显式指定Spring的作用域)。
- CDI的正确注解是
2. 检查Spring与CDI的上下文冲突
如果你的项目同时引入了Spring和CDI依赖,很可能出现两个容器同时管理Bean的情况:
- 打开你的
pom.xml,看看是否同时存在spring-context/spring-web和cdi-api/weld-servlet这类依赖。如果是,Spring的上下文加载器(比如ContextLoaderListener)可能优先接管了Bean创建。 - 查看
web.xml或者webapp/WEB-INF/web.xml,如果配置了org.springframework.web.context.ContextLoaderListener,Spring会创建全局应用上下文,这时候CDI的Bean管理可能被压制。
3. 容器层面的CDI生效检查
不同容器对CDI的支持不一样,这也可能导致作用域失效:
- Tomcat 9:默认不自带CDI实现,需要手动添加Weld或OpenWebBeans的依赖,并且在
web.xml中配置对应的监听器。如果没做这些,CDI根本没启动,你的Bean会被当成普通类,默认是单例(如果被Spring扫描到的话)。 - WildFly 11:默认自带Weld作为CDI实现,CDI应该是默认生效的,但如果Spring的Bean扫描范围覆盖了CDI Bean,还是会出现Spring接管的情况。
4. 排查静态变量的低级错误
别忽略这个!如果你的Bean里用了静态字段来保存表单数据,哪怕是Request Scope的Bean,静态变量也会在整个应用中共享,导致跨请求保留数据。赶紧检查你的Bean代码,把静态变量改成实例变量。
5. 验证Bean实例是否真的是单例
在Bean的构造方法里加一行日志(或者打印语句),比如:
public class YourFormBean { public YourFormBean() { System.out.println("创建新的FormBean实例:" + this.hashCode()); } // 其他字段和方法 }
然后每次请求页面提交表单,看控制台是不是每次都输出新的hashCode。如果只输出一次,说明确实是单例,那就是作用域没生效;如果每次都不一样,那可能是你保存数据的逻辑有问题(比如存在会话里了)。
解决建议
- 纯CDI方案:移除所有Spring相关的依赖和配置(包括
ContextLoaderListener、@Component等注解),确保pom.xml中引入CDI的API和实现(比如Weld),Tomcat下要配置Weld的监听器。 - 混合使用方案:明确划分Spring和CDI的管理范围:
- 用CDI的
@Named标记需要CDI管理的Bean,用Spring的@Component标记Spring管理的Bean。 - 调整Spring的扫描范围,比如在
@ComponentScan中指定只扫描Spring专属的包,避免扫描CDI的Bean。
- 用CDI的
内容的提问来源于stack exchange,提问作者Alejandro Romanella
相关产品推荐
相关产品推荐

