Pelayan Jeti Tertanam di Java

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat perpustakaan Jetty . Jetty menyediakan pelayan web yang dapat berfungsi sebagai wadah terbenam dan dapat disatukan dengan mudah dengan perpustakaan javax.servlet .

2. Pergantungan Maven

Untuk memulakan, kami akan menambahkan pergantungan Maven ke perpustakaan jetty-server dan jetty-servlet:

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

3. Memulakan Pelayan Jeti Dengan Servlet

Memulakan bekas tertanam Jeti adalah mudah. Kita perlu membuat objek Server baru dan menetapkannya untuk memulakan 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}); }

Katakan bahawa kita ingin membuat titik akhir yang akan bertindak balas dengan kod status HTTP 200 jika semuanya berjalan lancar dan muatan JSON yang sederhana.

Kami akan membuat kelas yang memperluas kelas HttpServlet untuk menangani permintaan tersebut; kelas ini akan diberi urutan tunggal dan blok sehingga 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\"}"); } }

Seterusnya, kita perlu mendaftarkan kelas BlockingServlet dalam objek ServletHandler dengan menggunakan kaedah addServletWithMapping () dan memulakan pelayan:

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

Sekiranya kami ingin menguji logik Servlet kami, kami perlu memulakan pelayan kami dengan menggunakan kelas JettyServer yang telah dibuat sebelumnya yang merupakan pembungkus contoh pelayan Jetty yang sebenarnya dalam persediaan ujian:

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

Setelah dimulakan, kami akan menghantar permintaan HTTP ujian 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 Tidak Menyekat

Jeti mempunyai sokongan yang baik untuk pemprosesan permintaan tidak segerak.

Katakan bahawa kita mempunyai sumber yang sangat besar iaitu I / O intens memerlukan masa yang lama untuk memuatkan penyekat utas pelaksanaan untuk sejumlah besar masa. Lebih baik jika utas itu dapat dibebaskan untuk menangani permintaan lain sementara itu, daripada menunggu beberapa sumber I / O.

Untuk memberikan logik seperti itu dengan Jetty, kita dapat membuat servlet yang akan menggunakan kelas AsyncContext dengan memanggil kaedah startAsync () pada HttpServletRequest. Kod ini tidak akan menyekat utas pelaksanaan tetapi akan melakukan operasi I / O dalam utas berasingan yang mengembalikan hasilnya apabila siap menggunakan kaedah 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 keseluruhan buffer ditulis, kami memberi isyarat bahawa hasilnya siap untuk dikembalikan kepada klien dengan menggunakan kaedah lengkap () .

Seterusnya, kita perlu menambahkan AsyncServlet sebagai pemetaan servlet Jetty:

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

Kami sekarang boleh menghantar permintaan ke titik akhir / heavy / async - permintaan itu akan ditangani oleh Jeti dengan cara tidak segerak:

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

Semasa aplikasi kami menangani permintaan dengan cara yang tidak segerak, kami harus mengkonfigurasi kumpulan utas dengan jelas. Di bahagian seterusnya, kami akan mengkonfigurasi Jetty untuk menggunakan kumpulan utas khusus.

5. Konfigurasi Jeti

Semasa kami menjalankan aplikasi web kami untuk pengeluaran, kami mungkin ingin menyesuaikan bagaimana pelayan Jetty memproses permintaan. Ini dilakukan dengan menentukan thread thread dan menerapkannya ke pelayan Jetty kami.

Untuk melakukan ini, kami mempunyai tiga tetapan konfigurasi yang dapat kami tetapkan:

  • maxThreads - Untuk menentukan bilangan utas maksimum yang boleh dibuat dan digunakan oleh Jetty di kolam
  • minThreads - Untuk menetapkan bilangan utas awal di kolam yang akan digunakan Jetty
  • idleTimeout - Nilai ini dalam milisaat menentukan berapa lama utas boleh terbiar sebelum dihentikan dan dikeluarkan dari kumpulan utas. Bilangan utas yang tersisa di kolam tidak akan pernah berada di bawah tetapan minThreads

Dengan ini, kita dapat mengkonfigurasi pelayan Jetty terbenam secara terprogram dengan meneruskan kumpulan utas yang dikonfigurasi ke pelayan Server :

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

Kemudian, apabila kita memulakan pelayan kita, ia akan menggunakan utas dari kumpulan utas tertentu.

6. Kesimpulannya

Dalam tutorial ringkas ini, kami melihat cara mengintegrasikan pelayan terbenam dengan Jetty dan menguji aplikasi web kami.

Seperti biasa, kodnya tersedia di GitHub.