Javaに組み込まれたJettyサーバー
1. 概要
この記事では、Jettyライブラリについて説明します。 Jettyは、組み込みコンテナとして実行でき、javax.servletライブラリと簡単に統合できるWebサーバーを提供します。
2. Mavenの依存関係
開始するには、Mavenの依存関係をjetty-serverおよびjetty-servletライブラリに追加します。
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.3.v20170317</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.3.v20170317</version>
</dependency>
3. サーブレットを使用したJettyサーバーの起動
Jetty組み込みコンテナの起動は簡単です。 新しいサーバーオブジェクトをインスタンス化し、特定のポートで開始するように設定する必要があります。
public class JettyServer {
private Server server;
public void start() throws Exception {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8090);
server.setConnectors(new Connector[] {connector});
}
すべてがうまくいけば、HTTPステータスコード200と単純なJSONペイロードで応答するエンドポイントを作成するとします。
このような要求を処理するためにHttpServletクラスを拡張するクラスを作成します。 このクラスはシングルスレッドであり、完了するまでブロックされます。
public class BlockingServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("{ \"status\": \"ok\"}");
}
}
次に、 addServletWithMapping()メソッドを使用して、BlockingServletクラスをServletHandlerオブジェクトに登録し、サーバーを起動する必要があります。
servletHandler.addServletWithMapping(BlockingServlet.class, "/status");
server.start();
サーブレットロジックをテストする場合は、テストセットアップ内の実際のJettyサーバーインスタンスのラッパーである、以前に作成されたJettyServerクラスを使用してサーバーを起動する必要があります。
@Before
public void setup() throws Exception {
jettyServer = new JettyServer();
jettyServer.start();
}
開始したら、テストHTTPリクエストを /statusエンドポイントに送信します。
String url = "http://localhost:8090/status";
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
4. ノンブロッキングサーブレット
Jettyは、非同期要求処理を適切にサポートしています。
実行中のスレッドをかなりの時間ロードブロッキングするのに長い時間がかかるI/O集約型の膨大なリソースがあるとしましょう。 I / Oリソースを待つのではなく、そのスレッドを解放して、その間に他の要求を処理できるようにするとよいでしょう。
このようなロジックをJettyに提供するために、 AsyncContext クラスを呼び出すことによって startAsync() 上のメソッド
public class AsyncServlet extends HttpServlet {
private static String HEAVY_RESOURCE
= "This is some heavy resource that will be served in an async way";
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ByteBuffer content = ByteBuffer.wrap(
HEAVY_RESOURCE.getBytes(StandardCharsets.UTF_8));
AsyncContext async = request.startAsync();
ServletOutputStream out = response.getOutputStream();
out.setWriteListener(new WriteListener() {
@Override
public void onWritePossible() throws IOException {
while (out.isReady()) {
if (!content.hasRemaining()) {
response.setStatus(200);
async.complete();
return;
}
out.write(content.get());
}
}
@Override
public void onError(Throwable t) {
getServletContext().log("Async Error", t);
async.complete();
}
});
}
}
ByteBufferをOutputStreamに書き込んでおり、バッファー全体が書き込まれると、
次に、AsyncServletをJettyサーブレットマッピングとして追加する必要があります。
servletHandler.addServletWithMapping(
AsyncServlet.class, "/heavy/async");
これで、 / Heavy / async エンドポイントにリクエストを送信できます。このリクエストは、Jettyによって非同期的に処理されます。
String url = "http://localhost:8090/heavy/async";
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
assertThat(response.getStatusLine().getStatusCode())
.isEqualTo(200);
String responseContent = IOUtils.toString(r
esponse.getEntity().getContent(), StandardCharsets.UTF_8);
assertThat(responseContent).isEqualTo(
"This is some heavy resource that will be served in an async way");
アプリケーションが非同期でリクエストを処理している場合は、スレッドプールを明示的に構成する必要があります。 次のセクションでは、カスタムスレッドプールを使用するようにJettyを構成します。
5. 桟橋の構成
Webアプリケーションを本番環境で実行する場合、Jettyサーバーがリクエストを処理する方法を調整したい場合があります。 これは、スレッドプールを定義し、それをJettyサーバーに適用することによって行われます。
これを行うために、設定できる3つの構成設定があります。
- maxThreads –Jettyがプールで作成および使用できるスレッドの最大数を指定します
- minThreads –Jettyが使用するプール内のスレッドの初期数を設定します
- idleTimeout –この値はミリ秒単位で、スレッドが停止してスレッドプールから削除されるまでにアイドル状態にできる時間を定義します。 プール内の残りのスレッドの数がminThreads設定を下回ることはありません
これらを使用して、構成済みのスレッドプールをサーバーコンストラクターに渡すことにより、組み込みのJettyサーバーをプログラムで構成できます。
int maxThreads = 100;
int minThreads = 10;
int idleTimeout = 120;
QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, minThreads, idleTimeout);
server = new Server(threadPool);
次に、サーバーを起動すると、特定のスレッドプールのスレッドが使用されます。
6. 結論
このクイックチュートリアルでは、組み込みサーバーをJettyと統合する方法を確認し、Webアプリケーションをテストしました。
いつものように、コードはGitHubでから入手できます。