You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Spring测试被EJB拦截器拦截的EJB服务时拦截器不生效如何解决

问题根因

你当前是将EJB类当成普通Spring Bean直接注册到Spring测试上下文,Spring 4.3原生不支持解析Java EE的@Interceptors、@AroundInvoke这类EJB专属注解,因此拦截器逻辑不会被触发。


方案1:基于Spring AOP适配现有拦截器(改动最小,测试速度快)

无需修改原有拦截器、服务类的业务代码,仅新增Spring侧配置即可:

  1. 调整测试配置类,注册拦截器并新增AOP适配逻辑:
@Configuration
public static class ClassContextTest {
    // 注册原有EJB拦截器到Spring容器
    @Bean
    public ValidationInterceptor validationInterceptor() {
        return new ValidationInterceptor();
    }

    @Bean
    public FooServiceImpl produceService() {
        return new FooServiceImpl();
    }

    @Bean
    public FooDao produceDao() {
        //...原有逻辑不变
    }

    // 新增切面配置,适配EJB拦截器执行逻辑
    @Bean
    public Advisor ejbInterceptorAdvisor(ValidationInterceptor validationInterceptor) {
        // 切点规则:匹配所有带@Interceptors注解的类的公共方法,也可缩小范围仅匹配FooServiceImpl
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("@within(javax.interceptor.Interceptors) && execution(public * *(..))");
        
        // 环绕通知适配EJB的InvocationContext规范
        return new DefaultPointcutAdvisor(pointcut, (MethodInterceptor) invocation -> {
            InvocationContext ctx = new InvocationContext() {
                @Override
                public Object getTarget() { return invocation.getThis(); }
                @Override
                public Method getMethod() { return invocation.getMethod(); }
                @Override
                public Object[] getParameters() { return invocation.getArguments(); }
                @Override
                public void setParameters(Object[] params) { invocation.setArguments(params); }
                @Override
                public Map<String, Object> getContextData() { return new HashMap<>(); }
                @Override
                public Object proceed() throws Exception {
                    try {
                        return invocation.proceed();
                    } catch (Throwable e) {
                        throw new Exception(e);
                    }
                }
                @Override
                public Constructor<?> getConstructor() { return null; }
                @Override
                public Object getTimer() { return null; }
            };
            // 直接调用原有EJB拦截器逻辑
            return validationInterceptor.intercept(ctx);
        });
    }
}
  1. 给测试类开启Spring AOP支持:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {FooServiceTest.ClassContextTest.class})
@EnableAspectJAutoProxy // 新增此注解
public class FooServiceTest {
    // 原有测试逻辑完全不变
}

该方案所有业务代码不需要调整,测试依然运行在纯Spring上下文,启动速度快,适配成本极低。如果有多个EJB拦截器,只需要扩展适配逻辑,读取@Interceptors注解配置的拦截器列表按顺序调用即可。


方案2:使用Arquillian嵌入式容器测试(完全对齐生产环境)

如果需要100%模拟WildFly生产环境的EJB运行规则,建议改用Arquillian集成测试框架,启动嵌入式WildFly容器部署服务,所有EJB注解都会被容器原生识别,无需做任何适配:

  1. 先引入Arquillian、WildFly嵌入式容器对应Java EE 7版本的依赖。
  2. 改造测试类为Arquillian测试:
@RunWith(Arquillian.class)
public class FooServiceTest {

    @Deployment
    public static WebArchive createDeployment() {
        return ShrinkWrap.create(WebArchive.class)
                .addClasses(FooService.class, FooServiceImpl.class, FooDao.class, Foo.class, ValidationInterceptor.class)
                // 按需加入所有依赖的DAO、Mapper等类
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @EJB
    public FooService service;

    @Test
    public void createTest() throws Exception {
        Foo foo = new Foo();
        // ...原有测试逻辑不变
        service.create(foo);
        // ...原有测试逻辑不变
    }
}

该方案完全对齐生产运行逻辑,缺点是测试启动速度慢,依赖嵌入式容器资源。


内容的提问来源于stack exchange,提问作者kwisatz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:27:03