在EJB中正确使用有状态会话Bean [英] Correct Usage of Stateful Session Bean in EJB

查看:150
本文介绍了在EJB中正确使用有状态会话Bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



起初,我尝试创建一个无状态bean并获取信息每个页面需要更改学生的某些属性

  @Entity 
public class Student {
@ Id
private String sid;
private String address;
@ManyToMany
私人列表<作业> submittedAssignments;
@ManyToMany
私人列表<课程>培训班;
}
@Stateless
@LocalBean
public class studentDao {
@PersistenceContext(unitName =PU)
private EntityManager em;

public Student getStudent(String sid){
return em.find(Student.class,sid);
}
public List<课程> 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){
}
//更多的方法,只列出几个为了说明。
}

@ManagedBean
@SessionScoped
public class LoginSession {
private String sid;
// getter
public login(String sid){
//以后可能需要密码验证,所以我必须连接到db并检查密码。
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> 

然后,我发现将学生从托管bean传递给无状态ejb,检索学生,一次又一次,只返回一部分信息给ManagedBean进行显示,所以我想我可以这样做。

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

public void login(String sid){
//没有输入密码,只需输入sid并完成。
currentStudent = em.find(Student.class,sid);
}
public Boolean getLoggedIn(){
return currentStudent!= null;
}
public学生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,为什么如果滥用或上述两种设计中的哪一种更好(或者如果两者都不好,建议另外一种,因为我是第一次从废品开始撰写网络应用程序,而是从Apress开始的几本书,那些从Pro开始的那些EJB3,JPA ,JSF,Java EE 6 with glassfish等)。



谢谢。

解决方案>

如果使用有状态会话bean,EJB容器将代表您的状态管理状态客户端,所以没有必要传递一个ID:更舒服。



在你的情况下可以。



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




  • 无状态服务有时会更容易测试:如果您编写测试用例,您不必考虑对状态的副作用。

  • 如果您的有状态会话bean包含缓存数据,则必须处理缓存无效。

  • <如果您的会话bean是 @Remote :如果客户端和服务器不在同一个JVM上,则每个方法调用都需要编组,并通过网络。
  • 如果您有很多有状态会话在服务器端消耗资源:您已经有两个列表,他们的号码和内容将最有可能成长的时间。例如,使用无状态设置,您可以设计一个仅在浏览器中管理状态的应用程序。

  • 如果有人正在使用您舒适的状态API,并且必须稍后更改您将无休止地讨论



由于这些原因,我总是喜欢使用数据传输对象 。但是再一次,在你的情况下可以。


I am trying to construct a test website that display various information about a student with JSF 2.0, EJB 3.1 and JPA 2.0.

After a student login, the student can browse different pages for displaying different kind of information, which is what a usual registration management system does. Say displaying a timetable according to enrollment information in one page, and display the assignments in another page. Information that will be displayed include attributes of the student, mapped entities like registered course, assignment submitted etc.

At first, I tried to create a stateless bean and get the information required for each page, and change some attributes of 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>

And then, I find it quite tedious to pass student from managed bean to stateless ejb, retrieve student, again and again, then return only a part of information to ManagedBean for display, therefore I think I can do it like this.

@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>

As the currentStudent lives with the extended persistence context, I can retrieve the information directly. And I do not have to pass SID to EJB again and again for each operation, also applies for finding that student again and again as it is already there managed.

I am not sure if it is an abuse of @Stateful bean as the pages had been a large group of conversations, unlike the common "shopping cart" example where user can choose a lot of orders, make payment, then commit all database changes after validation and user confirm.

Please comment on the above SFSB usage whether it is an abuse of SFSB and why if it is an abuse, or which one of the above two designs is better (or suggest another if both were bad as I am the first time writing a web application starting from scrap but a few books from Apress, those started with Pro whatever, EJB3, JPA, JSF, Java EE 6 with glassfish etc).

Thank you.

解决方案

If you use stateful session beans, the EJB container manages state on behalf of your client, so there is no need to pass around an ID: It's more comfortable.

In your case it's OK.

Generally speaking, consider these items:

  • Stateless services are sometimes a little bit easier to test: If you write a test case, you do not have to consider the side-effects on the state.
  • If your stateful session bean holds cached data, you have to handle cache invalidation.
  • If your session bean is @Remote: If client and server are not on the same JVM, each method call requires marshalling, and goes over the network.
  • If you have lots of stateful sessions which consume resources on the server side: You already have two Lists there, and their number and their content will most likely grow over the time. Using a stateless setup, you can design an application where the state is only managed in the browser, for example.
  • If someone else is using your comfortable stateful API, and you must change it later, you will have endless discussions.

For these reasons I always prefer the stateless setup using data transfer objects. But again, in your case it's OK.

这篇关于在EJB中正确使用有状态会话Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆