Məzmuna keçLogo

Command Palette

Search for a command to run...

Servlet və Embedded Jetty — Arxa Planda Baş Verənlər

Dərc olundu
8 apr 2025
Servlet və Embedded Jetty — Arxa Planda Baş Verənlər

Giriş

Java SE biliklərini möhkəmləndirdikdən sonra backend dünyasına Servlet və ardından Spring/Spring Boot ilə addımlamaq çox məntiqli bir yoldur.

Servlet API-siniJetty kimi Servlet Konteynerlərinin iş prinsipini başa düşmək, Spring Boot-un bəzən "sehrli" görünən bir çox davranışının arxasındakı təməlləri qavramağa kömək edəcək.

Bu məqalədə, bir backend developer olaraq arxa planda baş verən proseslərə fokuslanacağıq.


Əsas Anlayışlar: Servlet və Servlet Konteyneri

Servlet

  • HTTP protokolu üzərindən gələn istəklərə (requests) cavab (response) vermək üçün dizayn edilmiş bir Java sinfidir.
  • Dinamik veb məzmun yaratmaq üçün istifadə olunur.
  • javax.servlet.Servlet interfeysini və ya javax.servlet.http.HttpServlet abstrakt sinfini implementasiya edir.

Servlet Konteyneri (Web Konteyner/Web Server)

  • Servletlərin həyat dövrünü (lifecycle) idarə edən proqram təminatıdır.
  • HTTP istəklərini qəbul edib müvafiq Servlet-ə yönləndirir.
  • Şəbəkə əlaqəsi, thread idarəçiliyi və digər aşağı səviyyəli işləri həll edir.
  • Jetty, Tomcat, Undertow kimi nümunələr var. Spring Boot default olaraq Tomcat ilə gəlir, lakin JettyUndertow da konfiqurasiya edilə bilər.

Jetty

Jetty, Eclipse Foundation tərəfindən hazırlanmış açıq mənbəli bir veb server və Servlet konteyneridir.

Xüsusilə daxili sistemlər və mikroservis arxitekturalarında populyardır:

  • Yüngül və sürətli: Aşağı yaddaş istifadəsi və sürətli start-up.
  • Embeddable: Java tətbiqinə daxil edilə bilər (main() metodu ilə başlatmaq olar).
  • Çevik və genişləndiriləbilən: Modulları istəyə görə əlavə/sil.
  • Asinxron dəstəyi: Servlet 3.0+, WebSocket, NIO dəstəyi mövcuddur.

Request/Response Axışı

Listening

  • Jetty başladıqda konfiqurasiya olunmuş portu (məs: 8080) dinləməyə başlayır.
  • ServerConnector komponenti TCP soketini açır.

Connection Acceptance

  • Klient bağlantı istəyir → ServerConnector bağlantını qəbul edir.

Thread Allocation

  • Jetty Thread Pool (məs: QueuedThreadPool) istifadə edir.
  • İstək üçün boş bir thread təyin edilir və iş bitdikdən sonra geri qaytarılır.

Data Reading & HTTP Parsing

  • TCP soketindən xam HTTP məlumatı oxunur.
  • Jetty-nin HTTP Parser komponenti bu məlumatı method, URL, headers, body kimi hissələrə ayırır.

Request və Response Obyektləri

  • Jetty HttpServletRequestHttpServletResponse obyektlərini yaradır.
  • request → istək haqqında bütün məlumat
  • response → cavabın qurulması üçün istifadə olunur

Handler Chain & Routing

Jetty-də gələn istəklər Handler zəncirindən keçir:

  • ServletContextHandler və ya WebAppContext → URL ilə Servlet-i eşləşdirir.

Eşləşdirmə aşağıdakı yollarla təyin edilə bilər:

  • web.xml – XML faylı ilə klassik konfiqurasiya
  • Annotations@WebServlet("/path") şəklində annotasiyalar

Servlet Lifecycle – init()

  • Servlet ilk dəfə çağırıldıqda:
    • Yüklənir və obyekti yaradılır.
    • init(ServletConfig) metodu yalnız bir dəfə çağırılır.
    • Servlet-ə konfiqurasiya və ServletContext ötürülür.

İstəyin emalı – service()

  • Jetty service(request, response) metodunu çağırır.

Əgər HttpServlet sinfi istifadə edilirsə:

  • service() → HTTP metoduna uyğun olaraq doGet(), doPost(), doPut() və s. metodları çağırır.

Tipik doGet() və ya doPost() məntiqi

  • request.getParameter(), getHeader(), getInputStream() ilə məlumatları alırsan.
  • İş məntiqi icra olunur (DB sorğusu, API çağırışı və s.).
  • response obyektinə:
    • setStatus()
    • setContentType()
    • setHeader()
    • getWriter().println() ilə cavab yazılır.

Response Commit & Sending

  • Servlet service() metodunu bitirdikdə:
    • Jetty responsedakı məlumatları HTTP formatında klientə göndərir.
    • Commit baş verdikdə header-lar göndərilir və dəyişdirilə bilməz.

Thread Release

  • Thread hovuzuna geri qaytarılır və növbəti istək üçün hazır olur.

Connection Close / Keep-Alive

  • Connection: keep-alive varsa, bağlantı saxlanılır.
  • Əks halda, TCP bağlantısı bağlanır.

Jetty-nin Thread Modeli: Paralel İşləmə

Thread Hovuzu (Thread Pool)

  • Jetty performans üçün QueuedThreadPool istifadə edir.

Məqsəd

  • Hər istək üçün yeni thread yaratmaq əvəzinə, mövcud threadlər təkrar istifadə olunur.

İşləmə Prinsipi

  • İstək gəldikdə hovuzdan thread götürülür.
  • İş tamamlandıqdan sonra geri qaytarılır.
  • Bütün threadlər məşğuldursa, istəklər queueya düşür.

Potensial Problem: Pool Exhaustion

  • Uzun sürən çox sayda istək zamanı:
    • Thread-lər dolur
    • Növbə böyüyür
    • Gecikmələr yaranır

➡️ Həll: Hovuz ölçüsünü konfiqurasiya etmək mümkündür.


Real case Code Nümunə

servlet/SalamServlet.java
// @WebServlet("/salam") // <<<=== ANNOTASİYA müasir üsuldur amma onu etmədik
public class SalamServlet extends HttpServlet { 

    // Servlet ilk yükləndikdə yalnız bir dəfə çağırılır.
    @Override
    public void init() throws ServletException {
        System.out.println("SalamServlet başladılır (proqramatik qeydiyyat)...");
        super.init();
    }

    // Gələn HTTP GET istəklərini emal edir.
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {

        // 1. Request'dən məlumat oxu (məsələn, query parametri)
        String ad = request.getParameter("name");
        if (ad == null || ad.trim().isEmpty()) {
            ad = "Dünya"; // Default dəyər
        }

        // 2. Response'u hazırla
        response.setContentType("text/html; charset=UTF-8"); 
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();

        // 3. Cavabın gövdəsini (HTML) yarat
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Salam Embedded Jetty</title>");
        out.println("<style>body { font-family: sans-serif; }</style>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Salam, " + ad + "! (Embedded Jetty)</h1>");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
        out.println("<p>Server Vaxtı: " + LocalDateTime.now().format(formatter) + "</p>");
        out.println("<p>Servlet Yolu: " + request.getServletPath() + "</p>");
        // İstəyin tam URL-ni göstərək
        out.println("<p>İstək URI: " + request.getRequestURI() + "</p>");
        out.println("<p>Brauzeriniz (User-Agent): " + request.getHeader("User-Agent") + "</p>");
        out.println("</body>");
        out.println("</html>");

        System.out.println("'" + ad + "' üçün GET istəyi emal edildi (Embedded).");
    }

    // Gələn HTTP POST istəklərini emal edir
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         System.out.println("POST istəyi gəldi (Embedded), doGet'ə yönləndirilir...");
         doGet(request, response);
    }

    // Servlet konteyneri dayandırıldıqda və ya tətbiq durduqda çağırılır.
    @Override
    public void destroy() {
        System.out.println("SalamServlet dayandırılır (proqramatik qeydiyyat)...");
        super.destroy();
    }
}
EmbeddedJettyMain.java
public class EmbeddedJettyMain {

    public static void main(String[] args) throws Exception {
        // 1. Jetty Server obyektini yarat (port 8080-də dinləyəcək)
        Server server = new Server(8080); 
        System.out.println("Jetty server 8080 portunda başladılır...");

        // 2. Servlet Context Handler yarat (SESSIONS dəstəyi ilə)
        // Bu, veb tətbiqimizin əsas konteyneridir
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        // Context yolunu təyin et ( "/" kök yolu göstərir)
        context.setContextPath("/");
        // Yaradılan context handler-i serverə əlavə et
        server.setHandler(context);

        // 3. Servletləri Context Handler-ə əlavə et
        //    - SalamServlet-i yarat və ServletHolder ilə "paketlə"
        //    - "/salam/*" URL pattern-inə map et (yəni /salam və ya /salam/abc kimi yolları tutacaq)
        context.addServlet(new ServletHolder(new SalamServlet()), "/salam/*"); 
        System.out.println("SalamServlet '/salam/*' yolu üçün qeydiyyatdan keçirildi.");

        // Əlavə servletlər də eyni qayda ilə əlavə edilə bilər:
        // context.addServlet(new ServletHolder(new BaşqaServlet()), "/başqa/*");
        // context.addServlet(new ServletHolder(new AdminServlet()), "/admin/*");

        // 4. Serveri başlat
        server.start(); 
        System.out.println("Jetty server uğurla başladıldı!");
        System.out.println("Brauzerinizdə http://localhost:8080/salam və ya http://localhost:8080/salam?ad=SizinAdiniz yollarını yoxlayın.");

        // 5. Serverin işini bitirməsini gözlə (əsas thread-in dərhal çıxmasının qarşısını alır)
        server.join();
        System.out.println("Jetty server dayandırıldı.");
    }
}
Thanks for reading.