2012-08-14 23 views
7

मैं जबकि प्रलेखन sayingotherwise के बावजूद, एक LDAP पूल इस संदर्भ पर close() बुला यह पूल पर लौटने के लिए प्रकट नहीं किया था कनेक्ट का उपयोग कर देखा। इस प्रकार जब मैं पूल से आइटम प्राप्त करने का प्रयास करता हूं, जब यह पहले से ही अपने अधिकतम आकार में होता है, तो यह लटकता है।क्यों DirContext.close() पूल में एलडीएपी कनेक्शन वापस नहीं करता है?

मैं एक न्यूनतम मामले को उसे संक्षिप्त में कामयाब रहे। भले ही मेरा मानना ​​है कि मैं निर्धारित सभी प्रासंगिक वस्तुओं पर close() पर कॉल कर रहा हूं, ऐसा लगता है कि वास्तव में पूल में वस्तुओं को वापस करने के लिए कचरा संग्रह पर निर्भर है, जो अप्रत्याशित है। ऐसा क्यों हो रहा है? क्या कोई अन्य वस्तु है जो मुझे बंद करनी चाहिए?

नीचे कोड स्निपेट में:

  • मैं कृत्रिम समस्या को उजागर करने के 1 करने के लिए अधिकतम पूल आकार निर्धारित किया है।
  • मैं पूल से एक DirContext मिल (लाइन (2)), प्रयास यह पूल पर लौटने के लिए (लाइन (4)), तो पूल से एक और एक (लाइन (6)) मिलता है जो एक ही वापस जाने के लिए चाहिए वस्तु वापस कर दिया।
  • बजाय, दूसरा अनुरोध (लाइन (6)) Object.wait() को कुछ आंतरिक फोन पर लटका हुआ है। मुझे लगता है कि यह एक पूल ऑब्जेक्ट उपलब्ध होने की प्रतीक्षा कर रहा है।
  • अगर बाहर टिप्पणी करके पूलिंग बंद करें (1), यह लटका नहीं है (लेकिन मैं पूलिंग करना चाहता हूं!)।
  • अगर मैं बाहर टिप्पणी (3) - SearchResults.next() के लिए एक कॉल - यह ठीक काम करता है।
  • अगर मैं टिप्पणी हटाएं लाइन (5) की वापसी पूल करने के लिए 'कॉल और पूल करने के लिए एक नई वस्तु का अनुरोध के बीच कचरा संग्रहण के लिए मजबूर करने, लटका नहीं करता है।

लाइन से टिप्पणी करने के बाद (3) समस्या दूर हो जाती है, शायद मैं इसका सही मूल्य बंद नहीं कर रहा हूं, और यह पूल कनेक्शन को खुला रख रहा है। हालांकि, विधि results.next() इस मामले में SearchResult लौटाती है, जिसमें close विधि नहीं है और इसे अपने दस्तावेज़ में साफ-सफाई के तरीके पर कोई मार्गदर्शन नहीं है।

परीक्षण का मामला:

@Test 
public void testHangs() throws NamingException { 

    System.setProperty("com.sun.jndi.ldap.connect.pool.debug", "fine"); 
    System.setProperty("com.sun.jndi.ldap.connect.pool.maxsize", "1"); 

    Hashtable<String,String> env = new Hashtable<String,String>(); 
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
    env.put(Context.SECURITY_PRINCIPAL, user); 
    env.put(Context.SECURITY_CREDENTIALS, passwd); 
    env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
    env.put(Context.PROVIDER_URL, ldapUrl); 

    // use a connection pool 
    env.put("com.sun.jndi.ldap.connect.pool", "true"); // ----------------- (1) 

    // get a context from the pool. 
    DirContext context = new InitialDirContext(env); // -------------------- (2) 
    NamingEnumeration<SearchResult> results = context.search("", query, getSC()); 
    // obviously the next two lines would normally be in a 
    // while(results.hasMore()) { ... = results.next(); } loop. 
    assertTrue(results.hasMore()); // this is only a problem when there are some results. 
    results.next(); // ----------------------------------------------------- (3) 

    // ensure the context is returned to the pool. 
    results.close(); 
    context.close(); // ---------------------------------------------------- (4) 

    //System.gc(); // ------------------------------------------------------ (5) 

    new InitialDirContext(env); // hangs here! ---------------------------- (6) 
} 

कोड यह है के रूप में के साथ, मेरे कंसोल पता चलता है:

Create [email protected][ldapad:389] 
Use [email protected] 

जबकि यदि मैं जीसी मजबूर मैं अतिरिक्त देखें:

Release [email protected] <-- on GC 
Use [email protected]  <-- on new InitialDirContext 

उत्तर

7

कुछ जांच के बाद मुझे पता चला कि एलडीएपी कनेक्शन पूल में वापस नहीं किया गया है क्योंकि SearchResult ऑब्जेक्ट में एक है LdapCtx ऑब्जेक्ट का संदर्भ।

आप बदलना तो

results.next(); 

निम्नलिखित

SeachResult ob = results.next(); 
((Context)ob.getObject()).close(); 

के साथ कनेक्शन सही तरीके से पूल को लौटा दी जाएगी। यह डिफ़ॉल्ट कार्यान्वयन में एक बग की तरह लगता है।

स्प्रिंग एलडीएपी टेम्पलेट का उपयोग करते समय थेप्रोबलेम मौजूद नहीं है क्योंकि यह खोज में एक कस्टम "java.naming.factory.object" प्रदान करता है जो LdapCtx को SearchResult बनाने की प्रक्रिया के हिस्से के रूप में बंद करता है। यह आसानी से अपने classpath को वसंत LDAP पुस्तकालय जोड़ने और InitialContext

java.naming.factory.object = org.springframework.ldap.core.support.DefaultDirObjectFactory

के लिए निम्न जोड़कर demostrated किया जा सकता है जब यह किया जाता है तो SearchResult द्वारा आयोजित ऑब्जेक्ट com.sun.jndi.ldap.LdapCtx: com.sun.jndi.ldap.LdapCtx से org.springframework.ldap.core.DirContextAdapter से बदलता है। DefaultDirObjectFactory वर्ग DirContextAdapter बनाने के लिए जिम्मेदार है और DirectoryManager को DirContextAdapter लौटने से पहले LdapCtx बंद करने के लिए ख्याल रखता है। यहाँ अंत में DefaultDirObjectFactory से

finally { 
     // It seems that the object supplied to the obj parameter is a 
     // DirContext instance with reference to the same Ldap connection as 
     // the original context. Since it is not the same instance (that's 
     // the nameCtx parameter) this one really needs to be closed in 
     // order to correctly clean up and return the connection to the pool 
     // when we're finished with the surrounding operation. 
     if (obj instanceof Context) { 

      Context ctx = (Context) obj; 
      try { 
       ctx.close(); 
      } 
      catch (Exception e) { 
       // Never mind this 
      } 

     } 
    } 
+1

धन्यवाद! यह निराशाजनक है कि दस्तावेज कहता है कि एलडीएपी प्रदाता के लिए पूल किए गए कनेक्शन को सही तरीके से प्रबंधित करने के लिए आदेश में, आपको संदर्भों पर Context.close() को आमंत्रित करने के बारे में मेहनत करनी चाहिए, जिनकी आपको अब आवश्यकता नहीं है, फिर भी यह समझ में नहीं आता कि आप अर्थपूर्ण तरीके से कैसे कर सकते हैं यह न ही आपको बताएगा कि कौन सी प्रदत्त वस्तुएं स्वयं इन वस्तुओं को पकड़ सकती हैं जिन्हें बंद करने की भी आवश्यकता है। – bacar

+0

यदि आप लूप जारी रखते हैं, तब तक 'results.next() 'झूठी रिटर्न देता है, कनेक्शन स्वचालित रूप से बंद हो जाता है। – EJP

4
ब्लॉक

returningObjFlag झूठी विशेषता है करने के लिए अपने SearchControls वस्तु बदले है। आपको आमतौर पर ऑब्जेक्ट की आवश्यकता नहीं होती है, बस इसका नाम इननामस्पेस और इसके गुण। यदि आप subcontexts बनाने या संशोधित करने जा रहे हैं तो आपको केवल ऑब्जेक्ट की आवश्यकता है।

+0

धन्यवाद - यह काम करता प्रतीत होता है, और मुझे [खोज परिणाम] (http://docs.oracle.com/javase/tutorial/jndi/ldap पर एलडीएपी ट्यूटोरियल पेज से ध्वज क्या करता है, इसकी एक बेहतर समझ है। /result.html#OBJ) – bacar

संबंधित मुद्दे