探索 Java EE 的体系结构

现在有很多创建软件的方法。实际上,甚至有很多方法可以创建优秀的软件。在应用程序服务器开发方面,其中之一经受了时间的考验,并且有充分的理由:Java Enterprise Edition。

Java EE不仅仅是软件库,它也是一种体系结构和哲学。JEE不适合胆小的人;如果您要构建一个废弃的原型,那您走错了路。但是,如果您开始阅读可以承载大型企业并支持大规模应用程序的体系结构,那么您就是对的。JEE是软件开发的重炮。而且真是太棒了。

在本文中,我们将探讨JEE的体系结构方面。有关实现的文章将很快发布。

边注一下。当我在本文中讨论Java企业时,我并不是专门讨论库,而是讨论体系结构和哲学。官方的Java EE库只是一种方法。

JEE堆栈

那么您准备好进行一些严肃的软件开发了吗?抛开所有的非类型化语言、花哨的脚本、炒作式的开发和时髦的技术,让我们认真起来,编写可以运行20多年的软件。以下是Java EE架构的概要:

Java EE Stack

好的,理所当然,您需要有一个大范围的总括。让我们从一些初步的观察开始:

  • 与外界的每一次交流都严格基于请求-响应
  • 传入的请求在到达您的应用程序代码之前会经过几层。每一层都可以拒绝重定向更改请求。这些层次背后的动机是关注点分离
  • 许多层已经实现,您只需要使用它们即可。
  • JEE旨在使开发人员仅专注于业务功能。99%的其他一切都已为您解决。

应用容器

当请求通过网络到达我们的服务器计算机时,它首先被传递到操作系统。操作系统将根据已将请求发送到的端口来确定将请求转发到哪个应用程序。在这种情况下,应用程序是Java虚拟机。JVM在内部运行应用程序容器(例如Apache TomcatGlassfish)。应用程序容器实现Java Servlet API。应用程序容器具有以下职责:

  • 它管理一个或多个作为servlet交付的应用程序。实际上,大多数容器仅包含一个servlet,但是从理论上讲,一个Tomcat可以任意包含许多servlet。
  • 它提供了Servlet API的实现。这允许所包含的应用程序与容器对话。此功能最主要的用途是建立过滤器链(稍后会详细介绍)。
  • 它提供与操作系统的Services API的集成。这样,容器中运行的应用程序可以作为OS级服务启动、终止和重新启动。因此,即使Java是多平台的,许多应用程序容器仍包含特定于平台的代码(因此所包含的应用程序仍与平台无关)。
  • 它根据路径映射将传入的请求重定向到正确的应用程序。看到一个注册的servlet用于静态内容(绑定到/ static)和一个注册的servlet用于应用程序服务器的动态API(绑定到/ api)并不少见。
  • 它管理请求的线程池,并将每个请求绑定到一个线程。由于线程拥有请求上下文,因此不建议在JEE环境中手动启动新线程(除非您确切地知道自己在做什么)。

传统上,Java EE应用程序是通过称为WAR文件(用于Web归档)或EAR文件(用于企业归档)的归档文件部署的。这些档案的内部文件结构是标准化的。应用程序容器在启动时提取所包含的文件并启动所包含的servlet。这样做时,容器将servlet绑定到指定的端口(在代码或配置文件中指定)。

JEE框架

通常在使用JEE架构时,您不会从头开始实现所有东西。从一个JEE应用程序到下一个JEE应用程序,许多任务是完全相同的,因此使用合适的框架非常有意义。主要有实际的JEE参考实现和Spring框架。关于“vanilla”JEE我不能说太多,因为到目前为止我只使用了Spring框架。我们将在下一篇文章中更详细地讨论它。

过滤链

每个传入的请求在传递到您的应用程序之前,都必须通过一系列所谓的Servlet过滤器,它们形成一个过滤器链。请求通过第一个过滤器后,第二个过滤器将启动,依此类推。每个过滤器都有阻止请求的选项。应用程序容器允许通过Servlet API定制过滤器链。JEE框架实现将过滤器链用于许多任务,包括会话管理和安全性。过滤器也可能有副作用;如果每个请求都有您要执行的任务,那么您通常会以servlet过滤器的形式查看实现。另外,如果您需要将某些信息绑定到请求本身,则servlet过滤器是这样做的常见位置。

表示层

表示层是您的实际应用程序代码首次满足传入请求的地方。该请求已通过Servlet过滤器链,因此已建立用户会话并准备就绪,并且所有身份验证都已得到处理。在JEE的早期,表示层是发生服务器端HTML页面的地方。如今,表示层由一组REST控制器组成,这些控制器提供了构成REST API的各种端点。如果您面对的是较旧的应用程序,则在表示层中还将遇到XML Web服务。在表示层中要做的一件事是用户输入的服务器端验证和常规请求验证。与永远不要在GUI代码中编写SQL查询(表示层)的方式相同一定不要尝试直接访问数据库。表示层中的类仅允许与另一个表示层类,服务层类或由服务层返回的数据模型的元素通信。

服务层

服务层是您实际的应用程序代码所在的位置。这是将业务规则纳入代码的地方。服务层是您在数据模型中移动数据,创建新元素,删除旧元素等的地方。根据您的用例,服务层可能小到“将此调用转发到存储库层”,或者极其复杂的过程。服务层中的类只能与其他服务或存储库层中的类通信。

存储库层

这是代码中的最后一层,它在数据到达数据库之前修改数据。这一层的主要元素是存储库(也称为数据访问对象,或DAO*s)。这些类只是提供了一些方法,允许您*持久化、加载、删除和查询数据库中的数据。这里重要的是,绝不能让数据存储的任何细节脱离存储库层——它的目的就是确保您可以用不同的存储库交换数据存储库(甚至可能是带有NoSQL存储库的SQL数据库!)在内部,存储库方法将包含实际的查询语句。如果您使用的是一个标准的JEE堆栈,那么您将拥有一个Java Persistence API (JPA)提供者,比如Hibernate。JPA允许您相对轻松地将域模型转换为SQL表并返回。它仍然有很多陷阱,值得自己写一篇文章。您可能已经猜到了,除了JPA类之外,存储库层类不会调用它们自己的层之外的任何其他类。

数据模型

数据模型表示您域中的数据。它是应用程序的所有三层都将使用的唯一体系结构元素。因此,至关重要的是,领域模型类有任何其他类的引用,除了类驻留的域模型本身内。与表示层、服务层和持久层类相反,域模型是有状态的。通常,您不会想要在域模型中具有很多逻辑;它主要用于保存您的数据并提供干净的API,实际的复杂修改是在业务层进行的。域模型虽然在JEE中没有明确要求,但几乎总是遵循Java Bean模式。如果您想使用标准框架来轻松处理您的域模型,例如Bean验证和JPA(后面会详细介绍),那么适当的getter和setter不能在这里进行协商。域模型元素是典型的POJO-私有字段、构造函数以及getter和setter。通常,诸如JPA,Jackson和JAXB之类的框架还会迫使您为每个类提供默认的构造函数,因为这些类需要通过Java反射实例化。与JEE架构中的几乎所有其他类相比,它具有干净的实现equals()并且hashCode()关键的领域模型的POJO。通常,每个域模型元素为此都有一个唯一的ID,该ID也与数据库表中的ID一致。

JEE中的线程

JEE线程管理

请求总是绑定到一个线程在JEE这是由应用程序容器实例化和管理(通常在线程池)。这意味着JEE服务器应用程序总是固有地并发,您无法避免这种情况。众所周知,适当地处理并发是困难的。幸运的是,关于并发性,您已经涵盖了JEE体系结构。如果您查看上面的图片,您会看到四个用户在并行处理该应用程序,每个用户由绑定到线程的请求/响应表示。有一个特别的细节值得注意:线程永不相交。该应用程序不执行任何同步,而是将其留给真正擅长于此的组件:数据库。

这怎么可能?我们如何在不考虑多线程的情况下将所有这些层置于数据库之上?当并发成为问题时,请回想一下:当多个线程访问同一数据时。您想不惜一切代价避免在JEE应用程序中发生这种情况(存在例外,例如应用程序级缓存)。为此,属于存储库层服务层的所有类在JEE中都是无状态的。它们没有保持可变状态的私有或公共字段。那么数据呢?数据是按用户请求加载的。当请求到达服务层(表示层在这里有点例外)时,将打开一个新的数据库事务供该用户专用。然后,服务将收集请求的数据和/或执行请求的修改,全部都在此单个事务内。在将结果传递到表示层之前,将提交并关闭事务。

该体系结构具有两个主要优点:

  • 服务器是无状态的,这是一个很好的属性,例如用于测试。它有助于保持业务逻辑非常简单,并且可以使用功能更强的编程风格很好地工作。
  • 并发修改曾经遇到的唯一地方是在数据库中,但是它们是专门为处理该问题而设计的。

当然,代价是每个线程构建自己的(部分的)数据模型视图。因此,如果两个用户请求相同的数据块,它将被保存在内存中两次。

结束语

关于JEE还有很多要说的。我经常觉得它受到了很多不该受到的批评,仅仅是因为它被误解了。它与现代编程风格和语言配合得非常好,有助于构建非常稳定的应用程序。在某种程度上,JEE并不是关于它为作为程序员的您提供了什么,而是关于它如何保护您(并发性问题、数据完整性问题……)。在这方面,JEE架构是防御性编程的一个典型例子——它完全是关于安全第一的。这个架构有一个被证明非常适合大型项目和团队的跟踪记录。

原文链接:https://dev.to//martinhaeusler/java-enterprise-101-3djl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值