Ingebouwde steigerserver in Java

1. Overzicht

In dit artikel zullen we kijken naar de Steiger bibliotheek. Jetty biedt een webserver die kan worden uitgevoerd als een ingesloten container en gemakkelijk kan worden geïntegreerd met de javax.servlet bibliotheek.

2. Maven afhankelijkheden

Om te beginnen voegen we Maven-afhankelijkheden toe aan jetty-server en jetty-servlet-bibliotheken:

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

3. Start Jetty Server met Servlet

Het starten van de ingesloten Jetty-container is eenvoudig. We moeten een nieuwe instantiëren Server object en stel het in om te starten op een bepaalde poort:

openbare klasse JettyServer {privéserver-server; public void start () gooit uitzondering {server = nieuwe server (); ServerConnector connector = nieuwe ServerConnector (server); connector.setPort (8090); server.setConnectors (nieuwe connector [] {connector}); }

Laten we zeggen dat we een eindpunt willen maken dat reageert met de HTTP-statuscode 200 als alles goed gaat en een eenvoudige JSON-payload.

We maken een klasse die de extensie HttpServlet klasse om een ​​dergelijk verzoek te behandelen; deze klasse heeft een enkele thread en wordt geblokkeerd tot voltooiing:

openbare klasse BlockingServlet breidt HttpServlet {protected void doGet (HttpServletRequest-verzoek, HttpServletResponse-reactie) uit met ServletException, IOException {response.setContentType ("application / json"); response.setStatus (HttpServletResponse.SC_OK); response.getWriter (). println ("{\" status \ ": \" ok \ "}"); }}

Vervolgens moeten we het BlockingServlet klasse in de ServletHandler object met behulp van de addServletWithMapping () methode en start de server:

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

Als we onze Servlet-logica willen testen, moeten we onze server starten met behulp van het eerder gemaakte JettyServer klasse die een wrapper is van de daadwerkelijke Jetty-serverinstantie binnen de testopstelling:

@Before public void setup () gooit Uitzondering {jettyServer = nieuwe JettyServer (); jettyServer.start (); }

Eenmaal gestart, sturen we een test-HTTP-verzoek naar het /toestand eindpunt:

String url = "// localhost: 8090 / status"; HttpClient-client = HttpClientBuilder.create (). Build (); HttpGet request = nieuwe HttpGet (url); HttpResponse response = client.execute (verzoek); assertThat (response.getStatusLine (). getStatusCode ()). isEqualTo (200);

4. Niet-blokkerende servlets

Jetty heeft goede ondersteuning voor asynchrone aanvraagverwerking.

Laten we zeggen dat we een enorme bron hebben die I / O-intens is en er lang over doet om te laden en de uitvoerende thread gedurende een aanzienlijke hoeveelheid tijd te blokkeren. Het is beter als die thread kan worden vrijgemaakt om in de tussentijd andere verzoeken af ​​te handelen, in plaats van te wachten op een I / O-bron.

Om dergelijke logica met Jetty te bieden, kunnen we een servlet maken die de AsyncContext klasse door de startAsync () methode op de HttpServletRequest. Deze code blokkeert de uitvoerende thread niet, maar voert de I / O-bewerking uit in een afzonderlijke thread en retourneert het resultaat wanneer u klaar bent met het AsyncContext.complete () methode:

openbare klasse AsyncServlet breidt HttpServlet uit {privé statische String HEAVY_RESOURCE = "Dit is een zware bron die op een asynchrone manier wordt bediend"; beschermde ongeldige doGet (HttpServletRequest-verzoek, HttpServletResponse-antwoord) gooit ServletException, IOException {ByteBuffer-inhoud = ByteBuffer.wrap (HEAVY_RESOURCE.getBytes (StandardCharsets.UTF_8)); AsyncContext async = request.startAsync (); ServletOutputStream uit = response.getOutputStream (); out.setWriteListener (nieuwe WriteListener () {@Override public void onWritePossible () gooit 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 ();}}) ; }}

We schrijven het ByteBuffer naar de OutputStream, en zodra de hele buffer is geschreven, geven we aan dat het resultaat klaar is om terug te keren naar de client door de compleet() methode.

Vervolgens moeten we het AsyncServlet als een Jetty-servlet-mapping:

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

We kunnen nu een verzoek sturen naar het / heavy / async eindpunt - dat verzoek wordt op een asynchrone manier afgehandeld door de steiger:

String url = "// localhost: 8090 / heavy / async"; HttpClient-client = HttpClientBuilder.create (). Build (); HttpGet request = nieuwe HttpGet (url); HttpResponse response = client.execute (verzoek); assertThat (response.getStatusLine (). getStatusCode ()) .isEqualTo (200); String responseContent = IOUtils.toString (r esponse.getEntity (). GetContent (), StandardCharsets.UTF_8); assertThat (responseContent) .isEqualTo ("Dit is een zware bron die asynchroon wordt bediend");

Wanneer onze applicatie verzoeken op een asynchrone manier afhandelt, moeten we de threadpool expliciet configureren. In de volgende sectie zullen we configureren Steiger om een ​​aangepaste threadpool te gebruiken.

5. Steigerconfiguratie

Wanneer we onze webapplicatie in productie draaien, willen we misschien afstemmen hoe de Jetty-server verzoeken verwerkt. Dit wordt gedaan door een threadpool te definiëren en deze toe te passen op onze Jetty-server.

Om dit te doen, hebben we drie configuratie-instellingen die we kunnen instellen:

  • maxThreads - Om het maximale aantal threads op te geven dat Jetty kan maken en gebruiken in de pool
  • minThreads - Om het aanvankelijke aantal threads in de pool in te stellen die Jetty zal gebruiken
  • idleTimeout - Deze waarde in milliseconden bepaalt hoe lang een thread inactief kan zijn voordat deze wordt gestopt en verwijderd uit de threadpool. Het aantal resterende threads in de pool zal nooit onder de minThreads instelling

Hiermee kunnen we het embedded Steiger server programmatisch door de geconfigureerde threadpool door te geven aan de Server constructeur:

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

Als we vervolgens onze server starten, gebruikt deze threads uit een specifieke threadpool.

6. Conclusie

In deze korte tutorial hebben we gezien hoe we embedded servers kunnen integreren met Jetty en hebben we onze webapplicatie getest.

Zoals altijd is de code beschikbaar op GitHub.