服务提供者框架(Service Provider Framework)


       服务提供者框架是指:多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。服务提供者的改变对它们的客户端是透明的,这样提供了更好的可扩展性。例如,JDBC,JMS等就是用了服务提供者框架

      从字面意思看就是:实何实现服务提供者提供服务功能的设计结构,主体有服务、服务提供者。反映到我们程序中,通常有四个组件:

  • Service Interface:服务接口,将服务通过抽象统一声明,供客户端调用、由各个服务提供者具体实现。
  •  Provider Registration API:服务提供者注册API,用于系统注册服务提供者,使得客户端可以访问它实现的服务。
  •  Service Access API:服务访问API,用户客户端获取相应的服务。
  •  Service Provider Interface:服务提供者接口,这些服务提供者负责创建其服务实现的实例。(可选)


         服务接口定义服务。服务提供者接口产生服务实例。

       首先我们来看一下典型的服务提供者框架的程序结构是怎么样的:

       大家都知道都在我们国家盐是归定必须加碘才能在市场上卖的。食盐又分为海盐和内陆盐,食盐生产厂家在要生产食盐之前都必须去盐监局登记。

       

  

/**
 *
 * @author <a href="mailto:amoszhou@foxmail.com">amos zhou</a>
 * @Function:食盐
 * @Since Jan 30, 2012
 *
 */
public interface Salt {

    /**
     *
     * @Function:加碘
     * @Since Jan 30, 2012
     */
    void  addIodine();
}

现在这个加碘是盐监局制定的一个规定,那么海盐厂商和内陆盐厂商分别有自己的加碘方式,他们对这个规定有自己不同的实现。


/**
 *
 * @author <a href="mailto:amoszhou@foxmail.com">amos zhou</a>
 * @Function:海盐
 * @Since Jan 30, 2012
 *
 */
public class Baysalt implements Salt {

    public void addIodine() {
        // TODO 加碘操作
        
    }

    
}

 //内陆盐
 public class InlandSalt implements Salt {

    public void addIodine() {
        // TODO 加碘操作
        
    }

}





  要加碘,我们就首先得有盐啊,那么各厂商有自己生产盐的方式。

public interface  SaltProvider {

    Salt  getSalt();
}



/**
 *
 * @author <a href="mailto:amoszhou@foxmail.com">amos zhou</a>
 * @Function:海盐厂商
 * @Since Jan 30, 2012
 *
 */
public class BaysaltProvider implements SaltProvider {    
    
    /**
     * 去盐监司登记
     */
    static{
        SaltManager.registerProvider("baysaltProvider", new BaysaltProvider());
    }

    public Salt getSalt() {
        // 用太阳晒,把水份蒸发
        return new Baysalt();
    }
    
    

}


/**
 *
 * @author <a href="mailto:amoszhou@foxmail.com">amos zhou</a>
 * @Function:内陆盐厂商
 * @Since Jan 30, 2012
 *
 */
public class InlandSaltProvider implements SaltProvider {    
    
    /**
     * 去盐监司登记
     */
    static{
        SaltManager.registerProvider("inlandSalt", new InlandSaltProvider());
    }

    public Salt getSalt() {
        //用挖掘机挖
        return new InlandSalt();
    }
    
    

}

/**
 *
 * @author <a href="mailto:amoszhou@foxmail.com">amos zhou</a>
 * @Function:盐监司
 * @Since Jan 30, 2012
 *
 */
public class SaltManager {

    /**
     * 食盐生产厂商登记档案
     */
    private static final Map<String, SaltProvider> providers = new ConcurrentHashMap<String, SaltProvider>();

    /**
     *
     * @Function:食盐厂商登记
     * @Since Jan 30, 2012
     * @param name
     * @param p
     */
    public static void registerProvider(String name, SaltProvider p) {
        providers.put(name, p);
    }

    /**
     *
     * @Function: 获取食盐
     * @Since Jan 30, 2012
     * @param name
     * @return
     */
    public static Salt getSalt(String name) {

        SaltProvider p = providers.get(name);
        if (p == null) {
            throw new IllegalArgumentException(
                    "No SaltProvider registered with name:" + name);
        }
        return p.getSalt();

    }
}

测试代码:


public class Test {

    /**
     * @Function:
     * @Since Jan 30, 2012
     * @param args
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("com.amos.spf.InlandSaltProvider");
        Salt salt = SaltManager.getSalt("inlandSalt");
        salt.addIodine();

    }

}


 
          上面这个例子可能不在严谨,在理解上有点费力,但是请细心想想,感悟。服务提供者框架就是这样的:服务的具体实现对于客户端是透明的,用户只知道Salt接口,并不是知道海盐和内陆盐,具体的实现由服务提供者实现。服务提供者的主要任务就是将自己注册到服务管理器中,并产生服务接口的实例。

         也就是说:对服务标准制定者而言:我制定了一个服务标准,然后定义了一个类似于字典的服务管理器,提供一个注册的接口给你,你实现了服务以后就自己注册到字典里面去。我并不知道你是如何实现这个服务的。对于服务实现厂商而言,我只知道我要实现的服务标准,以及我如何注册,我只需要做两件事:1、实现服务。2、注册到服务管理器中。对最终用户而言,我只需要知道怎么用就行了,至于你们是怎么实现的跟我没半毛钱关系。



         


           引申至JDBC中:

        Connection接口就是一个服务接口,定义了很多操作,但是JDBC本身不对该服务进行实现,而是由mysql,sqlServer、Oracle、DB2等各数据库厂商去实现。然后注册到DriverManager中。 用户只需要根据注册时的KEY 去查找到相关的服务即可。


          以mysql为例:

 

Class.forName("com.mysql.jdbc.Driver");   
DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123");


Class.forName("com.mysql.jdbc.Driver"); 
从这句我们可以看出:com.sql.jdbc.Driver是一个服务提供者,他提供服务,并注册到DriverManager中。至于mysql中Connection的具体实现,我们甚连类名都不知道(在不看源码的情况下)。


我们来看一下DriverManager中getConnection的源码实现吧。

 private static Connection getConnection(
    String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
    java.util.Vector drivers = null;
        /*
     * When callerCl is null, we should check the application's
     * (which is invoking this class indirectly)
     * classloader, so that the JDBC driver class outside rt.jar
     * can be loaded from here.
     */
    synchronized(DriverManager.class) {    
      // synchronize loading of the correct classloader.
      if(callerCL == null) {
          callerCL = Thread.currentThread().getContextClassLoader();
       }    
    }
    
    if(url == null) {
        throw new SQLException("The url cannot be null", "08001");
    }
    
    println("DriverManager.getConnection(\"" + url + "\")");
    
    if (!initialized) {
        initialize();
    }

    synchronized (DriverManager.class){
            // use the readcopy of drivers
        drivers = readDrivers;  
        }

    // Walk through the loaded drivers attempting to make a connection.
    // Remember the first exception that gets raised so we can reraise it.
    SQLException reason = null;
    for (int i = 0; i < drivers.size(); i++) {
        DriverInfo di = (DriverInfo)drivers.elementAt(i);
      
        // If the caller does not have permission to load the driver then
        // skip it.
        if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
        println("    skipping: " + di);
        continue;
        }
        try {
        println("    trying " + di);
        Connection result = di.driver.connect(url, info);
        if (result != null) {
            // Success!
            println("getConnection returning " + di);
            return (result);
        }
        } catch (SQLException ex) {
        if (reason == null) {
            reason = ex;
        }
        }
    }
    
    // if we got here nobody could connect.
    if (reason != null)    {
        println("getConnection failed: " + reason);
        throw reason;
    }
    
    println("getConnection: no suitable driver found for "+ url);
    throw new SQLException("No suitable driver found for "+ url, "08001");
    }

其中最关键的是一那个For循环,drivers是一个Vector向量,他充当字典。对整个字典进行循环,对我们要查找的类和字曲中的所有的Class进行匹配,若能匹配成功即连接数据库,否则抛出异常。


        好啦,关于这个概念就写到这,关键还是要自己去感觉、体会。代码这东西很多东西,只可意会,不可言传!

      


     


     

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值