集成层如何与业务层交互?
我需要一些关于用 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 的新手,我已经阅读了足够多的内容来了解总体思路,但我需要帮助将各个部分组合在一起。
I need some advice on designing an "Integration Tier" of an N-Tiered system in Java. This tier is responsible for persisting and retrieving data for the "Business Tier" (located on a separate server). I'm new to J2EE and I've read a few books and blogs. The alphabet soup of technology acronyms is confusing me so I have a handful of questions.
First, what I have so far: I'm using JPA (via Hibernate) for persisting and retrieving data to a database. I made my data access objects EJBs and plan on deploying to an application server (JBoss) which makes transactions easier (they're at the function level of my DAOs) and I don't have to worry about getting a handle to an EntityManager (dependency injection). Here's an example of what things look like:
@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){ ... }
}
My question: How should the Business Tier exchange data with the Integration Tier. I've read up on RESTful services, and they seem simple enough. My concern is performance when the frequency of gets and sets increases (HTTP communication doesn't seem particularly fast). Another option is RMI. My DAOs are already EJBs. Could I just have the Business Tier access them directly (via JNDI)? If so, what happens if the @OneToMany link in the example above are lazily loaded?
For example if the Business Tier does something like the following:
Context context = new InitialContext(propertiesForIntegrationTierLookup);
ADAOImpl aDao = (ADAOImpl) context.lookup("something");
A myA = aDao.getAById(0);
int numberOfBs = myA.setOfBs.size();
If the setOfBs list is loaded lazily, when the Business Tier (on a separate server) accesses the list, is the size correct? Does the list somehow get loaded correctly through the magic of EJBs? If not (which I expect), what's the solution?
Sorry for the long post. Like I said I'm new to J2EE and I've read enough to get the general idea, but I need help on fitting the pieces together.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您在惰性集合上调用 size() 时,它会被初始化,因此无论您使用哪个接口(远程或本地),您始终会获得正确的大小。
另一种情况是当您尝试使用 JPA 类作为数据传输对象 (DTO) 并通过远程接口请求它们时。我不记得这里有任何延迟初始化问题,因为在传输之前,所有对象都必须在服务器端序列化(初始化延迟集合)。结果,整个对象图通过网络传递,这可能会导致严重的 cpu 和网络开销。此外,为了能够进行反序列化,您必须与远程应用程序共享 JPA 类。这就是“EJB 魔法”结束的地方和方式:)
因此,一旦远程调用成为可能,我建议开始考虑将数据传输策略和非 JPA 数据传输对象作为附加数据层。就我而言,我为 XML 绑定 (JAXB) 注释了 DTO 类,并在 Web 服务中重用它们。
When you call size() on lazy collection, it gets initialized, so you'll always get correct size no matter which interface you're using - Remote or Local.
Another situation is when you're trying to use JPA classes as data transfer objects (DTO) and request them via Remote interface. I don't remember any lazy initialization issues here, cause prior to transmission all objects have to be serialized (with lazy collections initialized) on server side. As a result, the whole object graph is passed over network, which might cause serious cpu and network overheads. In addition, for deserialization to be possible, you will have to share JPA classes with remote app. And that's where and how 'EJB magic' ends :)
So, once remote calls are possible, I'd suggest to start thinking of data transfer strategy and non-JPA data transfer objects as additional data layer. In my case, I've annotated DTO classes for XML binding (JAXB) and reused them in web-services.
简短的回答:如果您使用“集成层”方法,那么您应该集成的东西应该是松散耦合的服务,遵循 SOA 原则。
这意味着您不应该允许远程调用实体上的方法,这些实体可能会在另一台服务器上调用框架。如果这样做,您实际上正在构建一个紧密耦合的分布式应用程序,并且您将不得不担心延迟加载问题和持久性上下文的范围。如果您愿意,您可能需要考虑扩展持久性上下文 http:// docs.jboss.org/ejb3/docs/tutorial/extended_pc/extended.html。
您谈到了“业务层”,但 JPA 不提供业务层。它提供实体并允许 CRUD 操作,但这些通常不是业务操作。 “RegisterUser”操作不仅仅是保存“User”实体的问题。您的 DAO 层可能提供更高级别的操作,但 DAO 通常用于在数据库上放置一个薄层,但它仍然非常以数据为中心。
更好的方法是定义业务服务类型操作并使这些服务成为您公开的服务。您可能需要在 DAO 之上添加另一层,或者您可能需要一个层(转换您的 DAO 层)。
您的业务层应该调用flush并处理任何JPA异常并向调用者隐藏所有这些异常。
如何传输数据的问题仍然存在。在许多情况下,您的业务服务请求的参数将与您的 JPA 实体类似,但我认为您会注意到,通常存在足够的差异,您需要定义新的 DTO。例如,“RegisterUser”业务操作可能会更新“User”和“EmailAddresses”表。用户表可能包含“createdDate”属性,该属性不是“RegisterUser”操作的一部分,但设置为当前日期。
要创建 DTO,您可能需要查看 Project Lombok。
要将 DTO 复制到实体,您可以使用 Apache Commons BeanUtils(例如,PropertyUtils.copyProperties)来完成大量的跑腿工作,如果属性名称相同,则该工作有效。
就我个人而言,我不认为在这种情况下 XML 有什么意义,除非您想完全解耦您的实现。
Short answer: If you are using an "Integration Layer" approach, the things you should be integrating should be loosely coupled services, following SOA principles.
This means you should not be allowing remote calls to methods on entities that could be making calls to the framework under the lid on another server. If you do this, you are really building a tightly coupled distributed application and you will have to worry about the lazy loading problems and the scope of the persistence context. If you want that, you might like to consider extended persistence contexts http://docs.jboss.org/ejb3/docs/tutorial/extended_pc/extended.html.
You have talked about a "business tier", but JPA does not provide a business tier. It provides entities and allows CRUD operations, but these are typically not business operations. a "RegisterUser" operation is not simply a question of persisting a "User" entity. Your DAO layer may offer a higher level of operation, but DAOs are typically used to put a thin layer over the database, but it is still very data centric.
A better approach is to define business service type operations and make those the services that you expose. You might want another layer on top of your DAO or you might want to have one layer (convert your DAO layer).
You business layer should call flush and handle any JPA exceptions and hide all of that from the caller.
The issue of how to transfer your data remains. In many cases the parameters of your business service requests will be similar to your JPA entities, but I think you will notice that often there are sufficient differences that you want to define new DTOs. For example, a "RegisterUser" business operation might update both the "User" and "EmailAddresses" table. The User table might include a "createdDate" property which is not part of the "RegisterUser" operation, but is set to the current date.
For creating DTOs, you might like to look at Project Lombok.
To copy the DTO to the Entity, you can use Apache Commons BeanUtils (e.g., PropertyUtils.copyProperties) to do a lot of the leg work, which works if the property names are the same.
Personally, I don't see the point in XML in this case, unless you want to totally decouple your implementations.