EJB对于应用程序的状态参数所扮演的重要角色给予充分关注,提供了较高级别的结构——SFSB(状态会话 bean),专门用来管理状态会话。在应用组件中采用SFSB模式之后,对于组件的调用将自动共享同一个bean实例以及相应的状态。SFSB在设计上充分考虑了伸缩性和可靠性,具体的实现方式由厂商决定。Spring没有和SFSB直接对应的结构,而是通过其它多种技术途径的组合来达到同样的目标。
状态管理——功能性比较
图3通过机票预订流程的各个步骤,阐述了Spring 和 EJB 3.0管理状态的方式。

图3. 机票预订序列图。旅客通过一系列与订票代理的交互过程进行订票操作,每个步骤都会在会话场景产生相应的状态。
public void testPurchaseTicket_UseCase() throws Exception
...{
//开始购票会话
FlightCriteria flightCriteria = new FlightCriteria("DFW", "AUS", DateUtilities.parseDate("2006-01-15"));
bookingAgent.bookRoundTripTicket(flightCriteria);
![]()
//选择离港航班
List outboundFlights = bookingAgent.listOutboundFlights();
assertEquals(3, outboundFlights.size());
bookingAgent.selectOutboundFlight(selectFlight(outboundFlights, 1));
![]()
//选择返程航班
List<Flight> returnFlights = bookingAgent.listReturnFlights();
assertEquals(3, returnFlights.size());
bookingAgent.selectReturnFlight(selectFlight(returnFlights, 2));
![]()
//选择旅客
Passenger passenger = new Passenger("Rod", "Coffin");
bookingAgent.selectPassenger(passenger);
![]()
//选择座位
bookingAgent.selectOutboundSeat(selectSeat
(bookingAgent.retrieveCurrentTicket().getOutboundFlight(), "1B"));
bookingAgent.selectReturnSeat(selectSeat
(bookingAgent.retrieveCurrentTicket().getReturnFlight(), "1A"));
![]()
//购票
Ticket ticket = bookingAgent.purchaseTicket();
assertTrue(ticket.getId() != 0);
}
![]()
以下是基于Spring的实现:
![]()
public class BookingAgentSpring implements BookingAgent
...{
private FlightCriteria outboundCriteria;
private FlightCriteria returnCriteria;
private Ticket ticket;
![]()
public Ticket bookRoundTripTicket(FlightCriteria flightCriteria)
...{
outboundCriteria = flightCriteria;
returnCriteria = reverseCriteria(flightCriteria);
ticket = new Ticket();
ticketDAO.save(ticket);
return ticket;
}
...
}
以下的单元测试验证订票代理对象以有状态的方式交互。
为了在Spring中实现bean的状态管理,在bean的调用对象之间不能共享bean实例。因此,状态bean的作用域的属性配置为“原型”级别,这意味着要从bean工厂每次生成一个新的bean实例。
<bean id="bookingAgentSpring" scope=”prototype”
class="org.jug.flight.booking.spring.BookingAgentSpring">
...
</bean>
而EJB 3.0的处理方式如下:
@Stateful
public class BookingAgentEJB implements BookingAgent
...{
private FlightCriteria outboundCriteria;
private FlightCriteria returnCriteria;
private Ticket ticket;
![]()
public Ticket bookRoundTripTicket(FlightCriteria flightCriteria)
...{
outboundCriteria = flightCriteria;
returnCriteria = reverseCriteria(flightCriteria);
ticket = new Ticket();
ticketDAO.save(ticket);
return ticket;
}
...
}
从上例可见,Spring 和 EJB 3.0在保存状态的具体处理方式上差异较大。