【问题标题】:SFSB being removedSFSB 被移除
【发布时间】:2012-06-10 22:34:54
【问题描述】:

我正在使用 JBoss6.1.Final、JSF 2.0 (Mojarra)、Weld CDI、MyFaces CODI 1.0.5(用于视图访问范围)

我正在使用类似于Real World Java EE Patterns Rethinking Best Practices 的网关模式(不幸的是我没有它,所以我可能在这里搞砸了)。基本上,该应用程序允许用户进入“编辑模式”并编辑在具有扩展持久性上下文的 @ViewAccessScoped 支持 bean 中维护的人员列表(创建、编辑、删除),然后单击刷新的“保存”命令链接他们对数据库的所有更改。起初我遇到了 ViewExpiredExceptions 的问题(如果浏览器在会话超时期间空闲,然后执行了进一步的请求),但我添加了一些 jQuery 来向保持会话活动的 servlet 发出 get 请求(称为 10会话超时前的秒数)。这似乎工作,但现在我有另一个问题,支持 bean 也是一个 SFSB 并且在一些空闲时间后,它被删除,导致在我尝试执行时记录以下错误消息(并且所有 ajax 呈现的数据都消失)更多编辑...

13:06:22,063 严重 [javax.enterprise.resource.webcontainer.jsf.context] javax.el.E​​LException: /index.xhtml @27,81 渲染="#{!conversationBean.editMode}": javax. ejb.NoSuchEJBException: 找不到有状态 bean: 43h1h2f-9c7qkb-h34t0f34-1-h34teo9p-de

关于如何防止 SFSB 删除或至少更优雅地处理它的任何想法?

这是我的支持 bean:

package com.ray.named;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.EJBTransactionRolledbackException;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ViewAccessScoped;

import com.ray.model.Person;

@Named
@Stateful
@ViewAccessScoped
@TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER)
public class ConversationBean implements Serializable {
  private static final long serialVersionUID = 1L;
  //properties
  private List<Person> people;
  private String name;
  private Boolean editMode;

  @PersistenceContext(type=PersistenceContextType.EXTENDED)
  private EntityManager em;

  @PostConstruct
  public void init() {
    people = em.createNamedQuery("Person.findAll", Person.class).getResultList();
    setEditMode(false);
  }

  //event listeners
  public void beginEdits() {
    setEditMode(true);
  }

  public void addPerson() {
    Person p = new Person(name);
    em.persist(p);
    people.add(p);
    name = null;
  }

  public void removePerson(Person p) {
    people.remove(people.indexOf(p));
    em.remove(p);
  }

  //this method flushes the persistence context to the database
  @TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
  public void saveEdits() {
    setEditMode(false);
  }

  //getters/setters
  public List<Person> getPeople() {
    return people;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Boolean getEditMode() {
    return editMode;
  }

  public void setEditMode(Boolean editMode) {
    this.editMode = editMode;
  }
}

这是 Person 实体 bean:

package com.ray.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Version;

@Entity
@NamedQueries({
  @NamedQuery(name="Person.findAll",
              query="SELECT p FROM Person p")
})
public class Person {
  @Id @GeneratedValue(strategy=GenerationType.IDENTITY) 
  private Integer id;
  private String name;
  @Version
  private int version;

  public Person() { }

  public Person(String name) {
    setName(name);
  }

  public boolean equals(Object o) {
    if (!(o instanceof Person)) {
      return false;
    }
    return id == ((Person)o).id;
  }

  //getters/setters
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

  public Integer getId() {
    return id;
  }

  public int getVersion() {
    return version;
  }

  public void setVersion(int version) {
    this.version = version;
  }
}

这是视图:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
  <script>
  $(document).ready(function() {
    setInterval(function() {
      $.get("#{request.contextPath}/poll");
    }, #{(session.maxInactiveInterval - 10) * 1000});
  });
  </script>
  <title>Conversation Test</title>
</h:head>
<h:body>
  <h:form>
    <h:commandLink value="Begin Edits" rendered="#{!conversationBean.editMode}">
      <f:ajax render="@form" listener="#{conversationBean.beginEdits}"/>
    </h:commandLink>
    <h:commandLink value="Save" rendered="#{conversationBean.editMode}">
      <f:ajax render="@form" listener="#{conversationBean.saveEdits}"/>
    </h:commandLink>
    <h:dataTable id="peopleTable" value="#{conversationBean.people}" var="person">
      <h:column>
        <f:facet name="header">Name</f:facet>
        <h:panelGroup>
          <h:inputText value="#{person.name}" disabled="#{!conversationBean.editMode}">
            <f:ajax/>
          </h:inputText>
          <h:commandLink value="X" disabled="#{!conversationBean.editMode}">
            <f:ajax render="@form" listener="#{conversationBean.removePerson(person)}"/>
          </h:commandLink>
        </h:panelGroup>
      </h:column>
    </h:dataTable>
    <h:panelGrid columns="2">
      <h:outputLabel for="name">Name:</h:outputLabel>
      <h:inputText id="name" value="#{conversationBean.name}" disabled="#{!conversationBean.editMode}"/>
    </h:panelGrid>
    <h:commandButton value="Add" disabled="#{!conversationBean.editMode}">
      <f:ajax execute="@form" render="@form" listener="#{conversationBean.addPerson}"/>
    </h:commandButton>
  </h:form>
</h:body>
</html>

这是一个用于保持会话活动的 servlet(在会话过期前 10 秒由 jQuery ajax 获取请求调用):

package com.ray.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PollServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  public void init() throws ServletException {
  }

  public String getServletInfo() {
    return null;
  }

  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    request.getSession(); //Keep session alive
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
  }

  public void destroy() {
  }
}

【问题讨论】:

    标签: jsf-2 cdi ejb-3.1 jboss6.x codi


    【解决方案1】:

    关于如何防止 SFSB 删除或至少处理它的任何想法 更优雅?

    为了进一步调查,我建议查看钝化 的 EJB 生命周期挂钩,并在其中添加一些调试输出。

    如果这是问题的根源,您将能够配置/停用钝化 - 但可扩展性可能会成为一个问题。

    老实说,这种情况对我来说似乎并不常见。一般来说,我希望请求/对话/会话或多或少在默认边界内工作 - 如果您发现自己编写的代码可以规避这种情况,是不是您最好使用 RESTful / 无状态方法...?

    如果有更多信息,请更新问题。

    【讨论】:

    • 再次感谢 Jan。只是好奇,您是否发现我的示例代码有任何缺陷?你有什么不同的做法吗?
    • 我添加了一个 @PrePassivate 注释方法,可以看到支持/会话 bean 确实被钝化了。我正在试验 RichFaces a4j:poll 的间隔比 session.maxInactiveInterval 少 10 秒,这似乎可以解决问题。只要浏览器窗口打开,会话就会保持活动状态。
    • @Jasonl(#1) 不,您的代码没有任何问题。我不能像我在答案中所做的那样更好地表达自己......
    • 谢谢 Jan。您的帮助非常大!
    • 不客气 - 如果您想从更一般的角度讨论您的架构,您可能需要打开一个新问题,在其中提供有关您的应用程序的更多信息...
    【解决方案2】:

    我想你已经解决了你的问题。否则,这个 JBoss wiki 页面应该会有所帮助(也对未来的读者...)。

    https://community.jboss.org/wiki/Ejb3DisableSfsbPassivation

    干杯, 路易吉

    【讨论】:

      猜你喜欢
      • 2011-06-06
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 2018-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多