【问题标题】:How does the Integration Tier interface with the Business Tier?集成层如何与业务层交互?
【发布时间】:2011-08-25 09:31:03
【问题描述】:

我需要一些关于用 Java 设计 N 层系统的“集成层”的建议。该层负责为“业务层”(位于单独的服务器上)保存和检索数据。我是 J2EE 的新手,我已经阅读了一些书籍和博客。技术首字母缩写词的字母汤让我感到困惑,所以我有几个问题。

首先,我目前所拥有的:我正在使用 JPA(通过 Hibernate)将数据持久化并检索到数据库中。我制作了我的数据访问对象 EJB,并计划部署到应用程序服务器 (JBoss),这使得事务更容易(它们处于我的 DAO 的功能级别),我不必担心获取 EntityManager 的句柄(依赖注入)。下面是一个例子:

@Entity
class A{
  @Id
  Long id;
  @OneToMany
  List<B> setOfBs = new ArrayList<B>;
}

@Entity
class B{
  @Id
  Long id;
}

@Remote
public interface ADAO{
  public A getAById(Long id);
}

@Stateless
class ADAOImpl implements ADAO{
  @PersistenceContext
  EntityManager em;

  public A getAById(Long id){ ... }
}

我的问题:业务层应如何与集成层交换数据。我已经阅读了 RESTful 服务,它们看起来很简单。我担心的是获取和设置频率增加时的性能(HTTP 通信似乎不是特别快)。另一种选择是 RMI。我的 DAO 已经是 EJB。我可以让业务层直接访问它们(通过 JNDI)吗?如果是这样,如果上面示例中的 @OneToMany 链接被延迟加载会发生什么?

例如,如果业务层执行以下操作:

Context context = new InitialContext(propertiesForIntegrationTierLookup);
ADAOImpl aDao = (ADAOImpl) context.lookup("something");
A myA = aDao.getAById(0);
int numberOfBs = myA.setOfBs.size();

如果延迟加载 setOfBs 列表,当业务层(在单独的服务器上)访问该列表时,大小是否正确?列表是否通过 EJB 的魔力以某种方式正确加载?如果不是(我期望的),解决方案是什么?

抱歉,帖子太长了。就像我说的那样,我是 J2EE 的新手,我已经阅读了足够多的内容来了解​​总体思路,但是我需要帮助来将这些部分组合在一起。

【问题讨论】:

    标签: java rest jakarta-ee ejb n-tier-architecture


    【解决方案1】:

    简短回答:如果您使用“集成层”方法,那么您应该集成的东西应该是松散耦合的服务,遵循 SOA 原则。

    这意味着您不应该允许远程调用实体上的方法,这些实体可能正在调用另一台服务器上的框架。如果你这样做,你实际上是在构建一个紧密耦合的分布式应用程序,你将不得不担心延迟加载问题和持久化上下文的范围。如果您愿意,您可以考虑扩展持久性上下文http://docs.jboss.org/ejb3/docs/tutorial/extended_pc/extended.html

    您谈到了“业务层”,但 JPA 不提供业务层。它提供实体并允许 CRUD 操作,但这些通常不是业务操作。 “RegisterUser”操作不仅仅是持久化“用户”实体的问题。您的 DAO 层可能提供更高级别的操作,但 DAO 通常用于在数据库上放置一个薄层,但它仍然非常以数据为中心。

    更好的方法是定义业务服务类型操作并使这些操作成为您公开的服务。您可能想要在 DAO 之上再添加一层,或者您可能想要一层(转换您的 DAO 层)。

    您的业务层应该调用 flush 并处理任何 JPA 异常,并对调用者隐藏所有这些。

    如何传输数据的问题仍然存在。在许多情况下,您的业务服务请求的参数将与您的 JPA 实体相似,但我想您会注意到,通常有足够的差异来定义新的 DTO。例如,“RegisterUser”业务操作可能会同时更新“User”和“EmailAddresses”表。 User 表可能包含“createdDate”属性,该属性不属于“RegisterUser”操作,但设置为当前日期。

    对于创建 DTO,您可能希望查看 Project Lombok。

    要将 DTO 复制到实体,您可以使用 Apache Commons BeanUtils(例如,PropertyUtils.copyProperties)来完成大量工作,如果属性名称相同,则可以使用。

    就我个人而言,在这种情况下,我没有看到 XML 的意义,除非你想完全解耦你的实现。

    【讨论】:

      【解决方案2】:

      当您在惰性收集上调用 size() 时,它会被初始化,因此无论您使用哪个接口 - 远程或本地,您都将始终获得正确的大小。

      另一种情况是当您尝试将 JPA 类用作数据传输对象 (DTO) 并通过远程接口请求它们时。我不记得这里有任何延迟初始化问题,因为在传输之前,所有对象都必须在服务器端进行序列化(初始化延迟集合)。结果,整个对象图通过网络传递,这可能会导致严重的 CPU 和网络开销。此外,为了使反序列化成为可能,您必须与远程应用程序共享 JPA 类。这就是“EJB 魔法”结束的地方和方式:)

      所以,一旦远程调用成为可能,我建议开始考虑将数据传输策略和非 JPA 数据传输对象作为附加数据层。在我的例子中,我为 XML 绑定 (JAXB) 注释了 DTO 类,并在 Web 服务中重用它们。

      【讨论】:

      • 我听取了您的意见,并在最近几天研究了 EE 设计模式。看起来我有两个选项可以在集成层和业务层之间传输数据:DTO 或 REST。使用 DTO 似乎会在集成层引入大量额外代码(从 Doman 类 A 转换为 DTO B 等),但 DTO 可以在业务层中重用。 REST 对于集成层来说很容易,但业务层必须做繁重的解析工作,性能可能是个问题。这两种解决方案似乎都不完美。还有第三种选择吗?
      • 哎呀,我不是说 REST。这两个选项可以是 DTO,也可以是一些基于文本的方法,例如 XML。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      • 2011-12-06
      • 2018-06-28
      • 2013-11-10
      • 2010-11-09
      • 2012-05-11
      • 2018-04-17
      相关资源
      最近更新 更多