【问题标题】:Correct Usage of Stateful Session Bean in EJB在 EJB 中正确使用有状态会话 Bean
【发布时间】:2013-09-10 14:11:51
【问题描述】:

我正在尝试构建一个测试网站,显示有关 JSF 2.0、EJB 3.1 和 JPA 2.0 学生的各种信息。

学生登录后,可以浏览不同的页面,显示不同的信息,这就是通常的注册管理系统所做的。比如说在一个页面中根据注册信息显示时间表,在另一页面中显示作业。将显示的信息包括学生的属性、映射的实体(如注册课程、提交的作业等)。

一开始,我尝试创建一个无状态的bean并获取每个页面所需的信息,并更改student的一些属性

@Entity
public class Student{
    @Id
    private String sid;
    private String address;
    @ManyToMany
    private List<Assignment> submittedAssignments;
    @ManyToMany
    private List<Course> courses;
}
@Stateless
@LocalBean
public class studentDao {
    @PersistenceContext(unitName="PU")
    private EntityManager em;

    public Student getStudent(String sid){
        return em.find(Student.class, sid);
    }
    public List<Course> getCoursesByStudent(String sid){
    return em.find(Student.class, sid).getCourses();
    }
    public List<Assignment> getAssignmentsByStudent(String sid){
        return em.find(Student.class, sid).getSubmittedAssignments();
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void ChangeAddress(String sid, String newAddress){
        em.find(Student.class, sid).setAddress(newAddress);
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void SubmitAssignment(String sid, Assignment submittedAssignment){
    }
    //Some more methods, just list a few for illustration.
}

@ManagedBean
@SessionScoped
public class LoginSession{
    private String sid;
    //getter
    public login(String sid){
        //probably will need password validation later, so I have to connect to db and check the password.
        this.sid=sid;
    }
}

@ManagedBean
@RequestScoped
public class AssignmentBean{
    @EJB
    private StudentDao studentDao;
    @ManagedProperty(value="#{loginSession}")
    private LoginSession session;

    public List<Assignment> getAssignments(){
        return studentDao.getAssignmentsByStudent(session.sid);
    }
}

assignment.xhtml:

<h:datatable value="#{assignmentBean.assignments}"></h:datatable>

然后,我发现将student从托管bean传递到无状态ejb,一次又一次地检索student,然后只将部分信息返回给ManagedBean进行显示,因此我认为我可以这样做。

@Stateful
@LocalBean
public class studentDao {
    @PersistenceContext(unitName="PU", type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    private Student currentStudent;

    public void login(String sid){
        //didn't make a password, just type sid and done.
        currentStudent = em.find(Student.class, sid);
    }
    public Boolean getLoggedIn(){
        return currentStudent != null;
    }
    public Student getCurrentStudent(){
        return currentStudent;
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void ChangeAddress(String newAddress){
        currentStudent.setAddress(newAddress);
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void SubmitAssignment(Assignment submittedAssignment){
    }
}

@ManagedBean
@SessionScoped
public class LoginSession{
    @EJB
    private StudentDao studentDao;

    public login(String sid){
        studentDao.login(sid);
    }
}

assignment.xhtml:

<h:datatable value="#{loginSession.studentDao.currentStudent.submittedAssignments}"></h:datatable>

由于currentStudent 与扩展的持久性上下文一起存在,我可以直接检索信息。而且我不必为每个操作一次又一次地将 SID 传递给 EJB,也可以一次又一次地申请找到那个学生,因为它已经在那里管理了。

我不确定这是否是对@Stateful bean 的滥用,因为页面是一大群对话,不像常见的“购物车”示例,用户可以选择很多订单,付款,然后提交验证和用户确认后的所有数据库更改。

请评论上述 SFSB 的使用是否是对 SFSB 的滥用,以及为什么是滥用,或者上述两种设计中的哪一种更好(或者如果两者都不好,因为我是第一次写作,请建议另一种一个从废品开始的 Web 应用程序,但有几本书来自 Apress,那些从 Pro 开始,EJB3、JPA、JSF、Java EE 6 和 glassfish 等)。

谢谢。

【问题讨论】:

    标签: jsf jakarta-ee web-applications jpa ejb


    【解决方案1】:

    如果您使用有状态会话 bean,EJB 容器会代表您的客户端管理状态,因此无需传递 ID:这样更方便。

    在你的情况下没关系。

    一般来说,考虑以下项目:

    • 无状态服务有时更容易测试:如果您编写测试用例,则不必考虑对状态的副作用。
    • 如果有状态会话 bean 保存缓存数据,则必须处理缓存失效。
    • 如果您的会话 bean 是 @Remote:如果客户端和服务器不在同一个 JVM 上,则每个方法调用都需要编组,并通过网络进行。
    • 如果您有大量在服务器端消耗资源的有状态会话:您已经有两个Lists,它们的数量和内容很可能会随着时间的推移而增长。例如,使用无状态设置,您可以设计一个仅在浏览器中管理状态的应用程序。
    • 如果其他人正在使用您舒适的有状态 API,而您以后必须对其进行更改,那么您将有无休止的讨论。

    出于这些原因,我总是更喜欢使用数据传输对象的无状态设置。但同样,在你的情况下没关系。

    【讨论】:

    • 谢谢,我意识到我的设计存在缺陷,只需在无状态设置中传递密钥实际上简化了其他事情。例如,缓存的外部更新数据实际上会使程序复杂化。
    • 我已将有关缓存失效的项目添加到答案中。在这个问题上您需要更多帮助吗?
    猜你喜欢
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 2012-04-04
    • 2013-04-30
    • 2017-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多