Server Jetty Tertanam di Java

1. Ikhtisar

Pada artikel ini, kita akan melihat perpustakaan Jetty . Jetty menyediakan server web yang dapat dijalankan sebagai wadah tertanam dan terintegrasi dengan mudah dengan pustaka javax.servlet .

2. Ketergantungan Maven

Untuk memulai, kami akan menambahkan dependensi Maven ke pustaka jetty-server dan jetty-servlet:

 org.eclipse.jetty jetty-server 9.4.3.v20170317   org.eclipse.jetty jetty-servlet 9.4.3.v20170317 

3. Memulai Server Jetty Dengan Servlet

Memulai container tertanam Jetty itu sederhana. Kita perlu membuat objek Server baru dan mengaturnya untuk memulai pada port tertentu:

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}); }

Katakanlah kita ingin membuat titik akhir yang akan merespons dengan kode status HTTP 200 jika semuanya berjalan dengan baik dan muatan JSON sederhana.

Kita akan membuat kelas yang memperluas kelas HttpServlet untuk menangani permintaan seperti itu; kelas ini akan menjadi satu utas dan blokir sampai selesai:

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\"}"); } }

Selanjutnya, kita perlu mendaftarkan kelas BlockingServlet di objek ServletHandler dengan menggunakan metode addServletWithMapping () dan memulai server:

servletHandler.addServletWithMapping(BlockingServlet.class, "/status"); server.start();

Jika kami ingin menguji logika Servlet kami, kami perlu memulai server kami dengan menggunakan kelas JettyServer yang dibuat sebelumnya yang merupakan pembungkus dari instance server Jetty yang sebenarnya dalam pengaturan pengujian:

@Before public void setup() throws Exception { jettyServer = new JettyServer(); jettyServer.start(); }

Setelah dimulai, kami akan mengirim permintaan HTTP uji ke titik akhir / status :

String url = "//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. Servlet Tanpa Pemblokiran

Jetty memiliki dukungan yang baik untuk pemrosesan permintaan asynchronous.

Katakanlah kita memiliki sumber daya yang sangat besar yang I / O intens membutuhkan waktu lama untuk memuat pemblokiran thread yang menjalankan untuk waktu yang cukup lama. Lebih baik jika utas tersebut dapat dibebaskan untuk menangani permintaan lain untuk sementara, daripada menunggu beberapa sumber I / O.

Untuk menyediakan logika seperti itu dengan Jetty, kita bisa membuat servlet yang akan menggunakan kelas AsyncContext dengan memanggil metode startAsync () pada HttpServletRequest. Kode ini tidak akan memblokir utas yang menjalankan tetapi akan melakukan operasi I / O di utas terpisah yang mengembalikan hasilnya ketika siap menggunakan metode AsyncContext.complete () :

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(); } }); } }

Kami menulis ByteBuffer ke OutputStream , dan setelah seluruh buffer ditulis, kami memberi isyarat bahwa hasilnya siap untuk dikembalikan ke klien dengan menjalankan metode complete () .

Selanjutnya, kita perlu menambahkan AsyncServlet sebagai pemetaan servlet Jetty:

servletHandler.addServletWithMapping( AsyncServlet.class, "/heavy/async");

Sekarang kita dapat mengirim permintaan ke titik akhir / heavy / async - permintaan itu akan ditangani oleh Jetty dengan cara yang tidak sinkron:

String url = "//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");

Ketika aplikasi kita menangani permintaan dengan cara asynchronous, kita harus mengkonfigurasi kumpulan thread secara eksplisit. Di bagian selanjutnya, kita akan mengonfigurasi Jetty untuk menggunakan kumpulan utas khusus.

5. Konfigurasi Dermaga

Ketika kita menjalankan aplikasi web kita pada produksi, kita mungkin ingin menyesuaikan bagaimana server Jetty memproses permintaan. Ini dilakukan dengan menentukan kumpulan utas dan menerapkannya ke server Jetty kami.

Untuk melakukan ini, kami memiliki tiga pengaturan konfigurasi yang dapat kami atur:

  • maxThreads - Untuk menentukan jumlah maksimum utas yang dapat dibuat dan digunakan oleh Jetty dalam kumpulan
  • minThreads - Untuk menyetel jumlah awal utas di kumpulan yang akan digunakan Jetty
  • idleTimeout - Nilai dalam milidetik ini menentukan berapa lama thread dapat diam sebelum dihentikan dan dihapus dari kumpulan thread. Jumlah utas yang tersisa di kumpulan tidak akan pernah lebih rendah dari pengaturan minThreads

Dengan ini kita dapat mengkonfigurasi server Jetty tertanam secara terprogram dengan melewatkan kumpulan utas yang dikonfigurasi ke konstruktor Server :

int maxThreads = 100; int minThreads = 10; int idleTimeout = 120; QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, minThreads, idleTimeout); server = new Server(threadPool);

Kemudian, ketika kami memulai server kami, itu akan menggunakan utas dari kumpulan utas tertentu.

6. Kesimpulan

Dalam tutorial singkat ini, kami melihat bagaimana mengintegrasikan server tertanam dengan Jetty dan menguji aplikasi web kami.

Seperti biasa, kode tersedia di GitHub.