Вграден Jetty сървър в Java

1. Общ преглед

В тази статия ще разгледаме библиотеката на Jetty . Jetty предоставя уеб сървър, който може да работи като вграден контейнер и се интегрира лесно с библиотеката javax.servlet .

2. Зависимости на Maven

За да започнем, ще добавим зависимости Maven към библиотеките на jetty-server и jetty-servlet:

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

3. Стартиране на Jetty Server със Servlet

Стартирането на вградения контейнер на 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\"}"); } }

След това трябва да регистрираме класа BlockingServlet в обекта ServletHandler, като използваме метода addServletWithMapping () и стартираме сървъра:

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

Ако искаме да тестваме нашата логика на Servlet, трябва да стартираме нашия сървър, като използваме създадения по- рано клас JettyServer, който е обвивка на действителния екземпляр на Jetty сървър в тестовата настройка:

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

След като стартираме, ще изпратим тестова HTTP заявка до крайната точка / 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. Неблокиращи сървлети

Jetty има добра поддръжка за асинхронна обработка на заявки.

Да кажем, че разполагаме с огромен ресурс, който е интензивен по отношение на I / O, отнема много време, за да зареди блокирането на изпълняващата нишка за значително време. По-добре е тази нишка да може да бъде освободена, за да обработва междувременно други заявки, вместо да чака някакъв I / O ресурс.

За да осигурим такава логика с Jetty, можем да създадем сървлет, който ще използва класа AsyncContext, като извикаме метода startAsync () в HttpServletRequest. Този код няма да блокира изпълняващата нишка, но ще извърши операцията I / O в отделна нишка, връщайки резултата, когато е готов, използвайки метода 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(); } }); } }

Пишем ByteBuffer в OutputStream и след като целият буфер е написан, ние сигнализираме, че резултатът е готов да се върне на клиента чрез извикване на метода complete () .

След това трябва да добавим AsyncServlet като Jetty сървлет:

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

Вече можем да изпратим заявка до крайната точка / heavy / async - тази заявка ще бъде обработена от Jetty по асинхронен начин:

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

Когато нашето приложение обработва заявки по асинхронен начин, трябва изрично да конфигурираме пула от нишки. В следващия раздел ще конфигурираме Jetty да използва персонализиран пул от нишки.

5. Конфигурация на пристанището

Когато стартираме нашето уеб приложение в производство, бихме искали да настроим как сървърът на Jetty обработва заявките. Това се прави чрез дефиниране на пула от нишки и прилагането му към нашия Jetty сървър.

За целта имаме три конфигурационни настройки, които можем да зададем:

  • 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 и тествахме нашето уеб приложение.

Както винаги, кодът е достъпен в GitHub.