1. 简介
ActiveJ 是一个轻量级的 Java 框架,适用于高性能应用。我们可以用它来创建启动速度快、内存占用小的极简和模块化应用。它提供了异步 I/O、依赖注入、高效序列化和响应式编程支持等特性。
在本教程中,我们将讨论 ActiveJ 的主要特性,包括其 Inspect 模块、强大的事件循环和高级网络功能。
2. 注入
我们从 ActiveJ Inject 开始。它是一个轻量且性能优化的依赖注入库,可用于设置 bean 之间的依赖关系。让我们看看如何使用它。
2.1. 依赖
让我们将 Active Inject 依赖 添加到项目中:
<dependency>
<groupId>io.activej</groupId>
<artifactId>activej-inject</artifactId>
<version>6.0-rc2</version>
</dependency>
2.2. 使用模块进行依赖注入
让我们创建一个仓库 bean:
public class PersonRepository {
private final DataSource dataSource;
public PersonRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
}
在我们的 PersonRepository
中,只指定了对 DataSource
实例的依赖。现在让我们创建一个服务类:
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
类。此外,我们提供了 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 和 Event Loop 等关键元素来理解这一特性。
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
实例。
接下来,创建服务层要生成的另一个模型:
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()
方法,将仓库的findPerson()
和服务的findPersonNotes()
两个 promise 合并。然后对模型进行验证,返回最终结果的`Promise_。
3.3. 事件循环
**ActiveJ 的 Eventloop 在事件循环和线程中异步执行代码。**让我们看看如何用它来运行基于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);
}
//Other beans
}
我们将PersonController
加入PersonModule
并配置了其依赖。
最后,引入 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 应用。当然,该框架还远不止于此。
我们还可以用它进行数据处理、分布式系统等多种场景。其模块化特性帮助我们避免项目臃肿,只引入必要组件。
没有回复内容