如何检测含javax.faces.bean.ViewScoped的CDI Bean并终止应用启动
检测并拦截使用
javax.faces.bean.ViewScoped的CDI Bean 一、运行时启动阶段检测并终止应用
利用CDI的扩展机制,在容器启动过程中扫描所有Bean,一旦发现同时标注@Named和javax.faces.bean.ViewScoped的Bean,直接抛出异常终止启动。
- 编写CDI扩展类
创建一个实现Extension接口的类,在ProcessBean阶段检查Bean的注解:
import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessBean; import javax.enterprise.event.Observes; import javax.inject.Named; import javax.faces.bean.ViewScoped; import java.util.Set; public class InvalidViewScopedChecker implements Extension { public <T> void validateBeanScopes(@Observes ProcessBean<T> event) { Set<java.lang.annotation.Annotation> beanAnnotations = event.getBean().getAnnotations(); boolean isNamedBean = beanAnnotations.stream() .anyMatch(ann -> ann.annotationType() == Named.class); boolean usesOldViewScoped = beanAnnotations.stream() .anyMatch(ann -> ann.annotationType() == ViewScoped.class); if (isNamedBean && usesOldViewScoped) { throw new IllegalStateException( "非法CDI Bean配置:" + event.getBean().getBeanClass().getName() + " 同时使用了@Named和javax.faces.bean.ViewScoped,该注解仅适用于JSF托管Bean,CDI Bean请使用javax.faces.view.ViewScoped" ); } } }
- 注册扩展
在项目的META-INF/services/目录下创建文件javax.enterprise.inject.spi.Extension,将上述类的全限定名写入文件(例如com.yourpackage.InvalidViewScopedChecker)。CDI容器启动时会自动加载这个扩展,执行检测逻辑。
二、构建期提前检测(推荐)
用ArchUnit编写架构规则,在编译/测试阶段就发现问题,避免错误代码流入运行环境:
- 添加ArchUnit依赖(以Maven为例)
<dependency> <groupId>com.tngtech.archunit</groupId> <artifactId>archunit-junit5</artifactId> <version>1.2.1</version> <scope>test</scope> </dependency>
- 编写检测规则
import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.lang.ArchRule; import org.junit.jupiter.api.Test; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; public class BeanScopeValidationTest { @Test void cdiNamedBeansMustNotUseOldViewScoped() { JavaClasses appClasses = new ClassFileImporter() .importPackages("com.your.app"); // 替换为你的应用包路径 ArchRule invalidScopeRule = classes() .that().areAnnotatedWith(javax.inject.Named.class) .should().notBeAnnotatedWith(javax.faces.bean.ViewScoped.class); invalidScopeRule.check(appClasses); } }
运行这个测试,一旦发现违规Bean,测试会直接失败,阻止构建完成。
三、IDE层面避免误导入
在IDE中配置对旧注解的警告/拦截:
- IntelliJ IDEA:进入
Settings > Editor > Inspections > Java > Deprecated API,找到javax.faces.bean.ViewScoped,将严重级别设为"Error",这样代码中出现该注解时会直接标红,并且可以禁用它的自动补全。 - Eclipse:进入
Window > Preferences > Java > Compiler > Errors/Warnings > Deprecated and restricted API,将"Forbidden reference (access rules)"设为Error,同时在Access Rules中添加规则,禁止引用javax.faces.bean.ViewScoped。
内容的提问来源于stack exchange,提问作者Adrian Jałoszewski
相关产品推荐
相关产品推荐

