让我们共享基于 Java 的 Web 应用程序架构!
Web 应用程序有很多不同的体系结构,这些体系结构都是用 Java 实现的。这个问题的答案可以作为各种 Web 应用程序设计及其优缺点的库。虽然我知道答案是主观的,但是让我们尽可能的客观,并且激发我们列出的优点和缺点。
使用您喜欢的详细级别来描述您的体系结构。为了让您的答案有价值,您至少必须描述您所描述的体系结构中使用的主要技术和思想。最后但并非最不重要的,什么时候我们应该使用你的架构吗?
我从..。
我们使用一个基于开放标准的三层架构,这些标准来自于 Sun,比如 JavaEE、 Java持久化API、 Servlet 和 Java 服务器页面。
各层之间可能的通信流程表现为:
Persistence <-> Business <-> Presentation
例如,这意味着表示层从不调用或执行持久化操作,它总是通过业务层执行。这个架构是为了满足一个高可用性的 web 应用程序的需求。
执行创建、读取、更新和删除(讨厌)持久化操作。在我们的示例中,我们使用(Java持久化API) JPA,目前使用 冬眠作为持久性提供程序,并使用 它的 EntityManager。
这一层被划分为多个类,其中每个类处理特定类型的实体(即与购物车相关的实体可能由一个持久性类处理) ,并且 用过由一个且仅由一个 经理处理。
此外,这一层也存储 JPA 实体的事情,如 Account
,ShoppingCart
等。
所有与 Web 应用程序功能相关的逻辑都位于这一层。这个功能可以为想要使用信用卡在线支付产品的客户启动资金转账。它也可以创建一个新用户,删除一个用户,或者在一个基于网络的游戏中计算一场战斗的结果。
该层被划分为多个类,每个类都用 @Stateless
进行注释,从而成为一个 无状态会话 Bean(SLSB)。每个 SLSB 称为 经理,例如,一个管理器可以是一个被注释为 AccountManager
的类。
当 AccountManager
需要执行 CRUD 操作时,它对 AccountManagerPersistence
的实例进行适当的调用,AccountManagerPersistence
是持久层中的一个类。对 AccountManager
中的两种方法的粗略描述可以是:
...
public void makeExpiredAccountsInactive() {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
// Calls persistence layer
List<Account> expiredAccounts = amp.getAllExpiredAccounts();
for(Account account : expiredAccounts) {
this.makeAccountInactive(account)
}
}
public void makeAccountInactive(Account account) {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
account.deactivate();
amp.storeUpdatedAccount(account); // Calls persistence layer
}
我们使用 集装箱经理交易,所以我们不必做事务划分我们自己的。基本上,我们在进入 SLSB 方法时发起一个事务,并在退出方法之前立即提交(或回滚)它。这是一个约定优于配置的例子,但是我们只需要默认值,还需要。
以下是 Sun 的 JavaEE 5教程如何解释 EJB (EJB)的 必需的事务属性:
如果客户端在 事务并调用企业 Bean 的方法,则执行该方法 在客户的交易。如果 客户端与 事务时,容器启动一个 在运行 方法。
“必需”属性是隐式的 所有的事务属性 运行的企业 bean 方法 容器管理的事务 你通常不设置 必需属性,除非您需要 重写另一个交易 属性。因为交易 属性是声明性的,您可以 很容易改变他们以后。
我们的展示层负责... 展示!它负责用户界面,并通过构建 HTML 页面和通过 GET 和 POST 请求接收用户输入向用户显示信息。我们目前正在使用旧的 Servlet + Java 服务器页面(JSP)组合。
该层调用业务层的 经理中的方法来执行用户请求的操作,并接收要在网页中显示的信息。有时,从业务层接收到的信息是不太复杂的类型,如 String
和 int
egers,有时是 JPA 实体。
@NamedQuery
注释,可以将经常使用的查询存储为命名查询。如果您在持久性类中有尽可能多的与持久性相关的内容,就像在我们的体系结构中一样,那么这将扩展您可能发现包含 JPA 实体的查询的位置。概述持久性操作将更加困难,因此维护也更加困难。Account
和 ShoppingCart
,它们不是真正的业务对象吗?这样做是因为您必须触摸这些类,并将它们转换为 JPA 知道如何处理的实体。fetch=FetchType.LAZY
)从表示层内部从数据库加载。它会触发一个异常。在返回包含这些类型字段的实体之前,我们必须确保调用相关的 getter。另一种选择是使用 Java 持久化查询语言(JPQL)并执行 FETCH JOIN
。然而,这两个选项都有点麻烦。