Spring Boot与Jakarta EE API实现对比
作者 |MicroStone
来源 | 今日头条
在本文中,我们来探讨一下 Spring Boot 应用程序框架是否仍是最先进的java框架
在下文中,我想仔细探讨一下Spring Boot在基于 Java 应用程序开发中相关问题。我将对它的架构概念进行批判性讨论,并将其与Jakarta EE(原JavaEE)框架进行比较。我知道这个问题非常具有挑衅性,会引起很多同行的不理解。在比较这两个框架中,更关注于运行时环境的问题。
Spring Boot 和 Jakarta EE 都是用于开发微服务精心设计的概念。当我们谈论 Jakarta EE 和微服务时,总是谈论Eclipse Microprofile,它是当今 Jakarta EE 的标准扩展。Spring Boot 和 Jakarta EE 的概念非常相似。是因为 Jakarta EE 很多技术都受到了 Spring 和 Spring Boot 的启发。“约定优于配置”、CDI或注解的密集使用等概念最早是由 Spring 提出来的。这证明了 Spring 和 Spring Boot 的创新能力。
API 与实现
如果您在Jakarta EE上实现微服务,那么您是针对 API 而不是具体的实现来实现的。当您查看 Maven 项目的 pom.xml 时,这一方面变得显而易见。
....
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>${microprofile.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
.....
</dependencies>
.....
关键依赖项标记为“ provided”。这意味着您希望实现是您的运行时的一部分,而不是与您的组件捆绑在一起。因此,您的组件比Spring Boot组件小得多。要运行您的应用程序,您需要将其部署到Jakarta EE运行时环境中。
另一方面,Spring Boot构建了一个包含所有必要库的可引导组件,并为您提供了可引导服务器。不需要额外的运行时或应用程序服务器。这使得Spring Boot对开发人员如此有吸引力,并且是Spring Boot成功的最重要概念。但是这个概念是在 7 年多以前引入的。
那个时候安装应用服务器很痛苦——尤其是对开发人员来说。使用 Spring Boot,开发人员只需几个简单的步骤即可设置简单微服务的运行版本。
容器环境
今天我们已经确立了容器环境的概念。每个开发人员都可以使用一个简单的 Docker 命令启动任何类型的服务器或运行时环境。在容器环境中启动像Payara、Wildfly或OpenLiberty这样的现代应用程序服务器只需几秒钟,而部署微服务只需几秒钟。例如,要将您的微服务与最新的 Wildfly Docker 映像捆绑在一起,Dockerfile 如下所示:
FROM jboss/wildfly
ADD my-app.war /opt/jboss/wildfly/standalone/deployments/
要启动您的服务,您只需运行:
$ docker build --tag=my-app . && docker run -it my-app
这平衡了Spring Boot的初始优势。除了Jakarta EE组件要小得多这一事实外,您还可以在几秒钟内将微服务部署到不同的环境中。这为您的运行环境提供了更大的灵活性。但这不是唯一的优势。
摆脱依赖
使用Jakarta EE更有趣的方面是您没有对某些库的硬编码依赖。再次查看Spring Boot项目的 pom.xml,您会发现很多依赖项与您的项目捆绑在一起。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.4.0</version>
</dependency>
....
JPA 实现了 Jax-RS 实现等所有库都将成为您最终构建的一部分。相比之下,在Jakarta EE项目中,您不知道目标运行时将使用哪个 JPA 或 Jax-RS 实现。这意味着您的应用程序也更具互操作性。当开发人员开始使用具体实现的某些特性时,这一点变得更加明显。
Spring Boot 开发人员经常使用诸如 Rest API Jersey之类的 API 的特定功能来解决问题。但此时您的应用程序不再与其他 Jax-RS 实现兼容,例如Rest Easy。这是一个很大的威胁。针对 API 而不是具体实现进行开发是一种很好的做法。
日志4j
捆绑库的危险性最近在 Log4j 错误中变得清晰起来。一个简单而典型的 Spring Boot 依赖项,如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
… 可能导致您的最终应用程序出现安全漏洞。由于 Log4j 库现在是您构建的一部分。要更新此依赖项,您需要更新代码并重建和推出Spring Boot应用程序。
相比之下,在Jakarta EE中,您永远不会针对特定实现构建代码,而只会针对接口构建代码。这意味着您的代码以及最终的组件永远不会对特定实现有硬编码依赖。在具体示例中,您只需更改运行时环境,无需更新或重建代码。这意味着对于像 Kubernetes 这样的容器环境,您只需更新映像版本并重新启动容器。
结论
我想再次澄清一下,我不是在谈论这两个应用程序框架的 API。Spring Boot和Jakarta EE都提供了类似的功能范围,可以快速轻松地开发微服务。
然而,Spring Boot构建可启动服务器的原有优势在容器环境时代似乎越来越成为劣势。失去了灵活性,并冒着变得非常依赖库的风险,您作为开发人员无法监督其影响。
相比之下,当今应用程序服务器提供了容器技术的使用,使您能够在开发过程中使用类似生产的服务器系统。从这个角度来看,在我看来,今天围绕你的微服务构建一个可启动的服务器已经没有意义了。