在 B/S 開發中,頻繁存取 JNDI、XMLNS 等命名服務,每次都需提供環境屬性並查找,重複查找成本高。大型系統中存在多個 EJB 與資料源,需統一存取管理,隱藏底層平台、安全資訊與位址細節。Service Locator 模式正是為了解決此問題而生。
service.properties 集中管理所有命名服務設定(如 DEFAULTDS=webgl、NTCLASSREF=NTHome.class)Hashtable)避免重複 JNDI 查找// ServiceLocator.java
package com.learn;
import javax.ejb.EJBHome;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Hashtable;
import java.util.Properties;
import java.io.*;
public class ServiceLocator {
private static ServiceLocator serviceLocatorRef = null;
private static Hashtable ejbHomeCache = new Hashtable();
private static Hashtable dataSourceCache = new Hashtable();
private static Properties serviceCache = new Properties();
static { serviceLocatorRef = new ServiceLocator(); }
private ServiceLocator() {
try {
serviceCache.load(new FileInputStream("service.properties"));
} catch (IOException e) { System.out.println(e); }
}
public static ServiceLocator getInstance() { return serviceLocatorRef; }
// 取得服務名稱(用於資料源、XMLNS)
private static String getServiceName(String serviceId) throws ServiceLocatorException {
String name = (String) serviceCache.get(serviceId);
if (name == null) throw new ServiceLocatorException("找不到服務: " + serviceId);
return name;
}
// 取得 EJBHome 類別參考
private static Class getEJBHomeRef(String serviceId) throws ServiceLocatorException {
Class ref = (Class) serviceCache.get(serviceId);
if (ref == null) throw new ServiceLocatorException("找不到 EJBHome 參考: " + serviceId);
return ref;
}
// 取得 EJBHome(含快取)
public EJBHome getEJBHome(String serviceId) throws ServiceLocatorException {
if (ejbHomeCache.containsKey(serviceId)) return (EJBHome) ejbHomeCache.get(serviceId);
try {
Context ctx = new InitialContext();
Object jndiRef = ctx.lookup(serviceId);
Object portableObj = PortableRemoteObject.narrow(jndiRef, getEJBHomeRef(serviceId));
EJBHome home = (EJBHome) portableObj;
ejbHomeCache.put(serviceId, home);
return home;
} catch (NamingException e) {
throw new ServiceLocatorException("JNDI 錯誤", e);
}
}
// 取得資料庫連線(含快取)
public Connection getDBConn(String serviceId) throws ServiceLocatorException {
String serviceName = getServiceName(serviceId);
if (dataSourceCache.containsKey(serviceId)) {
DataSource ds = (DataSource) dataSourceCache.get(serviceId);
return ds.getConnection();
}
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(serviceName);
dataSourceCache.put(serviceId, ds);
return ds.getConnection();
} catch (Exception e) {
throw new ServiceLocatorException("取得連線失敗", e);
}
}
}
// ServiceLocatorException.java
package com.learn;
public class ServiceLocatorException extends DataAccessException {
public ServiceLocatorException(String msg) { super(msg); }
public ServiceLocatorException(String msg, Throwable e) { super(msg, e); }
}
參考書籍:《實用 J2EE 設計模式編程指南》、《Web 服務精髓》、《J2EE 與 BEA WebLogic Server》。