什么是EJB,它有什么作用?

163

一直在尝试学习什么是 EJB Bean,以及他们的实例为什么要被池化管理等问题,但无法真正掌握。

你能否解释一下他们到底是什么(对于Java程序员来说有什么实际意义)?他们都做些什么?它们的目的是什么?为什么真的要使用它们?(为什么不坚持使用POJO?)也许可以给出一个示例应用?

请只参考最新信息,即EJB 3.1。关于EJB的过时信息可能会误导。

对于EJB学习初学者请注意:

EJB基于分布式对象,这指的是在由网络连接的多个计算机(虚拟或物理)上运行的软件部件。


5个回答

173

为什么要使用它们?(为什么不只使用POJO?)

如果您需要一个访问数据库、访问其他连接性/目录资源、被多个客户端访问的组件,或者是用作SOA服务的组件,那么现在的EJB通常比POJO更“强大、快速(或至少更可扩展)和简单”。它们最有价值的是为网络或公司网络上的大量用户提供服务,对于部门内的小型应用程序来说,它们略显不足。

  1. 通过松耦合实现在多个应用程序/客户端之间共享逻辑。
    EJB可以封装为独立的JAR包,部署并从多个位置调用。它们是常见的组件。当然,POJO也可以(小心!)设计为库,并封装为JAR包。但是EJB支持本地和远程网络访问,包括通过本地Java接口、透明RMI、JMS异步消息和SOAP/REST Web服务,避免了使用多个(不一致的?)部署的复制粘贴JAR依赖关系。
    它们非常有用于创建SOA服务。当用于本地访问时,它们就是POJO(加上免费容器服务)。设计单独的EJB层促进了更大的关注最大化封装、松耦合和内聚,并促进了一个清晰的接口(Facade),遮蔽调用者复杂的处理和数据模型。

  2. 可扩展性和可靠性 如果应用程序从各种呼叫消息/进程/线程中发出大量请求,则它们首先分布在池中的可用EJB实例中,然后排队等待。这意味着,如果每秒传入的请求数量大于服务器可以处理的数量,我们可以优雅地降级——总是有一些请求被高效处理,而多余的请求则等待。我们不会出现服务器“崩溃”——所有请求都同时经历可怕的响应时间,并且服务器试图访问超过硬件和操作系统可以处理的更多资源,从而导致崩溃。EJB可以部署在单独的层上,可以进行集群化——这通过从一个服务器故障转移到另一个服务器来提供可靠性,而且可以添加硬件以实现线性扩展。

  3. 并发管理。 容器确保EJB实例由多个客户端安全(串行)访问。容器管理EJB池、线程池、调用队列,并自动执行方法级别的写锁定(默认)或读锁定(通过@Lock(READ))。这样可以防止数据在并发写-写冲突中损坏,并帮助数据通过防止读-写冲突而被一致地读取。
    这对于Singleton会话Bean特别有用,因为该Bean正在操作并共享跨客户端调用者的公共状态。这可以轻松地覆盖以手动配置或以编程方式控制并发代码执行和数据访问的高级场景。

  4. 自动化事务处理。
    什么也不用做,所有EJB方法都在JTA事务中运行。如果使用JPA或JDBC访问数据库,则会自动将其注册到事务中。对于JMS和JCA调用也是如此。在方法之前指定@TransactionAttribute(someTransactionMode)以指定该特定方法如何参与JTA事务,覆盖默认模式:“Required”。

  5. 通过注入非常简单地访问资源/依赖项。
    容器将查找资源并将资源引用设置为EJB实例字段:例如存储在JNDI中的JDBC连接、JMS连接/主题/队列、其他EJB、JTA事务、JPA实体管理器持久性上下文、JPA实体管理器工厂持久性单元和JCA适配器资源。 例如,设置对另一个EJB、JTA事务、JPA实体管理

    @Stateless
    public class MyAccountsBean {
    
        @EJB SomeOtherBeanClass someOtherBean;
        @Resource UserTransaction jtaTx;
        @PersistenceContext(unitName="AccountsPU") EntityManager em;
        @Resource QueueConnectionFactory accountsJMSfactory;
        @Resource Queue accountPaymentDestinationQueue;
    
        public List<Account> processAccounts(DepartmentId id) {
            // Use all of above instance variables with no additional setup.
            // They automatically partake in a (server coordinated) JTA transaction
        }
    }
    

    一个Servlet可以通过简单地声明实例变量来本地调用此Bean:

    @EJB MyAccountsBean accountsBean;    
    

    然后只需根据需要调用其方法。

  6. JPA的智能交互。默认情况下,上面注入的EntityManager使用事务作用域持久性上下文。这对于无状态会话bean非常完美。 当调用(无状态)EJB方法时,在新事务中创建一个新的持久化上下文,所有从DB检索/写入的实体对象实例仅在该方法调用内可见,并与其他方法隔离。 但是,如果方法通过调用其他无状态EJB,则容器会将同一PC传播并共享给它们,因此相同的实体会通过同一事务中的PC以一致的方式自动共享。 如果声明了@Stateful会话bean,则可以通过声明entityManager为扩展范围来实现与JPA的智能关联: @PersistentContent(unitName="AccountsPU, type=EXTENDED)。它存在于bean会话的整个生命周期中,跨多个bean调用和事务,在内存中缓存先前检索/编写的DB实体副本,因此不需要重新检索。

  7. 生命周期管理。EJB的生命周期由容器管理。根据需要,它创建EJB实例,清除和初始化有状态会话bean状态,使其处于被动和激活状态,并调用生命周期回调方法,因此EJB代码可以参与生命周期操作以获取和释放资源, 或执行其他初始化和关闭行为。它还捕获所有异常,记录它们,根据需要回滚事务,并抛出新的EJB异常或@ApplicationExceptions。

  8. 安全管理。可以通过简单的注释或XML设置配置对EJB的基于角色的访问控制。服务器自动将经过身份验证的用户详细信息与每个调用一起传递作为安全上下文(调用主体和角色)。 它确保自动执行所有RBAC规则,以便方法不能被错误的角色非法调用。它允许EJB轻松访问用户/角色详细信息以进行额外的编程检查。它允许以标准方式向容器插入额外的安全处理(甚至是IAM工具)。

  9. 标准化和可移植性。EJB实现符合Java EE标准和编码约定,促进质量和易于理解和维护。它还通过确保它们所有支持相同的标准特性和行为并防止开发人员意外采用专有的非可移植商家特性,从而促进代码到新供应商应用程序服务器的可移植性。

  10. 真正的关键点:简单性。所有这些都可以使用非常简化的代码完成-要么使用Java EE 6中的EJB默认设置,要么添加一些注释。在自己的POJO中编写企业/工业强度特性会更加冗长、复杂和容易出错。一旦开始使用EJB进行编码,它们就相当容易开发并提供了一系列“免费乘车”的好处。

在10年前的原始EJB规范中,EJB是一项生产力障碍。它们臃肿、需要大量的代码和配置文件,并且提供的好处只有三分之二左右。大多数 Web 项目实际上并没有使用它们。但是经过10年的调整、彻底改进、功能增强和开发流程优化,这已经发生了显着变化。在Java EE 6中,它们提供了最高级别的工业强度和易用性。

有什么不喜欢的呢??:-) :-)


71

EJB是一个Java组件,包含业务逻辑,您可以在容器中部署它,并从容器提供的技术服务中受益,通常以声明方式进行注释:

  • 事务管理:可以在调用EJB方法之前自动启动事务,并在该方法返回后提交或回滚。此事务上下文会传播到对其他EJB的调用中。
  • 安全管理:可以检查调用者是否具有执行该方法所需的角色。
  • 依赖注入:其他EJB或资源(如JPA实体管理器、JDBC数据源等)可以注入到EJB中。
  • 并发性:容器确保一次只有一个线程调用您的EJB实例的方法。
  • 分布式:某些EJB可以从另一个JVM远程调用。
  • 故障转移和负载平衡:您的EJB的远程客户端可以自动将其调用重定向到另一台服务器。
  • 资源管理:有状态bean可以自动被写入磁盘进行休眠,以限制服务器的内存消耗。
  • ...我可能忘记了一些要点。

1
当你提到事务时,你是在提到持久性吗? - jacktrades
8
是的,但不仅如此。EJB容器提供了分布式JTA事务管理器,可以支持在单个事务中处理多个资源。例如,在单个事务中更新数据库数据并发送一些JMS消息。如果出现任何问题,所有操作都会被回滚:包括数据库更新和已发送的消息。 - JB Nizet
@JBNizet 不好意思打扰这个旧帖子,但是像 Spring 这样的非 EJB 框架提供了你提到的这些服务。我不明白它们之间的区别。 - MoienGK
基本原则是相同的。Spring 借鉴了 EJB 的思想,反之亦然。但 API、实现方式、部署方式和一些特性是不同的。 - JB Nizet
在MVC模式中,通常应该将EJB放置在哪里?我认为它们属于Model层,尽管我知道很多人认为它们是控制器。如果EJB包含业务逻辑(你说过它们确实包含),那么根据定义,它们就是Model层。 - user107986

21
希望这篇来自Oracle文档的内容能够帮助像我一样的人以简单的方式理解EJB主题。
企业Bean是什么? 用Java编程语言编写的企业Bean是一个在服务器端操作的组件,封装了应用程序的业务逻辑。业务逻辑是实现应用程序目的的代码。例如,在库存控制应用程序中,企业Bean可以在方法中实现业务逻辑,称为checkInventoryLevel和orderProduct。通过调用这些方法,客户端可以访问应用程序提供的库存服务。
企业Bean的好处: 由于EJB容器为企业Bean提供系统级服务,因此企业Bean能够简化大型分布式应用程序的开发。首先,bean开发人员可以专注于解决业务问题,因为EJB容器负责处理系统级服务,例如事务管理和安全授权,而不是bean开发人员。
其次,由于bean而不是客户端包含应用程序的业务逻辑,客户端开发人员可以专注于客户端的展示。客户端开发人员无需编写实施业务规则或访问数据库的程序,因此客户端更轻巧,对于在小型设备上运行的客户端尤其重要。
第三,由于企业Bean是可移植组件,因此应用程序装配器可以从现有的bean构建新应用程序。只要使用标准API,这些应用程序就可以在任何兼容的Java EE服务器上运行。
何时使用企业Bean 如果您的应用程序具有以下任何要求,则应考虑使用企业Bean:
应用程序必须具有可扩展性。为了适应不断增长的用户数量,您可能需要将应用程序的组件分布在多台计算机上。一个应用程序的企业Bean不仅可以在不同的计算机上运行,而且它们的位置对客户端透明。
事务必须确保数据完整性。企业Bean支持事务,这些机制管理共享对象的并发访问。
应用程序将拥有各种客户端。只需几行代码即可创建Web客户端、Java客户端、CORBA客户端以及其他类型的客户端。通过代码中的注释,远程客户端可以轻松地找到企业级Bean。这些客户端可以是轻量级、各种各样和众多的。

4
我最感兴趣的问题是如何以及在哪里使用它们。要理解这一点,我们首先需要看看存在哪些类型的EJBs。有两大类:
  1. 会话bean
  2. 消息驱动bean
让我们考虑Session Beans。它们分为三种:
  1. 有状态 - 这些组件维护状态,并且对于多个请求中的客户端是特定的。将其视为会话。这些可能立即用于购物车或其他类型的会话(登录会话等)。
  2. 无状态 - 这些是自包含的组件,不在请求之间保留信息,但对于用户是唯一的。脑海中浮现出的即时使用-服务层中的服务类。想象一下OrderService。这些的另一个重要用途是公开Web服务。同样,这可以在服务层中或完全分开。
  3. 单例 - 这些是每个应用程序都存在的bean,并且只创建一次并且可以被重用/多次访问。立即想到的是Configuration组件-您可以在其中存储应用程序级别的配置,并在需要时从任何位置访问它们。
现在,其余的功能或特性可以在任何此类情况下跨层使用:
  • 安全性 - 您可以在调用的方法上使用注释检查权限。这可以在服务层以及控制器中发生。
  • 事务管理 - 这是服务层或持久性层中的明显候选者
  • 依赖注入 - 再次将在各处使用
在现代时代,一个重要应用是所谓的微服务和面向服务的架构。您可以将一些业务逻辑组件打包为EJB,并将它们分布在整个组织中,供多个客户端(此处的客户端指其他后端应用程序)使用。
等等。现在的一个大缺点是您变得非常依赖于EJB容器,尽管您可以在两个引用实现之间切换,但您将无法切换到更轻的Tomcat之类的东西。但是为什么要牺牲所有好处呢?

0

EJB 是分层应用程序中业务逻辑所在的地方。按照这个模型,一个层(不同于一个层)可以独立地从用户和其他接口访问,因此它们可以通过多个协议部署和访问多个组件。

在规范化系统模型中,EJB 是“操作”和“工作流程”,而 Servlet 将是“接口”,JCA 是“连接器”,计时器和 JMS 是“事件”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接