JAX-RS Provider在WildFly中随机全局生效引发异常求助
问题详情
我有两个部署在WildFly 27上的服务:Scheduler和Process。Process服务包含一个标注@Provider的ClientRequestFilter,用于为Rest请求添加自定义请求头;该过滤器注入了HttpServletRequest以获取用户信息。Scheduler服务无任何请求过滤器,也不依赖Process服务,仅通过Rest客户端调用外部服务。
但容器启动后,Scheduler会随机触发异常:堆栈信息显示异常来自Process服务的那个请求过滤器——由于Scheduler的Quartz任务运行时不存在活跃的RequestScoped上下文,注入的HttpServletRequest无法获取,触发WELD-001303: No active contexts for scope type jakarta.enterprise.context.RequestScoped错误。
已知WildFly会将所有标注@Provider的类注册到全局Resteasy运行时,而非仅所属部署包,但无法理解问题的随机性:有时启动完全正常,有时必现异常,部署顺序不影响,卸载Process服务后问题依然存在。尝试移除@Provider注解改用jakarta.ws.rs.ext.Providers文件配置过滤器,无效。手动在每个部署的Application类中注册资源和Provider可行,但服务器上服务数量多,不愿批量修改;为每个Rest客户端手动注册Provider也不现实。
异常堆栈
jakarta.ws.rs.ProcessingException: org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type jakarta.enterprise.context.RequestScoped] wildfly27_1 | at deployment.scheduler.war//.scheduler.jobs.AbstractRestJob.execute(AbstractRestJob.java:61) wildfly27_1 | at deployment.scheduler.war//org.quartz.core.JobRunShell.run(JobRunShell.java:202) wildfly27_1 | at deployment.scheduler.war//org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) wildfly27_1 | Caused by: jakarta.ws.rs.ProcessingException: org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type jakarta.enterprise.context.RequestScoped wildfly27_1 | at org.jboss.resteasy.resteasy-client@6.2.1.Final//org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterRequest(ClientInvocation.java:767) wildfly27_1 | at org.jboss.resteasy.resteasy-client@6.2.1.Final//org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:499) wildfly27_1 | at org.jboss.resteasy.resteasy-client@6.2.1.Final//org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:71) wildfly27_1 | at org.jboss.resteasy.resteasy-client@6.2.1.Final//org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.get(ClientInvocationBuilder.java:198) wildfly27_1 | at deployment.scheduler.war//scheduler.jobs.RestGetJob.performRequest(RestGetJob.java:16) wildfly27_1 | at deployment.scheduler.war//scheduler.jobs.AbstractRestJob.execute(AbstractRestJob.java:45) wildfly27_1 | ... 2 more wildfly27_1 | Caused by: org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type jakarta.enterprise.context.RequestScoped wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:628) wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:89) wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63) wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:87) wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105) wildfly27_1 | at org.jboss.weld.core@5.1.0.Final//org.jboss.weld.generated.proxies.servlet.http.HttpServletRequest$Proxy$_$$_WeldClientProxy.getRemoteUser(Unknown Source) wildfly27_1 | at deployment.process.war//process.core.remote.RequestFilter.filter(RequestFilter.java:20) wildfly27_1 | at deployment.process.war//process.core.remote.RequestFilter$Proxy$_$$_WeldClientProxy.filter(Unknown Source) wildfly27_1 | at org.jboss.resteasy.resteasy-client@6.2.1.Final//org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterRequest(ClientInvocation.java:754) wildfly27_1 | ... 7 more
解决方案
1. 给过滤器添加上下文检查与优先级控制
修改Process服务的RequestFilter,添加上下文异常捕获,同时设置低优先级确保仅自身服务触发:
import jakarta.ws.rs.Priorities; import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.ext.Provider; import org.jboss.weld.contexts.ContextNotActiveException; @Provider @Priority(Priorities.USER - 100) // 设置低于默认用户级别的优先级 public class RequestFilter implements ClientRequestFilter { @Inject private HttpServletRequest request; @Override public void filter(ClientRequestContext context) throws IOException { try { // 尝试获取请求信息,触发上下文检查 String user = request.getRemoteUser(); if (user != null) { context.getHeaders().add("X-User", user); } } catch (ContextNotActiveException e) { // 无活跃请求上下文时直接跳过,不执行过滤逻辑 return; } } }
- 原理:优先级设置让Process自身的Rest客户端优先加载该过滤器,而其他服务的客户端在无上下文时会捕获异常并跳过,避免报错。
2. 开启WildFly部署隔离
在WildFly的standalone.xml(或domain.xml)的JAX-RS子系统中配置部署隔离,让每个服务的Resteasy Provider仅在自身部署内生效:
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"> <deployment-isolation> <deployment name="scheduler.war" isolated="true"/> <deployment name="process.war" isolated="true"/> </deployment-isolation> </subsystem>
- 原理:部署隔离会让每个WAR包拥有独立的Resteasy运行时,全局Provider不再共享,彻底解决跨服务干扰问题。该配置支持WildFly 20及以上版本。
3. 改为客户端实例级注册过滤器
移除@Provider注解和jakarta.ws.rs.ext.Providers文件配置,仅在Process服务创建Rest客户端时手动注册过滤器:
import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.WebTarget; public class RestClientUtil { public static WebTarget createTarget(String baseUrl) { Client client = ClientBuilder.newClient() .register(RequestFilter.class); // 仅在当前客户端实例注册过滤器 return client.target(baseUrl); } }
- 原理:过滤器仅绑定到Process自己创建的客户端实例,不会被全局扫描注册,自然不会影响Scheduler服务。
问题随机性原因
WildFly的Resteasy Provider扫描与CDI上下文初始化存在竞态:
- 当Scheduler的Rest客户端先于Process的Provider完成初始化时,不会加载该过滤器,服务正常;
- 当Process的Provider先被全局注册,Scheduler的客户端初始化时会加载该过滤器,而Quartz任务运行时无活跃请求上下文,触发异常;
- 卸载Process后,WildFly的全局Provider缓存未及时清空,所以问题依然存在。
内容的提问来源于stack exchange,提问作者Cx Vercility

