服务提供者框架
1.什么是服务提供者框架
服务提供者框架是指:多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。服务提供者的改变对它们的客户端是透明的,这样提供了更好的可扩展性。例如,JDBC,JMS等就是用了服务提供者框架 服务提供者框架是指:多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。服务提供者的改变对它们的客户端是透明的,这样提供了更好的可扩展性。例如,JDBC,JMS等就是用了服务提供者框架。
2.服务提供者关系图
略讲JDBC
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123");
从这个地方可以看出:我们只需要更换数据库的驱动名称与建立连接的URL,用
户名等信息,就可以完全切换到另外一个数据库。数据库底部怎么操作的我们不
清楚,也没必要清楚。我们获取的连接对象是Connection,查看
java.sql.Connection这个类,会发现它只是一个接口。我们得到的只是一个接口,
怎么可能能够操作数据库呢?其实这里得到的不是Connection接口,而是它的一个
实现类,只是对于客户端不可见而已。这可能就是所谓的面向接口编程,客户端只
需要知道它该知道的信息,服务端告诉客户端,你可以调用哪些方法。至于具体方
法怎么实现是服务端的事情,客服端就不需要管,也不需要知道了。
下面我们看看简单的这2个语句分别做了什么事情:
语句一: Class.forName("...")。这样一个语句会实例化一个
com.mysql.jdbc.Driver类(提供服务者实现类),并将这个类的实例注册到
DriverManager(服务提供者注册类)。
语句二: 通过建立连接的URL,用户名,密码来获取建立到mysql数据库的连
接。是这样的,DriverManager通过你传进来的url信息判断出你是要获取那个服务
提供者提供的服务。也就是语句一已经将提供服务者实现类注册到DriverManager
了,DriverManager获取到这个服务提供者实现类对象之后,通过调用它的
getService(mysql里面是connect方法)方法获取到服务具体实现类对象,返回的
却是java.sql.Connection接口对象(因为服务具体实现类实现了Connection接
口),这样把服务具体实现类对象隐藏了。提供了很好的扩展性。
3.详解
服务接口(Service Interface)
在服务接口里面定义一些提供具体服务的方法,假设我们需要实现进出地铁的服务SubWayService,这个服务接口中一定有in(),out()方法,我们之后再创建这个服务接口的具体的实现类去实现lin(),out()方法.服务提供者接口(Service Provider Interface)
服务提供者接口顾名思义就是定义提供什么样的服务的方法.我们在上面提供了一个服务接口,在这里就要提供一个能获取'注册登陆'服务的方法.
例如 : getSubWayrService() 返回值 为SubWayServiceInterface
然后去创建实现服务提供者接口的具体实现类实现getUserService()方法.提供者注册API(Provider Registration API)
服务提供者接口的具体实现类里面去注册这个API,在类的静态初始块中去注册API,因为只有注册了API,才能享受服务.这些注册过的API交给ServiceManager管理.服务访问API(Service Acess API)
既然已经注册了API,那我们就可以向ServiceManager申请具体的服务,调用服务实例的方法.
服务访问API是灵活的静态工厂,它构成了服务提供者框架的基础.
4实例 (一卡通为例,一次性相同的步骤)
以地铁进出控制为例:现在北铁进出都是刷卡,有二种卡:1.一卡通(比如一次性冲值50元,进地铁刷一次,出地铁刷一次,扣2元)。2.一次性卡(进地铁刷一次,出地铁插入回收。)这2种卡都可以实现进出地铁功能,但实现的具体方法是有区别的:一卡通:需要获取这卡余额是多少,然后扣掉2元。如果余额不足2元怎么处理等。一次性卡则没必要了。
1.整体框架
2.首先服务接口 和服务提供者接口
package serviceProvider;
/**
* @author frank
* @version 1.0
* @project practice
* @description 进出地铁服务接口
* @date 2023/8/12 09:48:23
*/
public interface SubWayServiceInterface {
//进入地铁
public boolean in();
//出地铁
public boolean out();
}
服务提供者接口
package serviceProvider;
/**
* @author frank
* @version 1.0
* @project practice
* @description 地铁进出服务提供者接口
* @date 2023/8/12 09:48:23
*/
public interface SubwayProviderInterface {
public SubWayServiceInterface getSubwayService();
}
3.当有了接口过后,不同的服务提供者可以实现接口,来实现不同方法体,在这里我把两个文件写在一起
#SubWayProviderImpl.java
package serviceProvider.oneCard;
import serviceProvider.ServiceManager;
import serviceProvider.SubWayServiceInterface;
import serviceProvider.SubwayProviderInterface;
/**
* @author frank
* @version 1.0
* @project practice
* @description 地铁进出服务提供者接口实现类
* @date 2023/8/12 09:48:23
*/
public class SubWayProviderImpl implements SubwayProviderInterface {
//static 只会访问一次 第一次反射的时候可以访问一次,后面再次new的就不会访问了
static {
ServiceManager.registerProvider("一卡通",new SubWayProviderImpl());
}
@Override
public SubWayServiceInterface getSubwayService() {
return new SubWayServiceImpl();
}
}
#SubWayServiceImpl.java
package serviceProvider.oneCard;
import serviceProvider.SubWayServiceInterface;
/**
* @author frank
* @version 1.0
* @project practice
* @description 进出地铁服务接口实现类
* @date 2023/8/12 09:48:23
*/
public class SubWayServiceImpl implements SubWayServiceInterface {
@Override
public boolean in() {
//TODO
System.out.println("这是一卡通in:AAAAAA");
return false;
}
@Override
public boolean out() {
//TODO
System.out.println("这是一卡通out:BBBBBB");
return false;
}
}
4.如何管理不同的服务提供商,这个就需要同一个管理,就需要一个ServiceManager,向ServiceManager注册自己的API,并由ServiceManger同一个管理和调用。
package serviceProvider;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author frank
* @version 1.0
* @project practice
* @description 服务提供者注册类
* @date 2023/8/12 09:48:23
*/
public class ServiceManager {
private ServiceManager() {
}
private static final Map<String, SubwayProviderInterface> providers = new ConcurrentHashMap<String, SubwayProviderInterface>();
public static void registerProver(String name, SubwayProviderInterface p) {
//添加不同的服务提供商的API,并只生成一次,永久添加的是Provider。
providers.put(name, p);
}
public static SubWayServiceInterface getSubWayService(String name) {
SubwayProviderInterface p = providers.get(name);
//如果没有添加就进行访问就报错
if (p == null) {
throw new IllegalArgumentException(
"No provider registered with name:" + name);
}
return p.getSubwayService();
}
}
5.测试类
在通过类路径反射进行生成类的时候,会调用该类的static代码体里面代码,进行API的注册,这样就可以保持Provider只注册一次,任何时候就可以使用。最后通过Name,获取到对应的实例。
package serviceProvider;
public class text {
public static void main(String[] args) throws ClassNotFoundException {
//反射,调用类,而不是用实例化,向ServiceManager进行注册API
Class.forName("serviceProvider.oneCard.SubWayProviderImpl");
SubWayServiceInterface swi = ServiceManager.getSubWayService("一卡通");
swi.in();
swi.out();
}
}
最后这里可以看到输出效果: