描述您用于Java Web应用程序的架构?

148

让我们分享基于Java的Web应用程序架构!

有很多不同的架构可以用Java实现Web应用程序。这个问题的答案可以作为各种Web应用程序设计的库,包括它们的优缺点。虽然我意识到答案会是主观的,但让我们尽可能客观,并激励我们列出的优缺点。

您可以使用您喜欢的详细级别来描述您的架构。为了使您的答案具有任何价值,您至少需要描述所描述的架构中使用的主要技术和思想。最后但并非最不重要的,何时应该使用您的架构?

我来开始...


架构概述

我们采用基于Sun的开放标准,如Java EE、Java Persistence API、Servlet和Java Server Pages的3层架构。

  • 持久化层
  • 业务层
  • 表示层

层之间可能的通信流程如下所示:

Persistence <-> Business <-> Presentation

例如,这意味着演示层从不调用或执行持久性操作,它始终通过业务层进行操作。这种架构旨在满足高可用性Web应用程序的需求。

持久性

执行创建、读取、更新和删除(CRUD)持久性操作。在我们的情况下,我们使用(Java Persistence API)JPA,目前我们使用Hibernate作为持久性提供程序并使用其EntityManager

此层分为多个类,每个类处理某种类型的实体(即与购物车相关的实体可能由单个持久性类处理),并且仅由一个管理器使用

此外,此层还存储JPA实体,这些实体是诸如AccountShoppingCart等的东西。

业务

所有与Web应用程序功能相关联的逻辑都位于此层中。该功能可以是为希望使用信用卡在线支付产品的客户启动资金转移。也可以是创建新用户、删除用户或计算基于Web的游戏中的战斗结果。

这个层被分成多个类,并且每个类都用@Stateless进行注释,以成为一个无状态会话Bean(SLSB)。每个SLSB被称为一个管理器,例如,一个管理器可以是一个已经注释为AccountManager的类。
AccountManager需要执行CRUD操作时,它会对一个持久化层中的类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方法时启动事务,并在退出方法之前立即提交它(或回滚它)。这是约定优于配置的例子,但我们还没有需要除默认值Required之外的任何内容。

以下是Sun的Java EE 5教程如何解释企业级JavaBean(EJB)的Required事务属性

如果客户端正在运行事务并调用企业bean的方法,则该方法在客户端的事务中执行。如果客户端未与事务相关联,则容器在运行方法之前启动新事务。

对于所有使用容器管理的事务划分运行的企业bean方法,Required属性是隐式的事务属性。通常情况下,您不需要设置Required属性,除非您需要覆盖另一个事务属性。因为事务属性是声明性的,所以您可以很容易地稍后更改它们。

演示

我们的展示层负责展示内容!它负责用户界面,并通过构建HTML页面和通过GET和POST请求接收用户输入向用户显示信息。我们目前正在使用旧的Servlet和Java Server Pages (JSP)组合。
该层调用业务层中的管理器方法来执行用户请求的操作并接收要在Web页面中显示的信息。有时,从业务层接收到的信息是较简单的类型,如Stringint,而其他时候则是JPA entities

架构的优缺点

优点

  • 将与持久化方式相关的所有内容都放在此层中,意味着我们可以轻松地从使用JPA切换到其他方式,而无需在业务层中重新编写任何内容。
  • 我们可以轻松地将演示层切换到其他方式,并且如果我们找到更好的东西,很可能会这样做。
  • 让EJB容器管理事务边界很不错。
  • 使用Servlet + JPA很容易(起步)并且这些技术在许多服务器上得到广泛使用和实现。
  • 使用Java EE应该使我们更容易创建具有负载平衡故障转移的高可用性系统。我们认为这两个方面都是必须的。

缺点

  • 使用JPA,您可以使用@NamedQuery注解在JPA实体类上将经常使用的查询存储为命名查询。如果您将尽可能多的与持久性相关的内容放置于持久性类中(就像我们的架构一样),这将扩展您可以找到包括JPA实体的查询的位置。这将使持久化操作更难以概述,从而更难以维护。
  • 我们的持久层中有JPA实体。但是AccountShoppingCart,它们不是真正的业务对象吗?之所以这样做,是因为您必须触及这些类并将它们转换为JPA知道如何处理的实体。
  • JPA实体,也是我们的业务对象,像数据传输对象(DTO)一样创建,也称为值对象(VO)。这导致了贫血领域模型,因为业务对象除访问器方法外没有自己的逻辑。所有逻辑都由我们的业务层管理器执行,这导致了更多的过程式编程风格。这不是良好的面向对象设计,但也许这不是问题?(毕竟面向对象不是唯一已经取得了成果的编程范例。)
  • 使用EJB和Java EE会引入一些复杂性。我们不能纯粹地使用Tomcat(添加EJB微容器并不算是纯粹的Tomcat)。
  • 使用Servlet + JPA存在许多问题。使用Google以获得有关这些问题的更多信息。
  • 由于事务在退出业务层时关闭,因此我们不能从呈现层中加载配置为从数据库在需要时加载的JPA实体中的任何信息(使用fetch=FetchType.LAZY)。它会触发异常。在返回包含这些类型字段的实体之前,我们必须确保调用相关的getter。另一个选项是使用Java Persistence查询语言(JPQL)并执行FETCH JOIN。但这两个选项都有点繁琐。

1
你的回答似乎设定了太高的标准,可能会让其他人望而却步 :) - Jonik
5
另外,也许你的看法应该是一个正常的回答,而不是问题的一部分,这样它就可以和其他答案一起被投票了? - Jonik
这个问题已经在 Meta 上被引用了。 - D4V1D
10个回答

21

好的,我会做一个(较短的):

  • 前端: Tapestry (3 用于旧项目,5 用于新项目)
  • 业务层:Spring
  • DAO:Ibatis
  • 数据库:Oracle

我们使用Spring事务支持,并在进入服务层时启动事务,向下传播到DAO调用。服务层具有最多的业务模型知识,而DAO相对简单地执行CRUD操作。

一些更复杂的查询处理由后端中更复杂的查询语句来处理,以提高性能。

在我们的情况下,使用Spring的优点是我们可以拥有特定于国家/语言的实例,这些实例位于Spring代理类后面。根据会话中的用户,在进行调用时使用正确的国家/语言实现。

事务管理几乎是透明的,运行时异常时回滚。我们尽可能使用未检查的异常。我们曾经使用过已检查的异常,但是随着Spring的引入,我看到了未检查的异常的好处,只在必要时处理异常。这避免了大量的“catch/rethrow”或“throws”样板代码。

抱歉它比您的帖子短,希望您会觉得这很有趣...


很好的答案!这个帖子似乎吸引了一些流量,可惜其他人不觉得他们有时间描述自己的架构,或者有其他参与原因。 - user14070

19

现在的理想Java Web开发技术。

Web层:

HTML+CSS+Ajax+JQuery

RESTful Web控制器/操作/请求处理层:

Play框架

业务逻辑/服务层:

尽可能使用纯Java代码。在这里可以进行Web服务融合。

XML/JSON数据转换层:

XMLTool(在Google Code上搜索),JSoup,Google GSon,XStream,JOOX(在Google Code上搜索)

持久层:

CRUD:JPA或SienaProject或QueryDSL / 复杂查询:JOOQ,QueryDSL


9

以下是我的意见

介绍

Android, Angular.JS WebClient, OAUTHv2

应用程序接口(API)

REST, Jersey (JAX-RS), Jackson (JSON序列化和反序列化), DTO对象(与业务逻辑模型不同)

业务逻辑

使用Spring进行依赖注入和事件处理。采用DDD-ish方法来处理模型对象。长时间运行的作业通过SQS在工作模块中卸载。

数据访问对象(DAO)

采用Spring JDBC模板的存储库模型来存储实体。Redis(JEDIS)用于排行榜,使用有序列表。Memcache用于令牌存储。

数据库

MySQL、Memcached、Redis


这与我们在项目中遵循的类似!此外,还有JBPM用于业务工作流。我想为什么没有Spring? - ininprsr
我应该对我们当前的架构进行更新:目前我们使用Spring DI和JDBC模板来进行数据访问层。 - Pepster

6
我们在项目中使用的技术如下:
前端技术:
- AngularJS - HTML5 - css3 - Javascript - Bootstrap 3
API:
1. REST 2. JERSEY (JAX-RS) 3. REST ASSURED 4. SPRING BOOT 5. Jackson 6. spring security
业务逻辑:
- SPRING DATA - SPRING data MongoDB
数据库:
- MongoDB
服务器(用于缓存):
- redis

4
我们仍在使用传统的Struts-Spring-Hibernate堆栈。对于未来的应用程序,我们正在研究Spring Web Flow + Spring MVC + Hibernate或Spring + Hibernate + Web Services与Flex前端。我们架构的一个显著特点是模块化。我们有许多模块,一些模块在数据库中具有3到30个表。大多数模块包括业务和Web项目。业务项目包含业务和持久性逻辑,而Web则包含表现逻辑。在逻辑层面上,有三个层次:业务、持久性和表现。依赖关系:表现依赖于业务和持久性。持久性依赖于业务。业务不依赖于其他层。大多数业务项目有三种类型的接口(注意:不是GUI,而是程序化的Java接口层)。
1. 表现层使用的接口 2. 其他模块在作为模块客户端时使用的接口。 3. 可用于模块管理目的的接口。

通常,1扩展2。

这样,很容易用另一个模块的实现替换一个模块的实现。这有助于我们适应不同的客户并更轻松地集成更多功能。有些客户只会购买特定的模块,我们需要集成他们已经拥有的功能。由于接口和实现层是分开的,因此可以轻松地为特定客户推出特定的模块实现,而不会影响到依赖模块。Spring框架使注入不同的实现变得容易。

我们的业务层基于POJOs。我观察到的一个趋势是这些POJOs类似于DTOs。我们遭受贫血领域模型。我不太确定为什么会发生这种情况,但这可能是由于许多模块领域问题的简单性,大部分工作是CRUD,或者是由于开发人员更喜欢将逻辑放在其他地方。


3

这是我曾经参与开发的另一种Web架构:

一个主要需求是应用程序应支持手机/其他设备。该应用程序还应具有可扩展性或灵活性,以适应技术选择的变化。

表示层:

  • JSP / JQuery(客户端MVC)
  • 本机Android
  • 本机iPhone
  • 移动Web(HTML5 / CSS3 / 响应式设计)

  • Spring REST控制器(可以更改为JAX-RS)

业务服务层:

Spring @Service(可以更改为无状态EJB)

数据访问层:

Spring @Repository(可以更改为无状态EJB)

资源层:

Hibernate(JPA)实体(可以更改为任何ORM)

您可以在此处找到遵循此架构的书籍的更多信息。


2
在我看来,我们大多数人都有一个共同点。至少在后端,我们有某种形式的IOC / DI容器和持久性框架。个人使用Guice和Mybatis。区别在于我们如何实现视图/ UI /表示层。这里有两个主要选项(可能更多)...基于操作的(将URL映射到控制器)和基于组件的。目前我正在使用基于组件的表示层(使用Wicket)。它完美地模仿了桌面环境,我使用组件和事件而不是URL和控制器。我目前正在寻找迁移到这种URL-controller类型的架构的原因(这就是我来到这个页面的原因)。为什么RESTful和无状态架构备受瞩目。
简而言之,我使用基于组件的框架在Guice IOC容器之上编写有状态的Web应用程序,并使用Mybatis将数据放入关系数据库中。

1
略有不同,我认为这里使用了更模块化的Java架构。我们有以下内容:
  1. Spring WS/Rest/JSP前端
  2. Spring MVC用于业务服务逻辑,包含表示层逻辑和Spring事务
  3. 组件服务通信接口,通过EJB由业务服务查找。EJB设置自己的事务边界,能够加入Spring事务。
  4. 组件服务实现,同样是Spring组件
  5. 集成层,MyBatis用于数据库集成,Spring WS用于Web服务集成,其他技术用于其他服务的集成
  6. 主机,数据库,其他服务器上的其他服务......

除了以上内容之外,我们还有共享库模块,它是所有服务的常见功能提供者。

使用不同的层允许我们完全解耦并提供所需的模块化。我们也能够充分利用Java EE以及Spring的强大功能。如果需要,我们也可以使用JSF作为前端。

与OP的示例架构相比,我认为这可以描述为有四个主要层而不是三个,尽管有一些变化。


0

我曾经参与过使用那种严格的管理模式的项目。历史上,我是一个坚定的支持者,认为一切都应该整齐地放在一个盒子里的严格等级制度。随着我的职业发展,我发现在很多情况下这种方式是被强迫的。我相信采用更敏捷的思维方式来进行应用设计会带来更好的产品。我的意思是创建一组解决手头问题的类,而不是说“你为这个和那个建立了一个管理器吗?”

我目前正在开发一个使用Spring MVC和RestEasy JSON/Ajax调用的Web应用程序。在服务器端,我们的控制器中嵌入了一个合理的基于外观模式的数据层,使用JPA/Hibernate直接访问数据库,一些EJB访问以及一些基于SOAP的Web服务调用。将所有这些组合起来的是一些自定义的Java控制器代码,确定要序列化为JSON并返回给客户端。

我们几乎没有花时间去尝试创建某种统一的模式,而是选择采用“较差即更好”的Unix设计哲学。这意味着最好在规定之外进行创造,并快速构建出一些有意义的东西,而不是遵循一堆严格的设计要求来构建。


0
Web应用程序架构中的组件包括:

1 : 浏览器 : 客户端交互

        HTML
        JavaScript
        Stylesheet

2: 互联网

3: Web服务器

        CSS
        Image
        Pages(Java render )

4 : 应用服务器

        App Webapp (Java interaction)
        Others WebApps

5 : 数据库服务器

        Oracle, SQL, MySQL

6 : 数据


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