焊接1.0.1-最终:对话范围bean即使在开始对话后仍会重新创建?

时间:2011-04-04 09:18:52

标签: jsf jsf-2 cdi jboss-weld

我目前正在使用:

  1. Apache tomcat 7
  2. JBoss Weld servlet 1.0.1-Final
  3. empty beans.xml
  4. web.xml 中的
  5. <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>

    我正在测试一个简单的计数器@ConversationScoped bean,目的是在开始会话范围后,在点击按钮时继续递增计数器。

    但似乎在提交之后,即使我在第一个位置开始对话之后,bean也会始终重新创建。

    这是我的简单豆子:

    package user.ui;
    
    import java.io.Serializable;
    
    import javax.annotation.PostConstruct;
    import javax.enterprise.context.Conversation;
    import javax.enterprise.context.ConversationScoped;
    import javax.inject.Inject;
    import javax.inject.Named;
    
    @Named
    @ConversationScoped
    public class CounterBean implements Serializable {
        @Inject
        private Conversation conversation;
    
        @PostConstruct
        public void init() {
            System.out.println("beginning conversation : " + this.conversation);
            this.conversation.begin();
        }
    
        private int counter;
    
        public int getCounter() {
            return counter;
        }
    
        public void setCounter(int counter) {
            this.counter = counter;
        }
    
        public void increment() {
            this.counter++;
        }
    }
    

    这是我简单的jsf视图:

    <ui:composition template="/template/masterlayout.xhtml">
        <ui:define name="windowTitle">Test Conversation Scope</ui:define>
        <ui:define name="heading">Test Conversation Scope</ui:define>
        <ui:define name="content">
            <h:form>
                <p:messages id="messages" globalOnly="true" />
                <p:panel header="Test Conversation Scope">
                    <h:outputText value="counter : " /> #{counterBean.counter}
                </p:panel>
    
                <h:commandButton value="Submit Data to Server" action="#{counterBean.increment}" />
            </h:form>
        </ui:define>
    </ui:composition>
    

    这是第一次访问的日志文件:

    INFO: Server startup in 12055 ms
    beginning conversation : ID: 1, transient: true, timeout: 600000ms
    

    在显示视图后,我点击了按钮,然后在catalina.out中使用此日志抛出异常:

    beginning conversation : ID: 2, transient: true, timeout: 600000ms
    unhandled exception : org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped
    cause exception : org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped, cause exception is BE : false
    

    这是tomcat日志中的异常跟踪:

    Apr 4, 2011 3:56:27 PM org.apache.catalina.core.StandardWrapperValve invoke
    SEVERE: Servlet.service() for servlet [Faces Servlet] in context with path [/primebert] threw exception [WELD-001303 No active contexts for scope type @ConversationScoped] with root cause
    org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type @ConversationScoped
        at org.jboss.weld.conversation.ConversationImpl.checkConversationActive(ConversationImpl.java:79)
        at org.jboss.weld.conversation.ConversationImpl.isTransient(ConversationImpl.java:234)
        at org.jboss.weld.conversation.ConversationImpl.toString(ConversationImpl.java:199)
        at java.text.MessageFormat.subformat(MessageFormat.java:1246)
        at java.text.MessageFormat.format(MessageFormat.java:836)
        at java.text.Format.format(Format.java:140)
        at java.text.MessageFormat.format(MessageFormat.java:812)
        at ch.qos.cal10n.MessageConveyor.getMessage(MessageConveyor.java:89)
        at org.jboss.weld.logging.WeldMessageConveyor.getMessage(WeldMessageConveyor.java:78)
        at org.slf4j.cal10n.LocLogger.debug(LocLogger.java:95)
        at org.jboss.weld.conversation.ConversationImpl.switchTo(ConversationImpl.java:190)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
        at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
        at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113)
        at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
        at org.jboss.weld.conversation.ConversationImpl_$$_javassist_2.switchTo(ConversationImpl_$$_javassist_2.java)
        at org.jboss.weld.conversation.AbstractConversationManager.beginOrRestoreConversation(AbstractConversationManager.java:137)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
        at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
        at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:113)
        at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
        at org.jboss.weld.conversation.ServletConversationManager_$$_javassist_0.beginOrRestoreConversation(ServletConversationManager_$$_javassist_0.java)
        at org.jboss.weld.jsf.WeldPhaseListener.initiateSessionAndConversation(WeldPhaseListener.java:171)
        at org.jboss.weld.jsf.WeldPhaseListener.beforeRestoreView(WeldPhaseListener.java:118)
        at org.jboss.weld.jsf.WeldPhaseListener.beforePhase(WeldPhaseListener.java:87)
        at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99)
        at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:111)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
    

    任何想法出了什么问题?

    谢谢!

3 个答案:

答案 0 :(得分:2)

要跟踪长时间运行的对话,Weld会在HTML表单的cid方法中插入action参数。

在您的情况下,您可以使用PostConstruct的{​​{1}}方法开始长时间对话。但counterBean首先在counterBean内引用h:form,因此在counterBean初始化时,h:form的标头已经呈现。您需要提前开始对话。

我不确定最好的方法是什么。可能就是这样:

<f:metadata>
    <f:event type="preRenderView" listener="#{someBean.init}"/>
</f:metadata>

您只能在GET请求上开始对话:

public void init() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
        conversation.begin();
    }
}

JSF 2.2有一个<f:viewAction>标签(类似于Seam页面操作),可以用来完成同样的事情。

或者,您可以将此EL表达式放在表单上方:

#{javax.enterprise.context.conversation.begin()}

但是你必须小心不要再次重新渲染这个表达式。


作为旁注,通常会在某些JSF操作上启动对话,例如单击按钮。需要牢记的是,为了正确的对话,需要重新传播传播形式。

答案 1 :(得分:1)

从CDI的角度来看,您的代码应该可以工作(它实际上适用于JBoss AS 6)。似乎发生的事情是对话不是在两个请求之间传播的,但是在使用JSF表单提交时应该是隐含的。我假设你的设置是错误的,Tomcat没有按原样配置。

首先,尝试手动传播会话ID,如here所述。

答案 2 :(得分:1)

我们已经看到了同样的问题,因此我们在开始对话后立即将重定向重新定向到页面。我们知道应用程序的哪些部分需要基于表单ID前缀的对话,因此可以在早期阶段监听器中执行此操作。还原视图后运行良好。我在从“还原前视图”执行重定向时遇到了问题,这将更加理想。

我最终使用了FacesContext.getExternalContext()。getRequest()中的HttpServletRequest,它可以提供重定向到的完整URL。我在代码中将其分解并重新组合 - 我们的代码结构和包含表单和参数概念的可重用类。删除了异常处理的sendRedirect是

ExternalContext external = faces.getExternalContext();
String baseUrl = external.getRequestContextPath() + m_formId;
String target = external.encodeRedirectURL(baseUrl, m_requestParameters);
external.redirect(target);