2012-08-14 76 views
7

我同時使用LDAP連接該上下文調用close()並未將其返回到池池,儘管文檔sayingotherwise注意到。因此,當我試圖從池中獲取物品時,它已經達到其最大尺寸,它會掛起。爲什麼不DirContext.close()返回到連接池的LDAP連接?

我設法將它縮小到最小的情況下。儘管我相信我確定地調用了所有相關對象上的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] 

而如果我強迫GC我還看到:

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

回答

7

經過一番調查後,我發現LDAP連接沒有返回到池中,因爲SearchResult對象包含一個參考LdapCtx對象。

如果更換

results.next(); 

用下面

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

的連接將被正確地返回到池中。這看起來像是默認實現中的一個錯誤。

使用Spring LDAPTemplate時,該問題不存在,因爲它在關閉LdapCtx的環境中提供了一個自定義的「java.naming.factory.object」,作爲構建SearchResult的一部分。這可以通過添加春LDAP庫到類路徑並添加以下向初始

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

很容易地以實例闡述完成此操作後,SearchResult所持有的對象將從com.sun.jndi.ldap.LdapCtx:com.sun.jndi.ldap.LdapCtx更改爲org.springframework.ldap.core.DirContextAdapter。該DefaultDirObjectFactory類是負責創建DirContextAdapter和照顧返回DirContextAdapter將DirectoryManager之前關閉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

謝謝!令人感到沮喪的是,爲了讓LDAP提供者正確管理池連接,您必須努力在不再需要的上下文上調用Context.close(),但並未解釋如何有意義地執行這也不告訴你哪些提供的對象可能自己抓住這些也需要關閉的對象。 – bacar 2012-08-15 09:53:36

+0

如果繼續循環直到'results.next()'返回false,連接會自動關閉。 – EJP 2015-01-15 17:39:21

4

更改SearchControls對象有returningObjFlag屬性假。您通常不需要該對象本身,只需要它的nameInNamespace及其屬性。如果要創建或修改子上下文,則只需要該對象本身。

+0

感謝 - 這似乎工作,並且我已經更好地瞭解該標誌在[搜索結果]上的LDAP教程頁面(http://docs.oracle.com/javase/tutorial/jndi/ldap /result.html#OBJ) – bacar 2012-08-15 13:06:18