用SERVICE LOCATOR 模式实现命名访问服务 
  
在B/S开发中, 我们经常要用到名称服务,如JNDI,XMLNS等。名称服务随不同厂家而不同。每次需要获得名称服务时,需要适当的名称环境信息,然后查找服务,重复查找的成本很高。 
  
此外,在持久性框架中,要求将所有的服务访问都包装到对象中,开发人员不需要知道名称服务后面的平台(数据库)类型,及任何安全信息或地址。在一个大型软件产品间存在多个EJB和多个数据源连接时(我们目前只有一个写死的数据源WEBGL)需要一个类来实现统一的访问管理。 
  
因此,这就要求我们对这些访问进行封装隔离。这时我们就可以利用SERVICE LOCATOR模式。 
  
  
我们将利用一个文件service.properties来管理所有的命名服务。例子代码实现了EJB本地,数据源的访问。 
格式如下: 
DEFAULTDS=webgl 
NTCLASSREF=NTHome.class 
  
把它保存在CLASSPATH引用的路径里。 
  
源代码: 
  
Package  com.learn; 
  
import java.util.Hashtable; 
import java.util.Properties; 
import java.io.*; 
import javax.ejb.EJBHome; 
import javax.naming.InitialContext; 
import javax.naming.Context; 
import javax.naming.NamingException; 
import javax.rmi.PortableRemoteObject; 
import java.sql.Connection; 
import java.sql.SQLException; 
import javax.sql.DataSource; 
  
public class ServiceLocator { 
  private static ServiceLocator serviceLocatorRef = null; 
  private static Hashtable ejbHomeCache = null; 
  private static Hashtable dataSourceCache = null; 
  private static Properties serviceCache = null; 
  static { 
    serviceLocatorRef = new ServiceLocator(); 
  } 
  
  private ServiceLocator() { 
    ejbHomeCache = new Hashtable(); 
    dataSourceCache = new Hashtable(); 
    try { 
      String serviceFileName = "service.properties"; 
      serviceCache.load(new FileInputStream(serviceFileName)); 
    } 
    catch (IOException e) { 
      System.out.println(e.toString()); 
    } 
  } 
  
  /** 
   * 使用singleton.模式静态对象多次调用节省资源   */ 
  
  public static ServiceLocator getInstance() { 
    return serviceLocatorRef; 
  } 
  
  /* 
   * 由键获得键值,一般在数据源,XMLNS访问用到这个方法 
   */ 
  static private String getServiceName(String serviceId) 
    throws ServiceLocatorException{ 
    String serviceName=null; 
    if (serviceCache.containsKey(serviceId)) { 
      serviceName = (String) serviceCache.get(serviceId); 
    } 
    else { 
      throw new ServiceLocatorException( 
        "Unable to locate the service statement requested"); 
    } 
    return serviceName; 
  } 
  
/************************************************* 
 * EJB本地类引用 
*************************************************/    
  static private Class getEJBHomeRef(String serviceId) throws 
    ServiceLocatorException { 
    Class homeRef = null; 
    if (serviceCache.containsKey(serviceId)) { 
      homeRef = (Class) serviceCache.get(serviceId); 
    } 
    else { 
      throw new ServiceLocatorException( 
        "Unable to locate the service statement requested"); 
    } 
    return homeRef; 
  } 
  
/************************************************************************ 
 * 获得EJBHome对象 
 ***********************************************************************/    
  public EJBHome getEJBHome(String serviceId) throws ServiceLocatorException { 
    EJBHome ejbHome = null; 
    try { 
      //先检查缓存是否存在EJBHome接口 
      if (ejbHomeCache.containsKey(serviceId)) { 
        ejbHome = (EJBHome) ejbHomeCache.get(serviceId); 
        return ejbHome; 
      } 
      else { 
        //如果没有存在,则解析并存到缓存中 
        Context ctx = new InitialContext(); 
        Object jndiRef = ctx.lookup(serviceId); 
        Object portableObj = PortableRemoteObject.narrow(jndiRef, 
          getEJBHomeRef(serviceId)); 
        ejbHome = (EJBHome) portableObj; 
        ejbHomeCache.put(serviceId, ejbHome); 
        return ejbHome; 
      } 
    } 
    catch (NamingException e) { 
      throw new ServiceLocatorException( 
        "Naming exception error in ServiceLocator.getEJBHome()", e); 
    } 
  } 
  
  /* 
   * 获得JNDI数据源 
   */ 
  public Connection getDBConn(String serviceId) throws 
    ServiceLocatorException { 
    Connection conn = null; 
    String serviceName=getServiceName(serviceId); 
    try { 
      /*Checking to see if the requested DataSource is in the Cache*/ 
      if (dataSourceCache.containsKey(serviceId)) { 
        DataSource ds = (DataSource) dataSourceCache.get(serviceId); 
        conn = ( (DataSource) ds).getConnection(); 
        return conn; 
      } 
      else { 
        /* 
         * The DataSource was not in the cache.  Retrieve it from JNDI 
         * and put it in the cache. 
         */ 
        Context ctx = new InitialContext(); 
        DataSource newDataSource = (DataSource) ctx.lookup(serviceName); 
        dataSourceCache.put(serviceId, newDataSource); 
        conn = newDataSource.getConnection(); 
        return conn; 
      } 
    } 
    catch (SQLException e) { 
      throw new ServiceLocatorException("A SQL error has occurred in " + 
                                        "ServiceLocator.getDBConn()", e); 
    } 
    catch (NamingException e) { 
      throw new ServiceLocatorException("A JNDI Naming exception has occurred " + 
                                        " in ServiceLocator.getDBConn()", e); 
    } 
    catch (Exception e) { 
      throw new ServiceLocatorException("An exception has occurred " + 
                                        " in ServiceLocator.getDBConn()", e); 
    } 
  } 
  
} 
  
  
异常处理类: 
  
package com.learn; 
public class ServiceLocatorException extends DataAccessException{ 
  public ServiceLocatorException(String pExceptionMsg){ 
    super(pExceptionMsg); 
  } 
  
  public ServiceLocatorException(String pExceptionMsg, Throwable pException){ 
    super(pExceptionMsg, pException); 
  } 
  
} 
  
  
参考书籍: 
        《实用J2EE设计模式编程指南》 
              《WEB服务精髓》 
         《J2EE 与 BEA WEBLOGIC SERVER》 
  
  
请大家指教:[email protected]  
 
  |