सभी को नमस्कार!
और यहां हम
बन्स में लिप्त हैं और पाठ्यक्रम की दूसरी धारा
"जावा एंटरप्राइज डेवलपर" लॉन्च करते हैं। पाठ्यक्रम के स्थायी निर्माता और शिक्षक -
विटाली इवानोव ने इस विषय पर एक लेख भी लिखा है, जो हमें उम्मीद है, आपके लिए उपयोगी होगा :)
तो चलिए चलते हैं :)
यह लेख जावाईई कंज़िरेन्सी स्पेसिफिकेशन एपीआई (
जेएसआर 236 ) की खोज करता है, जो प्रबंधित संसाधनों की अवधारणा का उपयोग करके JavaEE कंटेनर में समानांतर कार्यों के लिए मानक को परिभाषित करता है। जावाईई के सातवें संस्करण की रिलीज ने मल्टीटास्किंग के साथ काम करने के लिए सुविधाजनक उपकरण और उपयोगिताओं के साथ डेवलपर को प्रदान करते हुए एंटरप्राइज कंटेनरों में समानांतर कार्यों को चलाने के लिए संभव बना दिया। उस क्षण तक, सभी मल्टीटास्किंग उपयोग किए गए एप्लिकेशन सर्वर के विशिष्ट कार्यान्वयन के लिए छोड़ दिया गया था, जो स्वतंत्र रूप से कार्यों के अनुकूलन पर निर्णय लेता है। इस सिद्धांत का उल्लंघन एंटरप्राइज़ अनुप्रयोगों की वास्तुकला के निर्माण में बुरा व्यवहार माना जाता था। नतीजतन, डेवलपर को नए धागे बनाने की सिफारिश नहीं की गई थी, और कभी-कभी कंटेनर स्तर पर ऐसा व्यवहार निषिद्ध था।
एंटरप्राइज़ बीन को थ्रेड्स को प्रबंधित करने का प्रयास नहीं करना चाहिए। एंटरप्राइज़ बीन को किसी थ्रेड को शुरू करने, रोकने, निलंबित करने या फिर से शुरू करने या किसी थ्रेड की प्राथमिकता या नाम बदलने का प्रयास नहीं करना चाहिए। एंटरप्राइज़ बीन को थ्रेड समूहों को प्रबंधित करने का प्रयास नहीं करना चाहिए।(लेखक का मुफ्त अनुवाद: EJBs को थ्रेड्स प्रबंधित करने की कोशिश नहीं करनी चाहिए, अर्थात्, उनके निष्पादन को रोकने, रोकने, थामने और बहाल करने की कोशिश करें, या प्राथमिकता बदलें या थ्रेड का नाम बदलें। इसके अलावा, EJB को थ्रेड समूहों को प्रबंधित करने का प्रयास नहीं करना चाहिए)।वास्तव में, जावा के कंटेनरों में अपने स्वयं के धागे के निर्माण पर रोक लगाने के लिए काफी समस्याग्रस्त है, हालांकि, इस दृष्टिकोण के साथ, कंटेनर की पृष्ठभूमि सेवाएं उनके काम की शुद्धता की गारंटी नहीं दे सकती हैं। उदाहरण के लिए, EJB विधि के पूरा होने पर लेनदेन को बंद करना संभावित रूप से गलत तरीके से काम कर सकता है यदि JavaSE से थ्रेड्स इनहेरिटर्स (या Runnable कार्यान्वयन) का उपयोग करके नए थ्रेड में कार्य शुरू किए गए थे। इसके अलावा, ExecutorService और ScheduledExecutorService जैसे एक्ज़ीक्यूटर API द्वारा आपूर्ति किए गए बुनियादी इंटरफ़ेस प्रकारों का उपयोग करके, जब एक्ज़ीक्यूटर्स क्लास के स्थिर तरीकों के माध्यम से बनाया जाता है, संभावित त्रुटियों को जन्म देगा और कंटेनर सेवाओं के निष्पादन को बाधित करेगा।
कार्यों के अतुल्यकालिक निष्पादन के लिए जावाईई विनिर्देश द्वारा सुझाए गए उपकरणों में से, डेवलपर को अतुल्यकालिक स्टेटलेस / स्टेटफुल ईजेबी और / या संदेश प्रेरित बीन्स का उपयोग करना था, जिनमें से क्षमताएं एक निश्चित सीमा तक कार्यों के लिए पर्याप्त हैं, और सबसे महत्वपूर्ण बात यह है कि प्रबंधन शुरू में एप्लिकेशन सर्वर द्वारा पूरी तरह से और पूरी तरह से नियंत्रित है। अर्थात् एक ईजेबी कंटेनर।
हालांकि, जैसा कि पहले उल्लेख किया गया है,
जेएसआर 236 के लिए धन्यवाद, कंटेनर-प्रबंधित संसाधन दिखाई दिए हैं जो
java.util.concurrent
के लिए
java.util.concurrent
पैकेज की क्षमताओं का विस्तार करते हुए मल्टीथ्रेडिंग और एसिंक्रोनस कार्य निष्पादन के लिए समर्थन को लागू करते हैं। JavaEE स्टैक के लिए, प्रबंधित संसाधन वर्ग
javax.enterprise.concurrent
पैकेज में स्थित हैं, और इन कक्षाओं की वस्तुओं तक पहुंच संसाधन इंजेक्शन के माध्यम से
@Resource
एनोटेशन, या JNDI संदर्भ (विशेष रूप से, InitialContext) के माध्यम से प्रदान की जाती है। इसी समय, JavaEE अनुप्रयोगों के अंदर बहु-थ्रेडेड वातावरण से परिचित Future / ScheduledFuture / CompletableFuture वस्तुओं का उपयोग करने की संभावनाओं को जोड़ा गया है।
इसलिए, पर्याप्त गीत हैं और चलो एक व्यावहारिक दृष्टिकोण से विनिर्देश द्वारा प्रदान किए गए प्रबंधित संसाधनों में से प्रत्येक पर एक करीब से नज़र डालते हैं, अर्थात् आवेदन कोड में एप्लिकेशन का उपयोग करने के संदर्भ में, साथ ही उदाहरण के लिए ग्लास 5 एप्लिकेशन सर्वर का उपयोग करके संसाधन कॉन्फ़िगरेशन के दृष्टिकोण से।
ठीक है, ManagedExecutorService वर्ग को सबसे पहले माना जाता था, जो (नाम से पहले से ही समझ) बॉक्स के बाहर परिचित JavaSE की क्षमताओं का विस्तार करता है और ExecutorService से बाहर निकलता है और JavaEE वातावरण में कार्यों के अतुल्यकालिक निष्पादन के लिए डिज़ाइन किया गया है।
ग्लासफ़िश एप्लिकेशन सर्वर के भीतर न केवल इस प्रकार के एक्सेलसॉर सेवा को कॉन्फ़िगर करने के लिए, आपको domain.xml कॉन्फ़िगरेशन फ़ाइल का उल्लेख करना चाहिए, जिसका स्थान $ {GLASSFISH_HOME} / डोमेन / <domainname> / config निर्देशिका द्वारा निर्धारित किया जाता है। इस फ़ाइल का एक टुकड़ा नीचे प्रस्तुत किया गया है:
<domain application-root="${com.sun.aas.instanceRoot}/applications" version="25" log-root="${com.sun.aas.instanceRoot}/logs"> <resources> <context-service object-type="system-all" jndi-name="concurrent/__defaultContextService" /> <managed-executor-service object-type="system-all" jndi-name="concurrent/__defaultManagedExecutorService" /> <managed-scheduled-executor-service object-type="system-all" jndi-name="concurrent/__defaultManagedScheduledExecutorService" /> <managed-thread-factory object-type="system-all" jndi-name="concurrent/__defaultManagedThreadFactory" /> </resources> <servers> <server config-ref="server-config" name="server"> <resource-ref ref="concurrent/__defaultContextService" /> <resource-ref ref="concurrent/__defaultManagedExecutorService" /> <resource-ref ref="concurrent/__defaultManagedScheduledExecutorService" /> <resource-ref ref="concurrent/__defaultManagedThreadFactory" /> </server> </servers> </domain>
ग्लासफिश 5 व्यवस्थापक पैनल के इंटरफ़ेस में जा रहे हैं, कॉन्फ़िगर कर रहे हैं
ManagedExecutorService निम्नानुसार है:

यह खंड एक ही प्रकार के नए संसाधनों के निर्माण, मौजूदा संसाधनों के प्रबंधन, विलोपन के साथ-साथ लॉकिंग और अनलॉकिंग की अनुमति देता है।
ग्लासफ़िश में कंसोल प्रशासन के प्रशंसकों के लिए, एक शक्तिशाली असादमिन उपयोगिता प्रस्तुत की जाती है, इसमें
create-managed-executor-service
एग्ज़ीक्यूटिव
create-managed-executor-service
कमांड का उपयोग करके, आप नए ManagedExecutorService संसाधन बना सकते हैं:

एप्लिकेशन कोड में, ManagedExecutorService द्वारा बनाई गई ऑब्जेक्ट का संदर्भ प्राप्त करने के लिए संसाधन इंजेक्शन का उपयोग करना अधिक सुविधाजनक है, लेकिन आप जेएनडीआई टूल का उपयोग भी कर सकते हैं, जैसा कि नीचे दिखाया गया है:
@Resource(lookup = "concurrent/OtusExecutorService") ManagedExecutorService executor; InitialContext context = new InitialContext(); ManagedExecutorService managedExecutorServiceWithContext = (ManagedExecutorService) context.lookup( "concurrent/OtusExecutorService");
मैं इस तथ्य पर पाठक का ध्यान आकर्षित करना चाहूंगा कि लुकअप पैरामीटर
@Resource
एनोटेशन के लिए वैकल्पिक है, और यदि इसे एप्लिकेशन कोड में डेवलपर द्वारा परिभाषित नहीं किया गया है, तो कंटेनर डिफ़ॉल्ट संसाधनों को उनके
__default
में
__default
उपसर्ग के साथ
__default
। इस मामले में, डेवलपर के लिए, कोड और भी संक्षिप्त हो जाता है:
@Resource ManagedExecutorService executor;
इस ऑब्जेक्ट का संदर्भ प्राप्त करने के बाद,
execute()
और
submit()
विधियों का उपयोग करके, आप कंटेनर के अंदर रननेबल या कॉल करने योग्य इंटरफ़ेस को लागू करने वाले कार्यों को चला सकते हैं।
एक उदाहरण की ओर मुड़ते हुए, मैं यह नोट करना चाहूंगा कि विभिन्न प्रकार के संभावित मामलों में, सबसे दिलचस्प एक वितरित जावा पर्यावरण में किए गए कार्य हैं और जिसमें बहु-थ्रेडेड वातावरण में लेन-देन का समर्थन प्रदान करना महत्वपूर्ण है। जैसा कि आप जानते हैं, JavaEE ने JTA (जावा ट्रांजैक्शन एपीआई) विनिर्देशन विकसित किया है, जो आपको लेनदेन की सीमाओं को स्पष्ट रूप से
begin()
विधि से
begin()
करने और
commit()
विधियों, परिवर्तनों को करने, या
rollback()
साथ शुरू करने की अनुमति देता है, जो किए गए कार्यों को वापस करता है।
एक उदाहरण कार्य पर विचार करें जो उपयोगकर्ता लेनदेन में सूचकांक द्वारा एक सौ वस्तुओं की सूची से एक संदेश लौटाता है:
public class TransactionSupportCallableTask implements Callable<String> { private int messageIndex; public TransactionSupportCallableTask(int messageId) { this. messageIndex = messageId; } public String call() { UserTransaction tx = lookupUserTransaction(); String message = null; try { tx.begin(); message = getMessage(messageIndex); tx.commit(); } catch (Exception e) { e.printStackTrace(); try { tx.rollback(); } catch (Exception e1) { e1.printStackTrace(); } } return message; } private void getMessage(int index) { … } private UserTransaction lookupUserTransaction () { … } }
सर्वलेट के लिए कोड जो सूची से संदेश को यादृच्छिक रूप से चयनित सूचकांक पर प्रदर्शित करता है:
@WebServlet("/task") public class ManagedExecutorServiceServlet extends HttpServlet { @Resource(lookup = "concurrent/OtusExecutorService") ManagedExecutorService executor; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Future<String> futureResult = executor.submit(new TransactionSupportCallableTask(Random.nextInt(100))); while (!futureResult.isDone()) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } try { response.getWriter().write("Callable task has received message with following content '" + futureResult.get() + "'"); } catch(Exception e) { e.printStackTrace(); } } }
माना जाने वाला अगला संसाधन ManagedScheduledExecutorService है, जिसका मुख्य उद्देश्य नियमित अंतराल पर दोहराए जाने वाले कार्यों की योजना बनाना या विलंबित निष्पादन की आवश्यकता है।

GlassFish व्यवस्थापक कंसोल के माध्यम से इस संसाधन को कॉन्फ़िगर करने के दृष्टिकोण से, पिछले प्रकार की तुलना में कोई विशेष परिवर्तन नहीं पाए गए थे:

ManagedScheduledExecutorService टाइप करने के लिए जल्दी से एक संसाधन बनाने के लिए,
asadmin
create-managed-scheduled-executor-service
आदेश है

एप्लिकेशन कोड में, हम अभी भी संसाधन इंजेक्शन का उपयोग करते हैं:
@Resource(lookup = "concurrent/OtusScheduledExecutorService") ManagedScheduledExecutorService scheduledExecutor;
इस प्रकार के ExecutorService के कार्यों को निष्पादित करने के मुख्य तरीके
schedule()
, जो इनपुट के रूप में रननेबल या कॉल करने योग्य प्रकार के कार्यों को प्राप्त करते हैं, और शेड्यूल.एफ़ फ़ेडरेट (
scheduleAtFixedRate()
, जो अतिरिक्त रूप से कार्य में प्रारंभिक देरी को निर्धारित करता है और दोहराव अंतराल (सेकंड, मिनट, आदि) में सेट करता है। ) ..
पिछला मामला इस प्रकार लिखा जा सकता है:
@WebServlet("/scheduledTask") public class ManagedScheduledExecutorServiceServlet extends HttpServlet { @Resource(lookup = "concurrent/OtusScheduledExecutorService") ManagedScheduledExecutorService scheduledExecutor; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ScheduledFuture<String> futureResult = scheduledExecutor.schedule( new TransactionSupportCallableTask(Random.nextInt(100)), 5, TimeUnit.SECONDS); while (!futureResult.isDone()) { try { Thread.sleep(50);
इसके अलावा, Enterpise वातावरण के लिए कॉनएरेबिलिटी एपीआई नियंत्रित प्रवाह बनाने की क्षमता प्रदान करता है। इन कार्यों के लिए, आपको एक प्रबंधित थ्रेड फैक्ट्री की क्षमताओं का उपयोग करना चाहिए जो उसी नाम के ManagedThreadFactory वर्ग के माध्यम से अपनी कार्यक्षमता को लागू करता है और JNDI सेवा के माध्यम से भी एक्सेस किया जाता है:
@Resource ManagedThreadFactory factory;
ग्लासफिश कंसोल के लिए प्रशासन की खिड़की "पुराने जमाने" लगती है:

प्रबंधित थ्रेड फ़ैक्टरी का उपयोग करना, न केवल कंटेनर को फ्लो कंट्रोल तंत्र के साथ प्रदान करना संभव हो जाता है, बल्कि उत्पन्न थ्रेड्स के गुणों को इनिशियलाइज़ करने के लिए भी होता है: सेट किए गए नाम और प्राथमिकता दें, जो कि भविष्य में समस्याओं की खोज को बहुत आसान कर सकते हैं जब थ्रेड को पहले से नामित थ्रेड्स के निष्पादन क्रम का आसानी से पता लगाकर।
हमारे मामले में, हम उस स्ट्रीम के वर्ग को परिभाषित करते हैं जो उस दोस्त के बारे में जानकारी प्रदर्शित करता है जिसके साथ यह कार्य सांत्वना से जुड़ा हुआ है:
public class SimpleThreadTask implements Runnable { private String friend; public SimpleThreadTask(String friend){ this.friend = friend; } @Override public void run() { System.out.println("Hello, " + friend); } }
सर्वलेट को थ्रेड प्रारंभ करें और इसे आउटपुट पर रिपोर्ट करें:
@WebServlet("/thread") public class ManagedThreadFactoryServlet extends HttpServlet { @Resource ManagedThreadFactory factory; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Thread thread = factory.newThread(new SimpleThreadTask("Otus")); thread.setName("ManagedThreadFromPool"); thread.setPriority(7); thread.start(); response.getWriter().write("Custom thread has been running."); } }
मल्टीथ्रेडिंग - प्रसंग सेवाओं के क्षेत्र में JavaEE की अंतिम विशेषता की ओर मुड़ते हुए, यह ध्यान दिया जाना चाहिए कि ये सेवाएं गतिशील संदर्भपरक प्रॉक्सी ऑब्जेक्ट बनाती हैं। हम सभी JavaSE (
java.lang.reflect.Proxy
) से गतिशील भविष्यवाणियों की क्षमताओं से परिचित हैं, जो आपको आवश्यक इंटरफेस का एक गतिशील कार्यान्वयन उत्पन्न करने की अनुमति देते हैं, जिनकी क्षमताओं का उपयोग डेटाबेस कनेक्शन और लेनदेन प्रबंधन बनाने के लिए सक्रिय रूप से किया जाता है, सभी प्रकार के एओपी इंटरसेप्टर, आदि के लिए उपयोग किया जाता है। इसके अलावा, JavaEE संदर्भ सेवाओं के माध्यम से बनाई गई भविष्यवाणियों के लिए, यह माना जाता है कि वे एक सामान्य JNDI संदर्भ, सुरक्षा संदर्भ और कंटेनर वर्ग के ढांचे के भीतर काम कर सकते हैं।
सेवा से कनेक्ट करने के लिए, बस कोड का उपयोग करें:
@Resource ContextService service;
इस संसाधन को प्रशासित और कॉन्फ़िगर करने के दृष्टिकोण से, सब कुछ बेहद परिचित है और पहले से ही विचार किए गए प्रकारों के समान है:

नीचे एक धागे का एक उदाहरण है जो एक कंटेनर के संदर्भ में एक प्रॉक्सी कार्य शुरू करता है:
public class SampleProxyTask implements Runnable { @Override public void run() {
सांकेतिक परदे के पीछे के लिए स्टेटलेस EJB बीन:
@Stateless public class ContextServiceBean { @Resource ContextService service; @Resource ManagedExecutorService executor; public void perform(Runnable task) { Runnable proxy = service.createContextualProxy(task, Runnable.class); executor.submit(proxy); } }
और अंत में, कार्य निष्पादित करने वाले सर्वलेट के लिए कोड:
@WebServlet("/context") public class ContextServiceServlet extends HttpServlet { @Inject ContextServiceBean contextServiceBean; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { contextServiceBean.perform(new SampleProxyTask()); } }
यह वास्तव में एक बहु-थ्रेडेड वातावरण में काम करने के लिए JavaEE डेवलपर की क्षमताओं को समाप्त करता है। उनके लिए धन्यवाद, कंटेनर में होने वाली सभी प्रक्रियाएं और सेवाएं सर्वर के सख्त नियंत्रण में होंगी, उनके काम का समन्वय और सामान्य निष्पादन आदेश का उल्लंघन नहीं होगा। एंटरप्राइज डेवलपर के लक्ष्यों के लिए, ये क्षमताएं अक्सर पर्याप्त होती हैं और आठवें संस्करण में यह एपीआई नहीं बदला है।
अंत
हमेशा की तरह, हम प्रश्नों और टिप्पणियों की प्रतीक्षा कर रहे हैं और
एक खुले सबक के लिए
विटाली की जांच करना सुनिश्चित करें, जहां वह प्रश्न पूछ सकते हैं और विषय "सीडीआई इन एक्शन" को सुन / सुन सकते हैं