为什么我得到WELD-001303:没有活动上下文的范围类型javax.enterprise.context.RequestScoped异常?

时间:2017-10-02 16:16:23

标签: jax-rs wildfly cdi

我已经在网站上查看了与此错误相关的其他问题,但其中大多数都是关于SessionScope或未得到答复。唯一可能有用的是No active contexts for scope type javax.enterprise.context.RequestScoped when invoking a bean from a thread,但它不在我的上下文中。

我在Wildfly 10.1(Java ee 7)上运行JAX-RS端点。看起来像这样:

@Path("")
public class ServerResource {

    @Inject
    Order order;

    @Resource
    ManagedExecutorService mes;

    @PUT
    @Path("/prepareOrder")
    public void prepareOrder(@Suspended AsyncResponse response) {
        mes.execute(() ->  {
            try {
                Item item = new Item(); // JPA entity
                order.setItem(item); // line 71
                // call a service to save the order data (like item) to the DB
            } catch (Exception e) {
                e.printStackTrace();
                response.resume(false);
            }
            response.resume(true);
        });
    }
}

我添加了try-catch只是因为这个问题,它通常不存在。 Order

@Stateful
@RequestScoped
public class Order {
    private Item item;
    // setter and getter
}

订单是RequestScoped,因为当它被使用/处理时,它会经历一种责任链(几个无状态bean注入Order并按顺序更改它)。无论如何,问题不在于设计,而在于错误。

order.setItem(item);抛出异常:

org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165)
at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
at com.a.b.Order$Proxy$_$$_WeldClientProxy.setItem(Unknown Source)
at com.a.c.ServerResource.lambda$0(ServerResource.java:71)
at org.jboss.as.ee.concurrent.ControlPointUtils$ControlledRunnable.run(ControlPointUtils.java:105)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.glassfish.enterprise.concurrent.internal.ManagedFutureTask.run(ManagedFutureTask.java:141)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:250)

我尝试使用@StatelessRequestScope@Stateless vs @RequestScoped)注释ServerResource类,但这并不重要。

为什么我会收到此错误以及如何让我的代码正常工作?

2 个答案:

答案 0 :(得分:2)

在CDI中,上下文不会传播到其他线程,如果您浏览规范,则会出现与线程相关的分散的上下文概念。 Bean存储("地图"它们为上下文保存bean)由ThreadLocal实现,因此它只是不起作用。

使用现有的上下文无法解决这个问题 - 唯一的选择是定义自定义范围/上下文,它将处理跨线程的上下文传播。

编辑:请注意,现在创建了JIRA ticket,考虑向Weld添加类似此功能的内容。

答案 1 :(得分:0)

您可以加入上下文,但我认为您理解错误。服务器拥有自己的线程池。因此,默认情况下,每个请求都是异步的(每个用户请求都创建新线程)。

ContextControl ctxCtrl = (ContextControl) BeanProvider.getContextualReference(ContextControl.class, new Annotation[0]);
ctxCtrl.startContext(RequestScoped.class);
try{
//...
} finally {
 ctxCtrl.stopContext(RequestScoped.class);
}