सर्वलेट्स अब भी क्यों डराते हैं, और इससे कैसे निपटें?
\n\nअगर आपने कभी Stack Overflow पर "सर्वलेट्स कैसे काम करते हैं?" सवाल का जवाब ढूंढा है, तो आपने शायद वह famous थ्रेड देखा होगा जिसे हज़ारों बार देखा गया है। वह सवाल जो बार-बार पूछा जाता है: "सर्वलेट के कितने इंस्टेंस बनते हैं? रिक्वेस्ट के बीच डेटा कैसे शेयर करें? और मेरा वेरिएबल पागलों की तरह क्यों व्यवहार कर रहा है?"
\n\nसच कहूं तो: सर्वलेट्स कोई rocket science नहीं हैं, लेकिन इनमें कई छिपे हुए खतरे हैं। खासकर जब बात आती है मल्टीथ्रेडिंग और शेयर्ड वेरिएबल्स की। इस लेख में हम सिर्फ डॉक्यूमेंटेशन नहीं दोहराएंगे। हम एक real-life उदाहरण लेंगे, उसे टुकड़ों में समझेंगे और दिखाएंगे कि गलतियों से कैसे बचें। चलिए शुरू करते हैं!
\n\nसर्वलेट मेमोरी में कैसे आता है: इंस्टेंसिएशन और लाइफ साइकिल
\n\nचलिए सबसे सरल से शुरू करते हैं: सर्वलेट के कितने इंस्टेंस बनते हैं? जवाब: एक। हाँ, आपने सही सुना। सर्वलेट कंटेनर (Tomcat, Jetty आदि) पूरे एप्लिकेशन के लिए प्रत्येक सर्वलेट का सिर्फ एक इंस्टेंस बनाता है। और यह इंस्टेंस तब तक जीवित रहता है जब तक एप्लिकेशन अनलोड न हो जाए।
\n\nयहाँ typical life cycle दिया गया है:
\n\n- \n
init()— सर्वलेट लोड होने पर एक बार कॉल होता है। यहाँ आप DB कनेक्शन, कॉन्फ़िगरेशन आदि initialize करते हैं। \n service()— हर incoming request के लिए कॉल होता है। यहीं पर प्रोसेसिंग होती है। \n destroy()— सर्वलेट अनलोड होने से पहले कॉल होता है। रिसोर्सेज़ को साफ करें। \n
मुख्य बात: service() (और इसके डेरिवेटिव doGet, doPost) हर request के लिए एक अलग thread में execute होता है। यानी एक ही सर्वलेट इंस्टेंस सैकड़ों requests को एक साथ प्रोसेस करता है। और यहीं से मज़ा शुरू होता है।
उदाहरण: एक सर्वलेट, कई threads
\n\n@WebServlet("/counter")\npublic class CounterServlet extends HttpServlet {\n private int counter = 0; // shared variable!\n\n @Override\n protected void doGet(HttpServletRequest req, HttpServletResponse resp) \n throws ServletException, IOException {\n counter++;\n resp.getWriter().write("Counter: " + counter);\n }\n}\n\nअगर आप यह कोड चलाते हैं और 10 parallel requests भेजते हैं, तो आपको 1 से 10 तक के क्रम में नंबर नहीं मिलेंगे। इसके बजाय आप कुछ ऐसा देखेंगे: 2, 5, 3, 8, 1... या counter कुछ वैल्यूज़ को छोड़ भी सकता है। क्यों? क्योंकि counter++ एक atomic operation नहीं है। दो threads एक ही वैल्यू पढ़ सकते हैं, उसे बढ़ा सकते हैं और वापस लिख सकते हैं, जिससे एक increment खो जाता है।
निष्कर्ष: सर्वलेट के instance fields shared variables हैं। ये सभी threads को दिखाई देते हैं। और अगर आप इन तक access को synchronize नहीं करते, तो race condition होगी।
\n\nसेशन: यूज़र्स को कैसे न मिलाएं
\n\nअब सोचिए: आप हर यूज़र के लिए unique डेटा स्टोर करना चाहते हैं (शॉपिंग कार्ट, लॉगिन, सेटिंग्स)। इसके लिए Java Servlets में HttpSession है। हर नए यूज़र के लिए एक सेशन बनता है और वह तब तक जीवित रहता है जब तक यूज़र ब्राउज़र बंद न करे या timeout न हो जाए।
\n\nसेशन शेयर्ड मेमोरी नहीं है। हर यूज़र को अपना खुद का सेशन इंस्टेंस मिलता है। लेकिन सेशन के अंदर आप कोई भी objects स्टोर कर सकते हैं, और वे सिर्फ उसी यूज़र के लिए उपलब्ध होंगे।
\n\nउदाहरण: सेशन के साथ काम करना
\n\n@WebServlet("/session-demo")\npublic class SessionServlet extends HttpServlet {\n @Override\n protected void doGet(HttpServletRequest req, HttpServletResponse resp) \n throws ServletException, IOException {\n HttpSession session = req.getSession();\n Integer visitCount = (Integer) session.getAttribute("visitCount");\n if (visitCount == null) {\n visitCount = 0;\n }\n visitCount++;\n session.setAttribute("visitCount", visitCount);\n resp.getWriter().write("आपने इस पेज को " + visitCount + " बार देखा है");\n }\n}\n\nयह कोड हर यूज़र के लिए अलग-अलग visit count रखेगा। कोई race condition नहीं, क्योंकि हर यूज़र की अपनी सेशन है।
\n\nServletContext बनाम HttpSession: कब क्या इस्तेमाल करें?
\n\nअब एक और important concept: ServletContext। यह पूरे एप्लिकेशन के लिए एक सिंगल ऑब्जेक्ट है। इसे सभी सर्वलेट्स और सभी यूज़र्स शेयर करते हैं। इसका उपयोग global settings, database connection pools, या ऐसे डेटा के लिए करें जो सभी यूज़र्स के लिए समान हो।
\n\nयाद रखें: ServletContext में स्टोर किया गया डेटा thread-safe होना चाहिए, क्योंकि कई threads एक साथ इसे access कर सकते हैं।
\n\nनिष्कर्ष: सर्वलेट्स को समझना आसान है
\n\nसर्वलेट्स को समझने के लिए बस तीन चीज़ें याद रखें:
\n\n- \n
- एक सर्वलेट = एक इंस्टेंस। सभी requests एक ही इंस्टेंस पर आती हैं। \n
- Instance fields = shared variables। इन्हें thread-safe बनाएं या इनका उपयोग न करें। \n
- HttpSession = per-user storage। यूज़र-विशिष्ट डेटा के लिए सेशन का उपयोग करें। \n
अब आप बिना किसी डर के सर्वलेट्स के साथ काम कर सकते हैं। हैप्पी कोडिंग!