LdapConnectionFactory 為單例工廠(私有建構子),提供兩類靜態方法:
DirContext(指定池名)DirContext(無池名)DirContext 並處理例外package com.common.ldapconnection;
import java.util.Properties;
import javax.naming.*;
import javax.naming.directory.*;
import org.apache.log4j.Logger;
import org.apache.commons.lang.StringUtils;
public class LdapConnectionFactory {
private static final Logger log = Logger.getLogger(LdapConnectionFactory.class.getName());
private LdapConnectionFactory() {} // 防止實例化
/** 從連線池取得 DirContext */
public static DirContext getDirContext(String poolName, Env env) {
log.debug("INTO getDirContext(pool)");
try {
Properties mEnv = buildEnvProps(env);
mEnv.put("com.sun.jndi.ldap.connect.pool", "true"); // 啟用連線池
// poolName 實際由上層透過 JNDI 名稱綁定管理,此處略過綁定邏輯
DirContext ctx = new InitialDirContext(mEnv);
log.debug("DirContext from pool created successfully");
return ctx;
} catch (NamingException ex) {
log.error("Create DirContext from pool failed", ex);
return null;
}
}
/** 直接建立 DirContext(無連線池) */
public static DirContext getDirContext(Env env) {
log.debug("INTO getDirContext(direct)");
try {
Properties mEnv = buildEnvProps(env);
DirContext ctx = new InitialDirContext(mEnv);
log.debug("Direct DirContext created successfully");
return ctx;
} catch (NamingException ex) {
log.error("Create direct DirContext failed", ex);
return null;
}
}
/** 共用屬性建構邏輯:DRY 原則 */
private static Properties buildEnvProps(Env env) {
Properties mEnv = new Properties();
mEnv.put(Context.AUTHORITATIVE, "true");
mEnv.put(Context.INITIAL_CONTEXT_FACTORY, env.factory);
mEnv.put(Context.PROVIDER_URL, env.url);
if (!StringUtils.isEmpty(env.timeOut)) {
mEnv.put("com.sun.jndi.ldap.connect.timeout", env.timeOut);
}
mEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
if (env != null && "ssl".equals(env.securityProtocol)) {
mEnv.put(Context.SECURITY_PROTOCOL, "ssl");
System.setProperty("javax.net.ssl.trustStore", env.sslTrustStore);
}
mEnv.put(Context.SECURITY_PRINCIPAL, env.adminUID);
mEnv.put(Context.SECURITY_CREDENTIALS, env.adminPWD);
return mEnv;
}
/** 安全關閉 DirContext */
public static void closeDirContext(DirContext dirContext) {
if (dirContext != null) {
try {
dirContext.close();
} catch (Exception ex) {
log.error("Failed to close DirContext", ex);
}
}
}
}
設定 com.sun.jndi.ldap.connect.pool=true 即啟用 JDK 內建 LDAP 連線池。池參數(大小、逾時、驗證)可透過系統屬性 com.sun.jndi.ldap.connect.pool.* 調整。生產環境強烈建議啟用,大幅降低頻繁建立連線開銷。
System.setProperty("javax.net.ssl.trustStore", ...) 為全 JVM 生效,若同一應用需連接不同 SSL LDAP 伺服器,需自行實作 SSLSocketFactory 而非依賴系統屬性。本工具類適用單一 LDAP 目標場景。
null,由呼叫端決定重試或拋出業務異常。commons-lang:StringUtils.isEmpty() 簡化空值檢查log4j:企業級日誌標準Env env = new Env("com.sun.jndi.ldap.LdapCtxFactory",
"ldap://ldap.example.com:389",
"cn=admin,dc=example,dc=com", "password");
// 直連模式
DirContext ctx = LdapConnectionFactory.getDirContext(env);
try {
// 業務操作...
} finally {
LdapConnectionFactory.closeDirContext(ctx);
}
// 連線池模式(需配合 JNDI 資源配置)
DirContext pooledCtx = LdapConnectionFactory.getDirContext("myLdapPool", env);
下一篇將介紹核心業務操作類 LdapOperUtils:Context 增刪改、屬性管理、搜尋與認證功能。