当前位置: 首页 > 工具软件 > Ratpack > 使用案例 >

java异步http服务器框架_高性能异步HTTP服务器 - Ratpack

陈季
2023-12-01

Ratpack API构建在Java 8上,提供Gradle支持,也可使用任何基于JVM的构建工具。

包是唯一必需的类库:ratpack-core

可选类库:ratpack-groovy、ratpack-guice、ratpack-jackson、ratpack-test

示例import ratpack.test.embed.EmbeddedApp;

import static org.junit.Assert.assertEquals;

public class Example {

public static void main(String... args) throws Exception {

EmbeddedApp.fromHandler(ctx ->

ctx.render("Hello World!")

).test(httpClient ->

assertEquals("Hello World!", httpClient.getText())

);

}

}

服务器(RatpackServer)

RatpackServer用于启动应用。import ratpack.server.RatpackServer;

import ratpack.server.ServerConfig;

import java.net.URI;

public class Main {

public static void main(String... args) throws Exception {

RatpackServer.start(server -> server

.serverConfig(ServerConfig.embedded().publicAddress(new URI("http://cs.xieyonghui.com")))

.registryOf(registry -> registry.add("World!"))

.handlers(chain -> chain

.get(ctx -> ctx.render("Hello " + ctx.get(String.class)))

.get(":name", ctx -> ctx.render("Hello " + ctx.getPathTokens().get("name") + "!"))

)

);

}

}

定义了两个接口:of()、start(),方法接收一个RatpackServerSpec对象,用于配置Ratpack应用的三个基本面:

服务器配置/server config、基础注册表/base registry、根处理程序/root handler。

服务器配置

ServerConfig定义是必需的,用于设置服务器启动项,使用ServerConfig静态方法创建实例。

基础目录

Ratpack服务器配置的一个重点是基础目录。

基础目录实际上是应用程序文件系统的根,便于移植文件系统。

运行时期间根据基础目录,解析应用程序中所有相对路径,如:静态资源(图像、脚本)的相对路径。

baseDir(Path)方法能设置基础目录,但BaseDir.find()更常见,支持在类路径上查找基础目录,提供更好的跨平台移植性。

此方法会在类路径上的“/.ratpack”目录下搜索资源。import ratpack.server.ServerConfig;

import ratpack.test.embed.EphemeralBaseDir;

import ratpack.test.embed.EmbeddedApp;

import java.net.URL;

import java.net.URLClassLoader;

import java.nio.file.Path;

import static org.junit.Assert.assertEquals;

public class Example {

public static void main(String... args) throws Exception {

EphemeralBaseDir.tmpDir().use(baseDir -> {

baseDir.write("mydir/.ratpack", "");

baseDir.write("mydir/assets/message.txt", "Hello Ratpack!");

Path mydir = baseDir.getRoot().resolve("mydir");

ClassLoader classLoader = new URLClassLoader(new URL[]{mydir.toUri().toURL()});

Thread.currentThread().setContextClassLoader(classLoader);

EmbeddedApp.of(serverSpec -> serverSpec

.serverConfig(c -> c.baseDir(mydir))

.handlers(chain ->

chain.files(f -> f.dir("assets"))

)

).test(httpClient -> {

String message = httpClient.getText("message.txt");

assertEquals("Hello Ratpack!", message);

});

});

}

}

示例中使用EphemeralBaseDir构造新的类加载器上下文,实际应用时主方法只需调用BaseDir.find(),使用适当的类路径启动Ratpack应用程序。

端口

ServerConfigBuilder port(int port) 设置服务器的端口。默认端口5050。

Ratpack Registry

一个registry是一个按类型存储的对象,应用程序中可能有许多不同的注册表。import ratpack.handling.Handler;

import ratpack.handling.Context;

import ratpack.registry.Registry;

import static org.junit.Assert.assertTrue;

public class Thing {

private final String name

public Thing(String name) { this.name = name; }

public String getName() { return name; }

}

public class UpstreamHandler implements Handler {

public void handle(Context context) {

context.next(Registry.single(new Thing("foo")));

}

}

public class DownstreamHandler implements Handler {

public void handle(Context context) {

assertTrue(context instanceof Registry);

Thing thing = context.get(Thing.class);

context.render(thing.getName());

}

}

import ratpack.test.handling.HandlingResult;

import ratpack.test.handling.RequestFixture;

import static ratpack.handling.Handlers.chain;

import static ratpack.func.Action.noop;

import static org.junit.Assert.assertEquals;

Handler chain = chain(new UpstreamHandler(), new DownstreamHandler());

HandlingResult result = RequestFixture.handle(chain, noop());

assertEquals("foo", result.rendered(String.class));

处理程序

Ratpack Handler是HTTP请求的处理程序,处理程序是可组合的,很少有应用程序只包含一个处理程序。

大多数应用服务器都是复合处理程序,常用handlers(Action)方法创建,使用Chain DSL创建复合处理程序。

启动/停止

应用程序启动时会通知服务器注册表中的所有服务。

应用程序停止时将通知所有服务执行清理程序。import ratpack.server.RatpackServer;

import ratpack.server.ServerConfig;

import ratpack.service.Service;

import ratpack.service.StartEvent;

import ratpack.service.StopEvent;

import java.util.List;

import java.util.LinkedList;

import static org.junit.Assert.*;

public class Example {

static class RecordingService implements Service {

public final List events = new LinkedList<>();

public void onStart(StartEvent event) {

events.add("start");

}

public void onStop(StopEvent event) {

events.add("stop");

}

}

public static void main(String... args) throws Exception {

RecordingService service = new RecordingService();

RatpackServer server = RatpackServer.of(s -> s

.serverConfig(ServerConfig.embedded())

.registryOf(r -> r.add(service))

.handler(r -> ctx -> ctx.render("ok"))

);

assertEquals("[]", service.events.toString());

server.start();

assertEquals("[start]", service.events.toString());

server.reload();

assertEquals("[start, stop, start]", service.events.toString());

server.stop();

assertEquals("[start, stop, start, stop]", service.events.toString());

}

}

单元测试

ExecHarness测试程序是Ratpack测试支持的一部分。

常用Ratpack Promise异步结构代码执行单元测试。

Ratpack Promise用来避免异步调用时的地狱回调。import com.google.common.io.Files;

import ratpack.test.exec.ExecHarness;

import ratpack.exec.Blocking;

import java.io.File;

import java.nio.charset.StandardCharsets;

import static org.junit.Assert.assertEquals;

public class Example {

public static void main(String... args) throws Exception {

File tmpFile = File.createTempFile("ratpack", "test");

Files.write("Hello World!", tmpFile, StandardCharsets.UTF_8);

tmpFile.deleteOnExit();

String content = ExecHarness.yieldSingle(e ->

Blocking.get(() -> Files.toString(tmpFile, StandardCharsets.UTF_8))

).getValueOrThrow();

assertEquals("Hello World!", content);

}

}

目标和理念

目标

快速、高效、可扩展,允许应用在不妥协的前提下在进行复杂性进化,利用非阻塞编程降低成本。

在集成其他工具和库时的灵活性,允许应用程序轻松、彻底地进行测试。

不可及的方面

成为一个完全的“全栈”解决方案;在一个简洁的框架中提供所有的功能;为“业务逻辑”而生的框架。

 类似资料: