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
注解提供了相互关联的 PersonService
、PersonRepository
和 DataSource
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));
}
在最终方法中,我们使用 Promise
的 combine()
方法组合了 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()
方法。方法内部获取 PersonService
的 findAndVerifyPerson()
结果,将其转为 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();
}
我们调用了接口并异步获取预期结果。测试结束后调用 Eventloop
的 breakEventloop()
方法停止执行。
5. 总结
本文介绍了 ActiveJ 框架的核心特性。利用这些功能,我们已经可以构建高效轻量的 Web 应用。但该框架远不止于此——它还适用于数据处理、分布式系统等多种场景。其模块化特性帮助我们避免项目臃肿,只引入必要的组件。