Jakarta EE 10的七大功能


Java EE 一直是所有 Java 企业开发背后的主导力量。最近,它被重命名为Jakarta EE,同时过渡到 Eclipse 基金会。

这种转变为开放治理、开放兼容性测试(早期的技术兼容性工具包是闭源的)以及当然的开源贡献打开了大门。这意味着没有哪个特定供应商的影响力比其他任何供应商都大,而且它现在是一个更加分散的过程。

Jakarta EE 是 Java 生态系统不可或缺的一部分。25-35% 的 Java 应用程序在 JakartaEE 应用程序服务器上运行。WildFly、JBoss EAP、Payara、WebSphere/Liberty、WebLogic 等是这些应用服务器的一些示例。这些应用服务器由不同的供应商开发和维护。然而,作为一项技术,Jakarta EE 仍然是供应商中立的,这意味着相同的应用程序代码应该能够通过任何应用程序服务器运行,因为所有供应商都遵守Jakarta EE 规范

70-80% 的 Java 应用程序以一种或另一种方式使用 Jakarta EE API,例如 Tomcat、Hibernate、ActiveMQ、Jetty、CXF、Jersey、RESTEasy、Quarkus、Microprofile 和 Spring。如果我们再深入一点,我们会发现 Java 应用程序背后的 Jakarta EE API。 

Jakarta EE 是一个活跃的生态系统。我们有 Jakarta EE、  MicroProfileHelidon在Micronaut和 Helidon之后引入的Quarkus仍然是一个流行的框架。许多应用程序尚未迁移,这就是 Java EE 8 仍然存在的原因。但是,Jakarta EE 9 可以被认为是推动 Jakarta EE 10 中新功能的创新基础,该版本即将发布。  

Jakarta EE 9 将所有相关规范javax移至 Jakarta 命名空间。不幸的是,这导致了一些重大变化,但迁移似乎相对容易。有工具可以做到这一点。它还删除了旧的弃用技术并将 Java 8 迁移到 Java 11。  

在进入 Jakarta EE 10 的众多功能中,我将讨论前 7 个功能,排名不分先后。

1. @ManagedExecutorDefinition
Jakarta Concurrency API 中最常用的服务之一是 ManagedExecutorService
它用于在 Jakarta EE 环境中创建线程池,以更易于管理的方式生成线程。
尽管它与ExecutorService几乎相同,但我们在 Java SE 环境中使用它。
为了配置线程池,我们有一个特定于供应商的设置。现在它可以只用注释来定义。这是一种更标准的配置线程池的方式。


@Named
@ApplicationScoped
@ManagedExecutorDefinition(
    name = "java:module/concurrent/MyExecutor",
    context =
"java:module/concurrent/MyExecutorContext",
    hungTaskThreshold = 120000,
    maxAsync = 5)
@ContextServiceDefinition(
    name =
"java:module/concurrent/MyExecutorContext",
    propagated = {SECURITY, APPLICATION})
public class WorkService {

  @Resource(name =
"java:app/concurrent/MyExecutorService")
  private ManagedExecutorService executor;

  @Asynchronous
  public CompletableFuture<Long> hoursWorked(LocalDate from, LocalDate to) {
    return CompletableFuture.supplyAsync(() -> heavyAPICall(from, to), executor);
  }

  private static long heavyAPICall(LocalDate from, LocalDate to) {
    return Duration.between(from, to).toMillis();
  }
}

2.@异步
EJB 中有一个类似的注释可用。使用此注解注解的方法应该异步运行。但是,EJB 有点过时了。
另外,在 EJB 中,我们不能指定线程池。它曾经使用应用服务器的默认线程池。现在新的注解 jakarta.enterprise.concurrent.Asynchronous
 自带Jakarta EE Con​​currency 3.0,不需要使用EJB,我们可以指定线程池。它可以与任何 CDI bean 一起使用。每个异步方法执行对应于一个托管 java.util.concurrent.CompletableFuture 实例,该实例由 a jakarta.enterprise.concurrent.ManagedExecutorService 作为其默认异步执行工具提供支持。 


@Named
@ApplicationScoped
public class PaymentService {

  @Asynchronous(executor = "java:app/concurrent/MyExecutorService")
  public CompletableFuture<Confirmation> processPayment(final Order order) {
    try {
      var status = processOrder(order);

      return CompletableFuture.completedFuture(status);
    } catch (PaymentException ex) {
      throw new CompletionException(ex);
    }
  }

  private Confirmation processOrder(Order order) {
    return new Confirmation();
  }
}

class PaymentException extends RuntimeException {
}

record Confirmation() {
}

record Order() {
}

3.引导API
如果您在 Jakarta EE 环境之外调用 REST 服务,例如单元测试、集成测试等,最好有一个独立的 API 来执行此操作。
有了这个,你不需要运行整个容器。因此,它变得非常方便。

4. 多部分/表单数据
Jakarta RESTful Web Service是开发人员中用于公开 RESTful 端点的流行功能之一。但是,它并没有以标准方式完全支持多部分表单数据。 
这就是为什么多年来,开发人员需要 Servlet 或特定于供应商的 REST API 来处理多部分媒体类型。 
使用 Jakarta REST 3.1,我们不再需要处理这样的问题,并且它增加了对多部分表单数据的全面支持,这是标准的。

package ca.bazlur;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.EntityPart;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;


@Path("/job")
public class FileResource {

  @Path(
"/apply")
  @POST
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  public Response applyForJob(
      @FormParam(
"name") String name, @FormParam("recentPhoto") EntityPart photo,
      @FormParam(
"resume") EntityPart resume) {
    processApplication(name,
        photo.getMediaType(), photo.getContent(), resume.getMediaType(), resume.getContent());
    return Response.ok(
"Application received").build();
  }

  private void processApplication(String name, MediaType mediaType, InputStream content,
      MediaType mediaType1, InputStream content1) {
  }
}

5. @OpenIdAuthenticationDefinition
好吧,多年来,我们一直在使用用户名和密码来验证 Web 应用程序中的用户。然而,在现代应用程序中,使用其他服务登录已变得很普遍,例如 Facebook、Google、Twitter 等。  
OpenID Connect 协议支持这种身份验证。在Jakarta Security 3.0 中,我们现在有了一个标准方式来遵守 OpenID Connect,只使用一个注解,即 @OpenIdAuthenticationDefinition。 
现在的生活简单多了;指定所需的属性,例如 Provider URI、clientId、clientSecret、redirect URI 等。 

@OpenIdAuthenticationDefinition(
       providerURI = "https://sample-openid-server.com",
       clientId =
"87068hgfg5675htfv6mrucov57bknst.apps.sample.com",
       clientSecret =
"{my-secret}",
       redirectURI =
"${baseURL}/callback",
       extraParameters = {
           
"testKey=testValue",
           
"testKey2=testValue2"
       }
)
public class SecurityConfig {
}

6.UUID键
Jakarta Persistence 3.1带来java.util.UUID的是作为基本类型的字段,对于云环境的实体 ID 来说非常方便,因为很多数据库不会自动生成 UUID。 

package ca.bazlur;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.util.UUID;

@Entity
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.UUID)
  private UUID id;

  private String username;
  private String password;
}

此外,它还为查询语言和 Criteria API 带来了一些功能。新功能分为三类:

  • 数值函数(CEILING、EXP、FLOOR、LN、POWER、ROUND、SIGN)
  • 使用java.time 类型(LOCAL DATE、LOCAL DATETIME、LOCAL TIME)返回当前本地日期和时间的函数 
  • EXTRACT 函数从给定日期(YEAR、QUARTER、MONTH、WEEK、DAY、HOUR、MINUTE、SECOND)中提取数字部分


7. Jakarta 使用纯 Java Faces视图
Jakarta Faces 4.0带来了一个新的 API,可以仅使用 Java 代码来定义完整视图(HTML 页面)。
如果您对编写任何类型的标记语言特别不感兴趣,您现在可以使用纯 Java Faces 视图完全用 Java 编写您的 UI 代码。我喜欢它。


整个 Jakarta 10 平台的最终版本将在下个月发布。