Warum nicht DirContext.close() return die LDAP-Verbindung an den pool?
Bemerkte ich während der Verwendung einer LDAP-Verbindung-pool, der Aufruf close()
auf den Kontext offenbar nicht zurück in den pool, trotz der Dokumentation sagen sonst. So, wenn ich Versuch, ein Element aus dem pool, wenn es schon bei seiner max Größe, hängt es.
Habe ich es geschafft es zu beschränken, um eine minimale Falle. Obwohl ich glaube, ich rufe close()
auf alle relevanten Objekte deterministisch, es scheint, verlassen sich auf die garbage collection, um tatsächlich die Objekte zurückgeben, um den pool, die unerwartet ist. Warum ist das passiert? Gibt es eine andere Objekt sollte ich schließen?
In das code-snippet unten:
- Ich habe künstlich legen Sie die maximale pool-Größe auf 1 markieren Sie das problem.
- Ich eine
DirContext
aus dem pool (Zeile (2)), Versuch es zurück an den pool (Zeile (4)), dann bekommen die anderen einen aus dem pool (Zeile (6)), die sollten wieder den gleichen, zurückgegebene Objekt. - statt, die zweite Anforderung (Zeile (6)) hängt einige interne Aufruf
Object.wait()
. Ich vermute, es wartet eine zusammengefasste Objekt verfügbar werden. - wenn ausschalten-pooling durch auskommentieren (1), hängt Sie nicht (aber ich möchte pooling!).
- wenn ich kommentiere (3) - ein Aufruf von
SearchResults.next()
- es funktioniert gut. - wenn ich die Auskommentierung Zeile (5) erzwingen, dass die garbage collection zwischen dem "return to pool' nennen, und die Anforderung ein neues Objekt an den pool, wird es nicht hängen.
Seit auskommentieren der Zeile (3) ist das problem Weg, vielleicht bin ich nicht die Schließung der return-Wert es richtig, und es hält die zusammengefasste Verbindung öffnen. Allerdings ist die Methode results.next()
gibt eine SearchResult
in diesem Fall, die hat keine close
Methode und keine Anleitung in der Dokumentation auf, wie um es zu schließen sauber.
Testfall:
@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)
}
Mit dem code, wie es ist, meine Konsole zeigt:
Create com.sun.jndi.ldap.LdapClient@1a7bf11[ldapad:389]
Use com.sun.jndi.ldap.LdapClient@1a7bf11
In der Erwägung, dass, wenn ich die Kraft der GC, die ich zusätzlich finden Sie unter:
Release com.sun.jndi.ldap.LdapClient@93dee9 <-- on GC
Use com.sun.jndi.ldap.LdapClient@93dee9 <-- on new InitialDirContext
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nach ein bisschen Untersuchung habe ich festgestellt, dass die LDAP-Verbindung ist nicht an den pool zurückgegeben, weil die SearchResult-Objekt enthält einen Verweis auf die LdapCtx Objekt.
Wenn Sie ersetzen
Mit den folgenden
Die die Verbindung ordnungsgemäß an den pool zurückgegeben. Dies scheint ein bug in der Standard-Implementierung.
Theproblem nicht vorhanden ist, wenn mit dem Frühjahr LDAPTemplate, weil es eine eigene "java.die Benennung.factory.Objekt" in der Umgebung, schließt die LdapCtx als Teil des Prozesses der Bau der SearchResult. Dies kann leicht demonstriert, indem die Feder LDAP-library zum Klassenpfad und fügen Sie den folgenden, um den InitialContext
java.die Benennung.factory.Objekt=org.springframework.ldap.core.Unterstützung.DefaultDirObjectFactory
Wenn dies geschehen ist, das Objekt im Besitz der SearchResult änderungen von com.Sonne.jndi.ldap.LdapCtx:com.Sonne.jndi.ldap.LdapCtx zu org.springframework.ldap.core.DirContextAdapter. Die DefaultDirObjectFactory Klasse ist verantwortlich für die Erstellung der DirContextAdapter und kümmert sich um das schließen der LdapCtx vor der Rückkehr der DirContextAdapter der DirectoryManager. Hier ist der finally-block aus der DefaultDirObjectFactory
results.next()
gibt false zurück, wird die Verbindung nicht automatisch geschlossen.Ändern Sie Ihre
SearchControls
Objekt zu haben, dasreturningObjFlag
Attribut false. Sie müssen sich normalerweise nicht das Objekt selbst, sondern nur seine nameInNamespace und seine Attribute. Sie müssen nur das Objekt selbst wenn Sie erstellen oder ändern subcontexts.