Сварка ContextNotActiveException в асинхронном сервлете
Среда:
- WildFly 9.0.1 / 9.0.2
- Java EE 7 Полный профиль
- Weld CDI среда.
Из-за ожидаемого количества запросов я хочу реализовать асинхронный запрос поверх FacesServlet и сделал это:
public class AsyncFacesServlet extends HttpServlet {
private static final long serialVersionUID = 111966573758921845L;
private FacesServlet delegate;
@Inject
private BeanManager beanManager;
@Inject
private ServletContext servletContext;
@Override
public void init(final ServletConfig servletConfig) throws ServletException {
delegate = new FacesServlet();
delegate.init(servletConfig);
}
@Override
public void destroy() {
delegate.destroy();
}
@Override
public ServletConfig getServletConfig() {
return delegate.getServletConfig();
}
@Override
public String getServletInfo() {
return delegate.getServletInfo();
}
@Override
public void service(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
final AsyncContext asyncContext = request.isAsyncStarted()
? request.getAsyncContext() : request.startAsync(request, response);
final Runnable runnable = () -> {
try {
delegate.service(request, response);
} catch (final IOException | ServletException ex) {
throw Throwables.propagate(ex);
}
};
asyncContext.start(runnable);
}
}
И затем обновил мой web.xml как:
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>com.mycompany.service.faces.AsyncFacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
При развертывании я получаю следующие исключения, которые указывают, что Weld не был правильно инициализирован внутри асинхронного текста.
SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-38) Error Rendering View[/login.xhtml]: 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:708)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:95)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.get(ContextualInstanceStrategy.java:178)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:761)
at org.jboss.weld.el.AbstractWeldELResolver.lookup(AbstractWeldELResolver.java:107)
at org.jboss.weld.el.AbstractWeldELResolver.getValue(AbstractWeldELResolver.java:90)
at org.jboss.as.jsf.injection.weld.ForwardingELResolver.getValue(ForwardingELResolver.java:46)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:188)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstIdentifier.getValue(AstIdentifier.java:116)
at com.sun.el.parser.AstValue.getBase(AstValue.java:151)
at com.sun.el.parser.AstValue.getValue(AstValue.java:200)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
at javax.faces.component.UIOutput.getValue(UIOutput.java:174)
at javax.faces.component.UIInput.getValue(UIInput.java:291)
at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:205)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:355)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:164)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:920)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:890)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:458)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:134)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
at com.mycompany.service.faces.servlet.AsyncFacesServlet.lambda$service$17(AsyncFacesServlet.java:61)
Происходит следующее: Weld неправильно инициализируется или контекст не распространяется на асинхронное выполнение контекста.
Как я могу быть в состоянии распространить или воссоздать контекст сварки при вызове асинхронного запроса?
1 ответ
Я добавлю к ответу примечание, что существует проблема с открытой спецификацией CDI, чтобы сделать асинхронное поведение более переносимым. Укажите, что bean-объекты веб-области (запрос, сессия, приложение) могут быть внедрены в асинхронные сервлеты.
То, что вы можете сделать специфическим для Weld способом - это запустить контекст. Apache DeltaSpike имеет несколько утилит, которые сделают этот контейнер также специфичным, http://deltaspike.apache.org/documentation/container-control.html
Если ваш runnable является управляемым компонентом, вы можете использовать BoundRequestContext
в сварке, чтобы начать контекст запроса для этого потока. Больше здесь. Недостатком является то, что это новый контекст, а не промежуточный контекст.