1. 框架概述

ActiveJ 是一个轻量级 Java 框架,专为构建高性能应用而设计。它允许我们创建启动速度快、内存占用小的极简模块化应用。该框架提供异步 I/O、依赖注入、高效序列化和响应式编程支持等核心特性。

本文将探讨 ActiveJ 的主要功能,包括其 Inspect 模块、强大的事件循环和高级网络能力。

2. 依赖注入

我们先从 ActiveJ Inject 开始。这是一个轻量级且性能优化的依赖注入库,用于配置 Bean 之间的依赖关系。下面看看具体用法。

2.1. 依赖配置

将 ActiveJ Inject 依赖 添加到项目:

<dependency>
    <groupId>io.activej</groupId>
    <artifactId>activej-inject</artifactId>
    <version>6.0-rc2</version>
</dependency>

2.2. 基于模块的依赖注入

创建一个 Repository Bean:

public class PersonRepository {
    private final DataSource dataSource;

    public PersonRepository(DataSource dataSource) {
          this.dataSource = dataSource;
    }
}

PersonRepository 中我们声明了对 DataSource 实例的依赖。接下来创建 Service 类:

public class PersonService {
    private final PersonRepository personRepository;

    public PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
}

PersonService 类声明了对 PersonRepository 的依赖。

现在创建 PersonModule 类配置所有 Bean 的关系:

public class PersonModule extends AbstractModule {

    @Provides
    PersonService personService(PersonRepository personRepository) {
        return new PersonService(personRepository);
    }

    @Provides
    PersonRepository personRepository(DataSource dataSource) {
        return new PersonRepository(dataSource);
    }

    @Provides
    DataSource dataSource() {
        return new DataSource() {
            //DataSource methods
        };
    }
}

我们继承了 AbstractModule 类,并通过 @Provides 注解提供了相互关联的 PersonServicePersonRepositoryDataSource Bean

测试依赖注入行为:

public class ActiveJTest {

    @Test
    void givenPersonModule_whenGetTheServiceBean_thenAllTheDependenciesShouldBePresent() {
        PersonModule personModule = new PersonModule();

        PersonService personService = Injector.of(personModule).getInstance(PersonService.class);
        assertNotNull(personService);
        PersonRepository personRepository = personService.getPersonRepository();
        assertNotNull(personRepository);
        DataSource dataSource = personRepository.getDataSource();
        assertNotNull(dataSource);
    }
}

我们创建了 PersonModule 实例。然后通过 Injector 获取 PersonService 实例。可以看到所有依赖都被正确注入。

3. 异步 I/O

ActiveJ Async I/O 提供了高效编写异步流程的组件。我们将通过 Promises事件循环 等关键元素来理解这个特性。

3.1. 依赖配置

添加 activej-promise 依赖

<dependency>
    <groupId>io.activej</groupId>
    <artifactId>activej-promise</artifactId>
    <version>6.0-rc2</version>
</dependency>

3.2. Promise 机制

创建使用的模型类:

public record Person(String name, String description) {
}

PersonRepository 类中添加业务逻辑:

public Promise<Person> findPerson(String name) {
    return Promises
      .delay(Duration.ofMillis(100), new Person(name, name + " description"));
}

我们添加了 findPerson() 方法模拟按名称查找的过程。使用 Promises.delay() 延迟生成 Person 实例,结果会被包装在 Promise

接下来创建 Service 层使用的模型:

public record VerifiedPerson(String name, String description, String notes, String result) {
}

VerifiedPerson 包含人员信息和验证结果。

PersonService 类中添加业务逻辑:

private Promise<String> findPersonNotes(String name) {
    return Promise.of(name + " notes");
}

findPersonNotes() 方法模拟获取人员备注的过程,结果同样通过 Promise.of() 包装。

添加验证方法:

private VerifiedPerson verify(VerifiedPerson person) {
    if(person.description().startsWith("Good")) {
        return new VerifiedPerson(person.name(), person.description(), person.notes(), "SUCCESS");
    }

    return new VerifiedPerson(person.name(), person.description(), person.notes(), "FAIL");
}

这里模拟验证过程,根据描述添加验证结果。

最后组合所有操作完成流程:

public Promise<VerifiedPerson> findAndVerifyPerson(String name) {
    return personRepository.findPerson(name)
      .combine(findPersonNotes(name),
        (person, notes) -> new VerifiedPerson(person.name(), person.description(), notes, null))
      .map(person -> verify(person));
}

在最终方法中,我们使用 Promisecombine() 方法组合了 Repository 的 findPerson() 和 Service 的 findPersonNotes() 操作。然后验证模型并返回包含最终结果的 Promise

3.3. 事件循环

ActiveJ 事件循环 在事件循环和线程中异步执行代码。看看如何用它运行基于 Promise 的流程:

@Test
void givenEventloop_whenCallFindAndVerifyPerson_thenExpectedVerificationResultShouldBePresent() {
    PersonModule personModule = new PersonModule();

    PersonService personService = Injector.of(personModule).getInstance(PersonService.class);

    Eventloop eventloop = Eventloop.create();
    eventloop.run();
    personService.findAndVerifyPerson("Good person")
      .whenResult(verifiedPerson -> assertEquals("SUCCESS", verifiedPerson.result()));
}

我们从 PersonModule 获取 PersonService。然后通过 Eventloop.create() 创建事件循环实例并用 run() 启动。接着调用 findAndVerifyPerson() 方法。如果忘记调用 run()会抛出以下异常

IllegalStateException: No reactor in current thread

4. HTTP 服务器

ActiveJ 另一个强大特性是高性能异步 HTTP 服务器

4.1. 依赖配置

添加 ActiveJ HTTP 依赖

<dependency>
    <groupId>io.activej</groupId>
    <artifactId>activej-http</artifactId>
    <version>6.0-rc2</version>
</dependency>

添加 Jackson Databind 依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

4.2. REST 接口示例

通过 HTTP 接口暴露 VerifiedPerson 流程。先创建 PersonController 类:

public class PersonController implements AsyncServlet {
    private final PersonService personService;
    private final ObjectMapper objectMapper;

    public PersonController(PersonService personService) {
        this.personService = personService;
        this.objectMapper = new ObjectMapper();
    }

    @Override
    public Promise<HttpResponse> serve(HttpRequest httpRequest) {
        return personService.findAndVerifyPerson(httpRequest.getQueryParameter("name"))
          .map((p) -> HttpResponse.ok200().withJson(objectMapper.writeValueAsString(p)).build())
          .mapException(e -> e);
    }
}

我们实现了 AsyncServlet 接口并重写 serve() 方法。方法内部获取 PersonServicefindAndVerifyPerson() 结果,将其转为 JSON 作为 HTTP 响应体返回 200 状态码。异常情况单独处理,默认返回 500 状态码

将控制器添加到注入上下文:

public class PersonModule extends AbstractModule {

    @Provides
    PersonController personController(PersonService personService) {
        return new PersonController(personService);
    }
    //其他 Bean
}

我们在 PersonModule 中添加了 PersonController 并配置其依赖。

最后编写 HTTP 服务器代码:

public class ActiveJIntegrationTest {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static HttpServer server;
    private static HttpClient client;
    private static int port;
    private static Eventloop eventloop;

    @BeforeAll
    static void setUp() throws Exception {
        eventloop = Eventloop.create();

        PersonModule personModule = new PersonModule();
        PersonController personController = Injector.of(personModule).getInstance(PersonController.class);

        RoutingServlet servlet = RoutingServlet.builder(eventloop)
          .with(HttpMethod.GET,"/person", personController)
          .build();

        server = HttpServer.builder(eventloop, servlet)
          .withListenPort(8080)
          .build();

        server.listen();

        port = server.getListenAddresses().get(0).getPort();

        InetAddress dnsServerAddress = InetAddress.getByName("8.8.8.8");
        DnsClient dnsClient = DnsClient.builder(eventloop, dnsServerAddress).build();
        client = HttpClient.builder(eventloop, dnsClient).build();
    }

    @AfterAll
    static void tearDown() {
        if (server != null) {
            server.close();
        }
    }
}

我们创建了 HttpServer 实例,使用 RoutingServlet 添加 HTTP 映射。最后通过 listen() 启动服务器并准备异步 HTTP 客户端。

调用接口并验证结果:

@Test
void givenHttpServer_whenCallPersonEndpoint_thenExpectedVerificationResultShouldPresentInResponse() {
    HttpRequest request = HttpRequest.get("http://localhost:" + port + "/person?name=my-name").build();

    client.request(request)
      .whenResult(response -> {
        assertEquals(response.getCode(), 200);

        response.loadBody()
          .whenResult(body -> {
              try {
                  VerifiedPerson responseData = objectMapper.readValue(body.getArray(),
                    VerifiedPerson.class);
                  assertEquals(responseData.result(), "FAIL");
                  eventloop.breakEventloop();
              } catch (Exception e) {
                throw new RuntimeException(e);
              }
          });
      });

    eventloop.run();
}

我们调用了接口并异步获取预期结果。测试结束后调用 EventloopbreakEventloop() 方法停止执行

5. 总结

本文介绍了 ActiveJ 框架的核心特性。利用这些功能,我们已经可以构建高效轻量的 Web 应用。但该框架远不止于此——它还适用于数据处理、分布式系统等多种场景。其模块化特性帮助我们避免项目臃肿,只引入必要的组件。


原始标题:Introduction to ActiveJ | Baeldung