首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2EE

Service Locator 模式:統一管理 JNDI 命名服務存取

     編輯:J2EE

背景動機

在 B/S 開發中,頻繁存取 JNDI、XMLNS 等命名服務,每次都需提供環境屬性並查找,重複查找成本高。大型系統中存在多個 EJB 與資料源,需統一存取管理,隱藏底層平台、安全資訊與位址細節。Service Locator 模式正是為了解決此問題而生。

設計核心

  • 使用 service.properties 集中管理所有命名服務設定(如 DEFAULTDS=webgl、NTCLASSREF=NTHome.class)
  • 採用 Singleton 模式確保單一實例,節省資源
  • 提供快取機制(Hashtable)避免重複 JNDI 查找
  • 封裝 EJBHome 取得、資料源連線取得等常用操作

核心程式碼解析

// 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); }
}

優勢總結

  • 集中設定,易於維護與移植
  • 快取機制大幅降低 JNDI 查找開銷
  • 統一存取介面,業務邏輯與底層資源解耦
  • 支援 EJB 與資料源兩大核心資源類型

參考書籍:《實用 J2EE 設計模式編程指南》、《Web 服務精髓》、《J2EE 與 BEA WebLogic Server》。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved