我对JSF2 + Spring + EJB3的混合使用或它们的任何组合感到有些困惑。我知道Spring的主要特征之一就是依赖注入,但是有了JSF托管的Bean,我可以使用@ManagedBean和@ManagedProperty注释,并且可以获得依赖注入功能。对于EJB3,我更困惑何时与JSF一起使用它,或者甚至有理由使用它。
那么,在哪种情况下使用Spring + JSF2或EJB3 + JSF2是一个好主意?
到现在为止,我仅使用JSF2仅创建了一些小型Web应用程序,而从未使用过Spring或EJB3。但是,我在很多地方看到人们正在一起处理所有这些东西。
首先,Spring和EJB(+ JTA)是竞争技术,通常不能在同一应用程序中一起使用。选择一个或另一个。Spring 或 EJB(+ JTA)。我不会告诉你选择哪个,我只会告诉你一些历史和事实,以便你更轻松地做出决定。
他们试图解决的主要问题是提供具有自动事务管理功能的业务服务层API。想象一下,你需要触发多个SQL查询来执行一个业务任务(例如下订单),而其中一个失败,那么你当然会想一切都回滚了,以便数据库保持相同的状态像以前一样,好像什么也没有发生。如果你不使用事务,那么数据库将处于无效状态,因为第一批查询实际上已经成功。
如果你熟悉基本的JDBC,那么你就应该知道,这可以通过关闭自动提交的连接,然后烧制这些查询的顺序,然后进行实现commit()以非常相似try的,其catch (SQLException)一个rollback()执行。但是,每次实施都非常繁琐。
commit()
catch (SQLException)
rollback()
使用Spring和EJB(+ JTA),默认情况下,单个(无状态)业务服务方法调用透明地计为单个完整事务。这样,你完全不必担心事务管理。你不需要手动创建EntityManagerFactory,也不需要显式调用em.getTransaction().begin(),就像将业务服务逻辑紧密耦合到JSF支持bean类和/或在JPA 中使用RESOURCE_LOCAL而不是JTA那样时。例如,你可以仅具有以下利用JPA的EJB类:
EntityManagerFactory
em.getTransaction().begin()
@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); } }
如果你@EJB private OrderService orderService;在JSF支持bean中具有并orderService.placeOrder(newOrder);在action方法中调用,则将执行单个完整事务。例如,如果某个updateQuantity()调用或该persist()调用因异常而失败,则它将回滚所有迄今已执行的updateQuantity()调用,并使数据库保持干净整洁的状态。当然,你可以在JSF支持bean中捕获该异常并显示Faces消息左右。
@EJB private OrderService orderService;
orderService.placeOrder(newOrder)
updateQuantity()
persist()
应该指出的是,“ Spring”是一个相当大的框架,不仅可以与EJB竞争,而且还可以与CDI和JPA竞争。以前,在黑暗的J2EE时代,EJB 2.x的实现极其糟糕(上述EJB 3.x OrderService示例在EJB 2.x中将需要至少5倍的代码和一些XML代码)。Spring提供了一个更好的替代方法,它需要更少的Java代码(但仍然需要许多XML代码)。J2EE / EJB2从Spring汲取了教训,并随Java EE 5一起提供,Java EE 5提供了新的EJB3 API,该API比Spring更加精巧并且完全不需要XML。
Spring还提供了开箱即用的IoC / DI(控制反转;依赖注入)。这是在XML所配置的J2EE时代中,这可能太过分了。如今,Spring还使用注释,但是仍然需要一些XML。从Java EE 6开始,从Spring汲取了教训之后,CDI即可提供相同的DI功能,但是不需要任何XML。使用Spring DI @Component/ @Autowired和CDI @Named/ @Inject可以实现与JSF使用@ManagedBean/相同的效果@ManagedProperty,但Spring DI和CDI围绕它提供了更多优势:例如,你可以编写拦截器来对托管bean的创建/销毁进行预处理或后处理,或者托管bean方法的调用,还可以创建自定义范围,生产者和使用者。可以在范围更广的实例中注入范围更窄的实例,依此类推。
DI @Component/ @Autowired和CDI @Named/ @Inject
@ManagedBean/
@ManagedProperty
Spring还提供了本质上可以与JSF竞争的MVC。将JSF与Spring MVC混合是没有意义的。此外,Spring还提供了数据,该数据本质上是JPA上的一个额外抽象层,从而进一步减少了DAO样板(但它实际上并不代表整个业务服务层)。