Servlet Lifecycle: init(), service(), destroy() සහ HTTP Request Handling SC Guide

Servlet Lifecycle: init(), service(), destroy() සහ HTTP Request Handling SC Guide

හෙලෝ යාලුවනේ! කොහොමද ඉතින්? අද අපි කතා කරමු Java Web Development වලදී ගොඩක් වැදගත් වෙන, හැබැයි සමහරුන්ට අවුල් වෙන්න පුළුවන් මාතෘකාවක් ගැන – ඒ තමයි Servlet Lifecycle එකයි, HTTP Request Handling එකයි.

මචං, අපි කෝකටත් කලින් පොඩ්ඩක් හිතලා බලමු Web Application එකක් කියන්නේ මොකක්ද කියලා. සරලවම කිව්වොත්, ඔයා Facebook එකට යනවා, Google එකේ search කරනවා, මේ ඔක්කොම Web Application. මේවා වැඩ කරන්නේ කොහොමද? ඔයාගේ browser එකෙන් server එකට request එකක් යනවා, server එක process කරලා response එකක් එවනවා. මේ process එකේදී, Java වලින් Web Application හදනකොට Servlets කියන දේ තමයි ගොඩක් වෙලාවට මේ request handling එකට යොදාගන්නේ.

Servlet කියන්නේ Java program එකක්. මේක අපේ Web Server (උදාහරණයක් විදියට Apache Tomcat, Jetty වගේ ඒවා) එකේදී වැඩ කරනවා. මේ Servlets වල ජීවිත චක්‍රයක් (Lifecycle) තියෙනවා, ඒ වගේම Client එකෙන් එන HTTP requests හසුරුවන්න විශේෂ ක්‍රම තියෙනවා. මේ ටික හරියට තේරුම් ගත්තොත්, ඔයාට Java Web Development වලදී ගොඩක් දුර යන්න පුළුවන්. එහෙනම්, අපි පටන් ගමුද?

Servlet කියන්නේ මොනවද බං?

හරි, මුලින්ම බලමු Servlet එකක් කියන්නේ මොකක්ද කියලා. Servlet කියන්නේ Java API (Application Programming Interface) එකක්. මේකේ class එකක් තමයි javax.servlet.Servlet කියන්නේ. මේවා නිර්මාණය කරලා තියෙන්නේ web server extensions විදියට වැඩ කරන්න. සරලවම කිව්වොත්, Client browser එකකින් එන requests අරගෙන, ඒවා process කරලා, ආපහු Client එකට response එකක් යවන්න තමයි Servlets පාවිච්චි කරන්නේ.

අපි හදන Servlet එකක් සාමාන්‍යයෙන් HttpServlet කියන Abstract Class එක extend කරනවා. HttpServlet කියන්නේ GenericServlet කියන class එක extend කරපු class එකක්. GenericServlet කියන්නේ Servlet interface එක implement කරපු එකක්. මේ HttpServlet එක තමයි HTTP protocol එකට අදාළ requests (GET, POST, PUT, DELETE, etc.) handle කරන්න උදව් කරන්නේ.

Web server එකක් (Servlet Container එකක්) තමයි මේ Servlet instances හසුරුවන්නේ. Server එක start වෙනකොට, requests එනකොට, server එක shutdown කරනකොට මේ Servlet instances කොහොමද හැසිරෙන්නේ කියන එක තීරණය වෙන්නේ ඒ Servlet Lifecycle එක අනුවයි.

Servlet Lifecycle එකේ මැජික් එක

Servlet එකක Lifecycle එක කියන්නේ ඒක නිර්මාණය වෙන මොහොතේ ඉඳන්, requests handle කරලා, මතකයෙන් ඉවත් වෙනකම් සිදුවන ක්‍රියාවලි මාලාව. මේක ප්‍රධාන methods තුනකින් සමන්විත වෙනවා:

  1. init() method එක
  2. service() method එක
  3. destroy() method එක

මේ methods තුනම javax.servlet.Servlet interface එකෙන් එන ඒවා. අපි මේවා එකින් එක බලමු.

init() method එක

init() method එක තමයි Servlet එකක ජීවිතයේ ආරම්භය. මේක run වෙන්නේ Servlet Container එක මුලින්ම Servlet එක load කරනකොට. මේක call වෙන්නේ එකම එක පාරයි. ඒ කියන්නේ, ඔයාගේ Servlet එක deploy කරලා, server එකට request එකක් ආවට පස්සේ හෝ server එක start වෙනකොට Servlet එක load වෙලා, init() method එක activate වෙනවා. ඒක පස්සේ ආපහු call වෙන්නේ නැහැ. හරියට ඔයාගේ ජීවිතේ උපත වගේ.

මේ method එක පාවිච්චි කරන්නේ Servlet එකට අවශ්‍ය එක වරක් කළ යුතු initialization (ආරම්භක සැකසුම්) ටික කරන්න. උදාහරණයක් විදියට, Database connection එකක් ඇති කරගන්න, configuration files load කරන්න වගේ දේවල් මේක ඇතුලේ කරන්න පුළුවන්.


public void init() throws ServletException {
    // Servlet එක initialize කරන code එක මෙතනට දාන්න
    System.out.println("Servlet initialize වෙනවා... Database connection එකක් හදනවා...");
}

service() method එක

service() method එක තමයි Servlet Lifecycle එකේ හදවත. Client එකකින් request එකක් ආවාම, init() method එක call කරලා ඉවර වුණාට පස්සේ, Servlet Container එක service() method එක call කරනවා. මේ method එකට ServletRequest object එකකුයි, ServletResponse object එකකුයි parameter විදියට එනවා.

ServletRequest object එකේ request එක ගැන තොරතුරු තියෙනවා (උදා: URL එක, parameters, headers, cookies). ServletResponse object එක පාවිච්චි කරන්නේ Client එකට response එකක් යවන්න. මේක තමයි request එකක් එන හැම වෙලාවෙම call වෙන්නේ. මේකේදී තමයි request එක HTTP GET ද, POST ද, PUT ද, DELETE ද කියලා බලලා අදාළ method එකට (doGet(), doPost() වගේ) request එක යොමු කරන්නේ.


public void service(ServletRequest request, ServletResponse response)
    throws ServletException, IOException {
    // මේක තමයි හැම request එකකටම call වෙන්නේ
    System.out.println("Request එකක් ආවා! Service method එක run වෙනවා.");
    // මේකෙන් තමයි doGet, doPost වගේ ඒවාට යොමු කරන්නේ
}

destroy() method එක

destroy() method එක තමයි Servlet එකක ජීවිතයේ අවසානය. මේක call වෙන්නේ Servlet Container එක Servlet එක memory එකෙන් අයින් කරන්න යනකොට. මේකත් init() වගේම එකම එක පාරයි call වෙන්නේ. සාමාන්‍යයෙන් මේක call වෙන්නේ server එක shutdown කරනකොට, හෝ Web Application එක undeploy කරනකොට.

මේ method එක පාවිච්චි කරන්නේ Servlet එකේදී open කරපු resources (Database connections, file handlers වගේ දේවල්) වහන්න. හරියට අපි වැඩ ඉවර වුණාම computer එක shutdown කරනවා වගේ වැඩක්. මේකෙන් resource leaks වළක්වා ගන්න පුළුවන්.


public void destroy() {
    // Servlet එක shutdown කරනකොට කරන වැඩ මෙතනට දාන්න
    System.out.println("Servlet එක destroy වෙනවා... Database connection වහනවා...");
}

HTTP Request Handling: doGet සහ doPost

අපි කලින් කිව්වා වගේ, HttpServlet class එක service() method එක override කරලා, HTTP request වර්ගය අනුව (GET, POST, PUT, DELETE) අදාළ method එකට request එක යොමු කරනවා. ඒ අතරින් බහුලවම පාවිච්චි කරන methods දෙක තමයි doGet() සහ doPost().

මේ methods දෙකටම HttpServletRequest object එකකුයි, HttpServletResponse object එකකුයි parameter විදියට ලැබෙනවා. මේවා ServletRequest සහ ServletResponse වල HTTP-specific subclasses.

doGet() method එක

doGet() method එක call වෙන්නේ Client එකෙන් HTTP GET request එකක් එව්වොත්. මේක සාමාන්‍යයෙන් පාවිච්චි කරන්නේ server එකෙන් data retrieve (ගෙන්වා ගැනීමට) කරන්න. උදාහරණයක් විදියට, වෙබ් page එකක් load කරනකොට, search engine එකක search කරනකොට, හෝ URL එකකට කෙලින්ම ගහලා යනකොට GET requests යනවා.

  • සරලයි, වේගවත්: Parameters URL එකේම (query string එකක් විදියට) යවන නිසා.
  • Bookmarking පුළුවන්: URL එක bookmark කරන්න පුළුවන්.
  • Idempotent: එකම request එක කීප වතාවක් යැව්වත් server එකේ තත්ත්වයේ වෙනසක් වෙන්නේ නැහැ. (දත්ත වෙනස් වීමක් වෙන්නේ නැහැ)
  • Security අඩුයි: Sensitive data (passwords වගේ) URL එකේ යවන්න සුදුසු නැහැ. URL එකේ ප්‍රමාණය සීමා සහිතයි.

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello") // web.xml නැතුව Servlet mapping කරන්න පුළුවන්
public class MyGetServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        
        response.setContentType("text/html"); // Response එකේ content type එක සකසනවා
        PrintWriter out = response.getWriter(); // Client එකට data යවන්න writer object එකක් ගන්නවා

        String name = request.getParameter("name"); // URL එකේ "name" parameter එක ගන්නවා
        if (name == null || name.isEmpty()) {
            name = "World";
        }

        out.println("<html>");
        out.println("<head><title>Hello Servlet</title></head>");
        out.println("<body>");
        out.println("<h1>Hello, " + name + "!</h1>");
        out.println("<p>This is a GET request example.</p>");
        out.println("</body>");
        out.println("</html>");
    }
}

මේ Servlet එක deploy කරලා, http://localhost:8080/YourAppName/hello?name=John වගේ URL එකකට ගියොත් "Hello, John!" කියලා output වෙයි. `name` parameter එක නැතුව ගියොත් "Hello, World!" කියලා එයි.

doPost() method එක

doPost() method එක call වෙන්නේ Client එකෙන් HTTP POST request එකක් එව්වොත්. මේක සාමාන්‍යයෙන් පාවිච්චි කරන්නේ server එකට data submit (යවන්න) කරන්න. උදාහරණයක් විදියට, login form එකක් submit කරනකොට, account එකක් create කරනකොට, හෝ database එකට data add කරනකොට POST requests යනවා.

  • Security වැඩියි: Data request body එකේ යවන නිසා URL එකේ පේන්නේ නැහැ. Sensitive data යවන්න සුදුසුයි.
  • ප්‍රමාණ සීමාවක් නැහැ: යවන්න පුළුවන් data ප්‍රමාණයට ලොකු සීමාවක් නැහැ.
  • Not Idempotent: එකම request එක කීප වතාවක් යැව්වොත් server එකේ තත්ත්වය වෙනස් වෙන්න පුළුවන්. (උදා: එකම form එක දෙපාරක් submit කළොත් data දෙපාරක් save වෙන්න පුළුවන්).
  • Bookmarking බැහැ: URL එක bookmark කරන්න බැහැ.

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/register")
public class MyPostServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        out.println("<html>");
        out.println("<head><title>Registration Result</title></head>");
        out.println("<body>");
        out.println("<h1>Registration Successful!</h1>");
        out.println("<p>Username: " + username + "</p>");
        out.println("<p>Password: " + password + " (Never display passwords like this in real apps!) </p>");
        out.println("</body>");
        out.println("</html>");
    }
}

මේ doPost Servlet එක පරීක්ෂා කරන්න HTML form එකක් හදාගන්න වෙනවා. උදාහරණයක් විදියට:


<!-- register.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Register</title>
</head>
<body>
    <h1>Register Here</h1>
    <form action="register" method="POST">
        <label for="username">Username:</label><br>
        <input type="text" id="username" name="username"><br><br>
        <label for="password">Password:</label><br>
        <input type="password" id="password" name="password"><br><br>
        <input type="submit" value="Register">
    </form>
</body>
</html>

මේ HTML file එක deploy කරලා, form එක submit කළාම MyPostServlet එකට data යවයි.

ප්‍රායෝගික උදාහරණයක්

අපි මේ ඔක්කොම එකට එකතු කරලා පොඩි Servlet එකක් හදමු, මේ methods කොහොමද එකට වැඩ කරන්නේ කියලා බලන්න.


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/lifecycle-demo")
public class LifecycleDemoServlet extends HttpServlet {

    // Constructor එක. මේක සාමාන්‍යයෙන් පාවිච්චි කරන්නේ නැහැ init() එක තියෙන නිසා
    public LifecycleDemoServlet() {
        super();
        System.out.println("1. Servlet Constructor: Servlet instance එක නිර්මාණය වුණා.");
    }

    // Servlet එක initialize වෙනකොට call වෙනවා (එක පාරයි)
    @Override
    public void init() throws ServletException {
        super.init();
        System.out.println("2. init() method: Servlet එක initialize වෙනවා. Configuration loaded.");
        // Database connection, external resources load කිරීම මෙතනදී කරන්න පුළුවන්
    }

    // හැම HTTP GET request එකකටම call වෙනවා
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        System.out.println("3. doGet() method: GET request එකක් ආවා.");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<h2>Hello from doGet()!</h2>");
        out.println("<p>You sent a GET request.</p>");
        out.println("<p>Parameter 'message': " + request.getParameter("message") + "</p>");
    }

    // හැම HTTP POST request එකකටම call වෙනවා
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("4. doPost() method: POST request එකක් ආවා.");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<h2>Hello from doPost()!</h2>");
        out.println("<p>You sent a POST request.</p>");
        out.println("<p>Parameter 'data': " + request.getParameter("data") + "</p>");
    }

    // Servlet Container එක Servlet එක memory එකෙන් අයින් කරනකොට call වෙනවා (එක පාරයි)
    @Override
    public void destroy() {
        super.destroy();
        System.out.println("5. destroy() method: Servlet එක destroy වෙනවා. Resources closed.");
        // Open කරපු resources close කිරීම මෙතනදී කරන්න පුළුවන්
    }

    // service() method එක override නොකළොත් HttpServlet එකේ service() එක call වෙනවා.
    // ඒකෙන් තමයි doGet/doPost වගේ method වලට request එක redirect කරන්නේ.
    // අපි මෙතනදී override කරන්නේ නැහැ, HttpServlet එකේ default behavior එක පාවිච්චි කරනවා.
}

මේ Servlet එක deploy කරලා, ඔයාගේ server console එක බැලුවොත්, ඔයාට මේ methods call වෙන පිළිවෙල පැහැදිලිව පේයි.

  1. Server එක start කරලා Servlet එක load වුණාම: Constructor සහ init() call වෙනවා.
  2. Browser එකෙන් http://localhost:8080/YourAppName/lifecycle-demo?message=hi වගේ URL එකකට ගියාම: doGet() call වෙනවා.
  3. POST request එකක් යැව්වොත් (HTML form එකක් හරහා): doPost() call වෙනවා.
  4. Server එක shutdown කරනකොට හෝ Web Application එක undeploy කරනකොට: destroy() call වෙනවා.

මෙතනදී වැදගත් දේ තමයි, service() method එක HttpServlet class එකේ implement කරලා තියෙන්නේ. ඒක තමයි HTTP method (GET, POST, etc.) අනුව අදාළ doGet(), doPost() වගේ methods වලට request එක යොමු කරන්නේ. ඒ නිසා අපි HttpServlet extend කරනකොට service() method එක override කරන්නේ නැතුව, doGet(), doPost() වගේ ඒවා override කරන එක තමයි සාමාන්‍යයෙන් කරන්නේ.

අවසාන වශයෙන්

ඉතින් යාලුවනේ, ඔන්න ඔය තමයි Servlet Lifecycle එකේයි, HTTP request handling එකේයි මූලිකම දේවල් ටික. මේ concepts ටික හොඳට තේරුම් ගත්තොත්, ඔයාට Java web applications හදනකොට ගොඩක් පැහැදිලිව වැඩ කරන්න පුළුවන්. විශේෂයෙන්ම, init(), service() (doGet/doPost හරහා), destroy() කියන methods වල කාර්යභාරය සහ ඒවා call වෙන පිළිවෙල මතක තියාගන්න එක ගොඩක් වැදගත්.

දැන් ඔයාලට පුළුවන් මේ උදාහරණ code ටික අරගෙන, ඔයාලගේම Servlet එකක් හදලා, Tomcat වගේ Servlet Container එකක deploy කරලා run කරලා බලන්න. console එකේ output එක බැලුවොත් මේ methods call වෙන පිළිවෙල හොඳට තේරෙයි.

මතක තියාගන්න, theory දැනගෙන විතරක් මදි, අතේ වැඩ කරන එක තමයි වැදගත්ම දේ. මේ ගැන තව මොනවා හරි දැනගන්න ඕනේ නම්, නැත්නම් මේකේ මොකක් හරි ගැටලුවක් තියෙනවා නම්, පහලින් comment එකක් දාගෙන යන්න. සෙට් වෙමු තව අලුත් article එකකින්!