服务提供者框架是指:多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。服务提供者的改变对它们的客户端是透明的,这样提供了更好的可扩展性。例如,JDBC,JMS等就是用了服务提供者框架
从字面意思看就是:实何实现服务提供者提供服务功能的设计结构,主体有服务、服务提供者。反映到我们程序中,通常有四个组件:
Service Interface:服务接口,将服务通过抽象统一声明,供客户端调用、由各个服务提供者具体实现。
Provider Registration API:服务提供者注册API,用于系统注册服务提供者,使得客户端可以访问它实现的服务。
Service Access API:服务访问API,用户客户端获取相应的服务。
Service Provider Interface:服务提供者接口,这些服务提供者负责创建其服务实现的实例。(可选)
服务接口定义服务。服务提供者接口产生服务实例。
首先我们来看一下典型的服务提供者框架的程序结构是怎么样的:
大家都知道都在我们国家盐是归定必须加碘才能在市场上卖的。食盐又分为海盐和内陆盐,食盐生产厂家在要生产食盐之前都必须去盐监局登记。
[java] view plain copy
/**
*/
public interface Salt {
/**
现在这个加碘是盐监局制定的一个规定,那么海盐厂商和内陆盐厂商分别有自己的加碘方式,他们对这个规定有自己不同的实现。
[java] view plain copy
/**
*/
public class Baysalt implements Salt {
public void addIodine() {
// TODO 加碘操作
}
}
//内陆盐
public class InlandSalt implements Salt {
public void addIodine() {
// TODO 加碘操作
}
}
要加碘,我们就首先得有盐啊,那么各厂商有自己生产盐的方式。
[java] view plain copy
public interface SaltProvider {
Salt getSalt();
}
/**
*/
public class BaysaltProvider implements SaltProvider {
/**
public Salt getSalt() {
// 用太阳晒,把水份蒸发
return new Baysalt();
}
}
/**
*/
public class InlandSaltProvider implements SaltProvider {
/**
public Salt getSalt() {
//用挖掘机挖
return new InlandSalt();
}
}
[java] view plain copy
/**
*/
public class SaltManager {
/**
/**
/**
@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();
}
}
测试代码:
[java] view plain copy
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为例:
[java] view plain copy
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123");
[java] view plain copy
Class.forName("com.mysql.jdbc.Driver");
从这句我们可以看出:com.sql.jdbc.Driver是一个服务提供者,他提供服务,并注册到DriverManager中。至于mysql中Connection的具体实现,我们甚连类名都不知道(在不看源码的情况下)。
我们来看一下DriverManager中getConnection的源码实现吧。
[java] view plain copy
private static Connection getConnection(
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
java.util.Vector drivers = null;
/*
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进行匹配,若能匹配成功即连接数据库,否则抛出异常。
好啦,关于这个概念就写到这,关键还是要自己去感觉、体会。代码这东西很多东西,只可意会,不可言传!
2025 - 快车库 - 我的知识库 重庆启连科技有限公司 渝ICP备16002641号-10
企客连连 表单助手 企服开发 榜单123