EJB的用处是什么?

29

我目前正在学习Java-EE,有丰富的C++经验并学习过Java SE。我不理解企业级Java Bean的目的; 能否有人为我澄清一下这一点。我对传统用法不感兴趣: 这是在EJB-3.1和Java-EE 6的背景下。

似乎有些人将它们用于包含业务逻辑,实现传统三层架构的业务层。这将领域逻辑与领域对象分离,导致贫血领域模型。但这违反了我所有面向对象设计(OOD)的本能; 我同意Martin Fowler的观点,认为这是一种反模式。我应该放松对贫血领域模型的反对意见吗?或者EJB还有其他用处吗?


2
这是一种反模式,这就是为什么Java EE多年来一直在衰退。10年前它可能看起来是个好主意。我不会放松你的正确反对意见,而是避免首先进入EJB。 - Elad
5
Elad:下降了 - 你从哪里得到这个想法的? - Heiko Rupp
8
@Elad: 看起来你在过去五年中没有了解Java EE。它有了很大的改进,非常值得重新流行起来。 - Michael Borgwardt
1
@Elad:Java EE不仅仅是EJB的容器,即使没有引入EJB 3.x,它仍然非常强大。 - Lukas Eder
相关问题:https://dev59.com/wHE95IYBdhLWcg3wY85l - Raedwald
7个回答

23
正如其他答案所指出的,EJB非常适合实现服务层。它们是Java EE中一种非常现代、轻量级的Bean。尽管名字相同,但您不能将它们与J2EE中的重型EJB2比较。每个人都认为那些是灾难性的,但这已经不是2002年了。
自从EJB3(2006年)以来,EJB Bean已经成为一种完全可以使用的技术。
它们通过提供声明式事务(如果没有正在进行的事务,则每个入口方法会自动开始一个事务,但如果需要,可以更改此行为)、池化、安全、锁定、远程访问等方面极大地帮助了我们。请参阅以下答案以获取更多详细信息:
- 可重用架构的分层框架 - 在什么情况下会使用EJB?网站/ Web应用程序开发是否需要它们? - EJB 3还是Hibernate 3 - @EJB注入与查找 - 性能问题 事务已经在这里解释过了,但是要补充一点:这不仅用于高度复杂、高度安全的系统。我甚至认为即使只处理数据库,它也是一个基本要求。如果我处理一个简单的订单,我希望库存和订单都被更新或者都没有被更新。这就像在数据库中使用主键和外键来确保完整性一样基本。

EJB使事务管理变得十分简单。如果没有EJB,启动、提交或回滚事务时就需要大量样板代码。

此外,不要低估EJB提供的池和存根(stubs)的好处。这意味着一个bean可以注入许多EJB,并且您不必担心每次创建此类bean时它们都会被实例化。否则,当不是每次都使用所有EJB时,这将特别麻烦。

由于存在池,因此只注入非常轻量级的存根,它们更类似于指向实际实例的URL。从内存或CPU开销的角度来看,这些存根的成本几乎为零。

EJB还具有注释,以声明它们是Singletons,安排它们的锁定行为(写锁/读锁),声明应该在启动时初始化一个实例,允许它们管理所谓的扩展持久性上下文(一个未限定到TX的持久性上下文)等。

这些都是您不希望出现在精简实体中的问题。在许多架构中,例如用户对象是一个简单的数据实体,我希望将其发送到各个层。我不想让我的User实例有一个sendMsg()方法,并且拥有一个JMS资源作为依赖项,以便可以从某个客户端突然发送消息。我真不确定为什么人们认为这样做在面向对象编程中很“自然”。

在现实世界中,当我想给我的朋友Joe寄明信片时,我也不会调用sendMsg操作。相反,我会写上地址并把它带到邮局或投递到邮箱里。

我也不会对蛋糕调用bake()操作。相反,我会把蛋糕放进烤箱里等它烤熟,等等。


1
@Geek 代理不必包含任何数据或很多逻辑。它可以是一个小包装器,对于每个调用的方法 X,只需说:“从池 A 获取 bean“xyz.foo.kaz”并调用方法 X”。实际上,您可以将其视为对“A://xyz.foo.kaz/X”执行http请求。代理可以非常轻巧,因为它甚至不需要包含对真实bean的引用,仅需要一个对池的“命令/请求”。 - Arjan Tijms
1
@ArjanTijms,我现在明白你的观点了。感谢你的跟进和支持。 - Geek
@TomAnderson,您所说的池现在“几乎没有意义,甚至可能有害”,是什么意思?我正在开始学习EJB,对池的缺点不太了解。 - Michel Feinstein
@mFeinstein:池化可以节省分配的成本,但会在 GC 期间引入维护和扫描的成本。在 Java 分配速度较慢时,像 EJB 这样的对象是性能上的胜利者。十多年来,它已经成为了一种损失。除非某个对象因某种原因非常昂贵而需要创建;最常见的原因是它使用类似 TCP 套接字之类的本机资源。在这里,我认为 EJB 不应该有这样的原因。 - Tom Anderson
@mFeinstein 数据库连接池确实是一件不同的事情,因为连接代表着在数据库上昂贵的资源,每次创建都很昂贵。对于持有没有特定资源的普通对象的实例池确实是有争议的。如果您在内存中有10,000个这样的对象,则GC需要通过检查所有引用来完成更多的工作。这种额外的GC压力加上从池中查找的成本可能比在需要时分配对象并在其后立即进行GC更大。在Java中,两者都变得非常快。 - Arjan Tijms
显示剩余7条评论

6
使用Java EE并不自动意味着贫血领域模型,就像您可以在Java中编写代码而不遵循最佳实践一样,这并不意味着不可能在Java中实现。我认为Martin Fowler的观点是J2EE(注意使用J2EE而不是Java EE)基本上强制执行逻辑和数据的操作。使用基于POJO的实体允许适当地对数据和行为进行建模。您的EJB中的“业务逻辑”通常编排业务逻辑的应用,但往往不会实际执行它,通常只是一个非常薄的包装器。
因此,EJB形成了您的服务API,无论您使用哪个平台/框架,都需要这个API作为入口点以便您可以物理调用。无论您是使用Spring、Web服务等方式进行实现,您都需要一个服务层,没有任何阻止在Java EE中实现这一点。下面是一个比较牵强的例子。
@Stateless
public SomeServiceImpl implements SomeService
    someServiceMethod() {
       delegate.doSomething();
    }
}

public SomeServiceDelegate implements SomeService
    someServiceMethod() {
       modelObject.doSomething();
    }
}

我不会详细解释为什么要选择EJB而不是其他技术,只想指出使用它们并不意味着您的实现不能使用最佳实践。

同意:“EJB通常在服务层作为服务类”。 - Raedwald

5
你已经提到了“实现业务逻辑”的用例。
在EJB 3.x中,Session Beans、Message Driven Beans以及3.1中的新Singleton Beans确实允许你实现业务逻辑。Session Beans通常作为Facade,客户端连接到它们。这些客户端可以是通过HTTP提供内容的Servlet,也可以是使用其他(更二进制)协议与EJBs通信的“fat”客户端。
Message Driven Beans作为异步通信的终点,并且可以调用Session Beans上的方法作为示例。
所有的EJB都有一个共同点,使它们非常有吸引力:它们由一个容器管理。因此,容器负责实例化、池化、事务、安全等方面的处理。
如果你在一个EJB中编写代码
@Resource DataSource x;

容器确保当您的bean准备好接收方法调用时,变量“x”包含合适的数据源。

Bean池化允许您拥有比没有池化更多的客户端连接到站点,因为实例可以共享(无状态SB)或者实例可以被容器交换到第二存储器中以释放内存并在后续重新激活它们。

在EJB 3中,EJB 1.x和2.x中的旧EntityBeans已经消失,由JPA取代。JPA构建了POJO的域数据模型,可以通过注释来提供关系语义,也可以通过外部XML文件提供语义。

使用JPA(完全不需要EJB),EJB通常用于实现这些实体的处理:

@Stateless
public class MyBean {
    @PersistenceContext EntityManager em;

    public Foo getFoo(String name) {
        Query q = em.createQuery("SELECT f FROM Foo f WHERE f.name = :name");
        q.setParameter("name",name);
        return q.getSingleValue();
    }
}

“Session Beans经常充当Facade”,你会说这是它的主要用途,作为你的领域对象的Facade吗? - Raedwald
虽然不是主要用途,但是非常受欢迎。特别是在领域对象方面,SB还包含了查询它们和处理ORM框架的逻辑。 - Heiko Rupp
3
"EJB(Enterprise Java Beans)在什么情况下使用?它们在网站/ Web 应用程序中是否必需?" 这篇文章强调了“不再需要自己启动、提交/回滚事务”的要求。 - Raedwald

5

几个要点:

  • EJB并不孤立存在;它们存在于EJB容器中,通过它们提供一些非常有用的服务,如声明式安全、声明式事务和相对容易的集群。
  • 虽然无血统模型是反模式:但一旦你的业务逻辑变得更加复杂,例如多个应用程序操作同一模型时,将大部分逻辑从模型中分离出来就成为了关注点分离的问题。

@Michael Borgwardt:第一点中提到的所有服务甚至都由Spring提供。 - Dead Programmer
3
@Suresh: 那又怎样?在Spring出现之前,EJB容器就已经提供了它们。 - Michael Borgwardt
2
@Raedwald:不,我的意思是强制将所有逻辑排除在域模型之外和将更专业或复杂的逻辑放入单独的类中以实现关注点分离之间存在差异。 - Michael Borgwardt
1
EJB 3没有EntityEJBs - EntityBeans是EJB 1.x和2.x的。 - Heiko Rupp
3
从同一篇文章中引用Raedwald的话:“如果业务规则逻辑涵盖了两个或更多实体对象,则应将其作为服务类的一部分。” - 无状态会话EJB正是这样一个服务类。请注意,该文章还将服务类视为域层的一部分。 - Michael Borgwardt
显示剩余3条评论

3

根据个人经验的一点评论...

我不怀疑EJB的好处,但是我曾经使用过它们,我认为EJB只适用于安全性和事务非常重要的情况(例如:金融应用)。对于90%的情况,您没有EJB也可以正常运作。另外...可扩展性和EJB并不是很友好。


1
你最后那个想法从哪里得来的?EJB非常适合扩展。 - Heiko Rupp
如果这是真的,我们会看到更多使用它们的高度使用的门户网站(Twitter、Facebook、Google等)。正如我所说,如果您的系统大量使用事务和安全性,那么EJB可能是一个很好的选择,否则像大多数情况一样,它们是过度杀伤力的。 - Manuel Salvadores
2
我不想进行长时间的讨论(可能是最后一条评论),但如果您不需要事务/安全性,那么它就不会使用,也不会使用额外的资源。但是,如果您只想托管一个微不足道的服务,那么这显然过于复杂了。您的观点是可扩展性,EJB是可扩展的,并且在我使用过的所有EJB容器中都很容易实现。 - vickirk
@vickirk,你对“琐碎”应用的概念过于狭隘了。有数百万个非常复杂的服务和应用程序,即使它们需要事务和/或安全性,也不一定需要EJBs。 - Manuel Salvadores
1
但是使用EJB,管理事务的痛苦大大减少,甚至变得微不足道。这极大地增加了简单和复杂应用程序的健壮性。在底层,事务本质上仍然很复杂,但是EJB使它们变得容易。就像FK的实现可能在内部非常复杂,但是您的数据库使将其添加到列中变得微不足道一样。 - Arjan Tijms
显示剩余2条评论

2
一些人在讨论中说EJB只有在EJB3之后才变得有用,这是不正确的。 确实,它随着JPA变得更加强大了,但是EJB1.0和EJB2.1仍然做了很多事情。 也许他们没有在大型应用程序中使用它,所以这样说。
例如,POJO无法处理事务,因此在EJB中,您可以为特定方法指定事务类型,是需要新事务还是不需要从事务中取消。
在我们的组织中,我们使用版本为1.0的EJB在业务逻辑中构建ERP。它是从2000年开始使用的。 它不仅将业务层与其他层分离,而且将系统相互分离, 例如: 财务模块与HR模块分开。 如果他们想要添加一个新模块,他们可以添加它而无需重新启动系统,并且它将与系统完美集成。
还要记住,在EJB中: 您在代码中看到的内容毫无意义,而EJB容器为您做的一切都很重要 :) .


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