首先,Spring和EJB(+JTA)是竞争性技术,通常不会在同一个应用程序中同时使用。选择其中一个。Spring或者EJB(+JTA)。我不会告诉你该选择哪一个,我只会给你一些历史和事实,以便于你更容易做出决定。
它们试图解决的主要问题是提供具有自动事务管理的业务服务层API。想象一下,您需要发出多个SQL查询才能执行单个业务任务(例如下订单),其中一个查询失败了,那么您当然希望所有都可以回滚,以便将数据库保持为与之前完全相同的状态,就像完全没有发生任何事情一样。如果您没有使用事务,则数据库将处于无效状态,因为第一组查询实际上已成功执行。
如果您熟悉基本的JDBC,则应该知道可以通过在连接上关闭自动提交,然后按顺序发送这些查询,然后在catch (SQLException)
中执行rollback()
之前在同一个try
块中执行commit()
来实现这一点。然而,这很烦琐,需要每次都手动实现。
使用Spring和EJB(+JTA),默认情况下,单个(无状态的)业务服务方法调用会透明地计算为一个完整事务。这样,您就不需要担心事务管理了。您不需要手动创建EntityManagerFactory
,也不需要像将业务服务逻辑紧密耦合到JSF后备bean类中或在JPA中使用RESOURCE_LOCAL
而不是JTA
时那样明确调用em.getTransaction().begin()
等。例如,您可以只有以下使用JPA的EJB类:
@Stateless
public class OrderService {
@PersistenceContext
private EntityManager em;
@EJB
private ProductService productService;
public void placeOrder(Order newOrder) {
for (Product orderedproduct : newOrder.getProducts()) {
productService.updateQuantity(orderedproduct);
}
em.persist(newOrder);
}
}
如果你的JSF后备bean中有@EJB private OrderService orderService;
,并在动作方法中调用orderService.placeOrder(newOrder);
,那么将执行单个完整事务。例如,如果updateQuantity()
调用或persist()
调用之一失败并引发异常,则会回滚到目前为止执行的任何updateQuantity()
调用,并使DB处于干净和清晰状态。当然,你可以在JSF后备bean中捕获该异常并显示faces消息之类的内容。
需要注意的是,“Spring”是一个相当大的框架,它不仅与EJB竞争,还与CDI和JPA竞争。以前,在黑暗的J2EE时代,当EJB 2.x难以实现时(上述EJB 3.x OrderService
示例需要至少5倍的代码以及一些XML代码),Spring提供了一个更好的选择,其要求更少的Java代码(但仍需要很多XML代码)。J2EE/EJB2从Spring中吸取了教训并推出了Java EE 5,该版本提供了新的EJB3 API,比Spring更加流畅,而且根本不需要XML。
Spring还提供IoC/DI(控制反转;依赖注入)。在J2EE时代,这是通过XML配置的,但现在已经不再需要。自从Java EE 6之后,CDI就可以提供同样的DI功能,而且根本不需要XML。使用Spring DI @Component
/@Autowired
和CDI @Named
/@Inject
,你就可以像JSF使用@ManagedBean
/@ManagedProperty
一样实现相同的功能,但是Spring DI和CDI还提供了许多其他优势:例如,你可以编写拦截器来预处理或后处理托管bean的创建/销毁或托管bean方法调用,可以创建自定义作用域、生产者和消费者,可以将较窄范围的实例注入到较宽范围的实例中等。
Spring还提供MVC,与JSF竞争。将JSF与Spring MVC混合使用没有任何意义。此外,Spring还提供Data,这实际上是JPA上的额外抽象层,最小化DAO样板代码(但并不完全代表业务服务层)。
另请参阅:
t = em.getTransaction()
,t.begin()
,t.commit()
等)。JPA不是事务管理API,而是ORM API。 - BalusC