服務提供者框架是指:多個服務提供者實現一個服務,系統爲客戶端提供多個實現,並把他們從多個實現中解耦出來。服務提供者的改變對它們的客戶端是透明的,這樣提供了更好的可擴展性。例如,JDBC,JMS等就是用了服務提供者框架java
他們之間的關係以下圖:mysql
1.服務具體實現類和服務提供者實現類是服務提供者本身去實現。以JDBC爲例,這2個模塊由具體的數據庫提供商來實現。sql
2.其餘三個模塊是java對數據庫提供商怎麼實現上面2個模塊的一個約束。好比:提供服務者實現類必須實現服務提供者接口。才能成功註冊到服務提供者注 冊類。以JDBC爲例,全部的數據庫提供商只須要按照接口裏面定義的規則來操做,都能成功地使java連上他們的數據庫。數據庫
下面以mysql數據庫爲例簡單說明一下mysql數據庫提供商是如何實現這些接口的。編程
1.咱們在java中獲取mysql鏈接對象源代碼以下:框架
Class.forName("com.mysql.jdbc.Driver"); 測試
DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123"); url
從這個地方能夠看出:咱們只須要更換數據庫的驅動名稱與創建鏈接的URL,用戶名等信息,就能夠徹底切換到另一個數據庫。數據庫底部怎麼操做的咱們不清 楚,也不必清楚。咱們獲取的鏈接對象是Connection,查看java.sql.Connection這個類,會發現它只是一個接口。咱們獲得的只 是一個接口,怎麼可能可以操做數據庫呢?其實這裏獲得的不是Connection接口,而是它的一個實現類,只是對於客戶端不可見而已。這可能就是所謂的 面向接口編程,客戶端只須要知道它該知道的信息,服務端告訴客戶端,你能夠調用哪些方法。至於具體方法怎麼實現是服務端的事情,客服端就不須要管,也不需 要知道了。spa
下面咱們看看簡單的這2個語句分別作了什麼事情:
語句一: Class.forName("...")。這樣一個語句會實例化一個com.mysql.jdbc.Driver類(提供服務者實現類),並將這個類的實例註冊到DriverManager(服務提供者註冊類)。
語句二: 經過創建鏈接的URL,用戶名,密碼來獲取創建到mysql數據庫的鏈接。是這樣的,DriverManager經過你傳進來的url信息判斷出你是要獲 取那個服務提供者提供的服務。也就是語句一已經將提供服務者實現類註冊到DriverManager了,DriverManager獲取到這個服務提供者 實現類對象以後,經過調用它的getService(mysql裏面是connect方法)方法獲取到服務具體實現類對象,返回的倒是 java.sql.Connection接口對象(由於服務具體實現類實現了Connection接口),這樣把服務具體實現類對象隱藏了。提供了很好的 擴展性。
最後,咱們本身來測試一個。
以北京地鐵進出控制爲例:如今北京地鐵進出都是刷卡,有二種卡:1.一卡通(好比一次性衝值50元,進地鐵刷一次,出地鐵刷一次,扣2元)。2.一次性卡 (進地鐵刷一次,出地鐵插入回收。)這2種卡均可以實現進出地鐵功能,但實現的具體方法是有區別的:一卡通:須要獲取這卡餘額是多少,而後扣掉2元。若是 餘額不足2元怎麼處理等。一次性卡則不必了。
服務接口源碼:
/**
* 進出地鐵服務接口
* @author Administrator
*
*/
public interface SubWayInterface {
//進入地鐵
public boolean in();
//出地鐵
public boolean out();
}
服務實現源碼:
/**
* 一卡通地鐵進出服務實現
* @author Administrator
*
*/
public class SubWayImpl implements SubWayInterface {
public boolean in() {
System.out.println("經過一卡通進入地鐵");
/**
* 進行一些處理,而後返回是否放行
*/
return false;
}
public boolean out() {
System.out.println("經過一卡通出地鐵");
/**
* 進行一些處理,而後返回是否放行
*/
return false;
}
}
服務提供者接口源碼:
/**
* 地鐵進出服務提供者接口
* @author Administrator
*
*/
public interface SubwayProviderInterface {
public SubWayInterface getService();
}
服務提供者接口實現源碼:
/**
* 服務提供者實現類
* @author Administrator
*
*/
public class SubwayProviderImpl implements SubwayProviderInterface {
static {
ServiceManager.registerProvider("一卡通", new SubwayProviderImpl());
}
public SubWayInterface getService() {
return new SubWayImpl();
}
}
服務提供者註冊類實現源碼:
/**
* 服務提供者註冊類
*
* @author Administrator
*
*/
public class ServiceManager {
private ServiceManager() {
}
private static final Map<String, SubwayProviderInterface> providers = new ConcurrentHashMap<String, SubwayProviderInterface>();
public static void registerProvider(String name, SubwayProviderInterface p) {
providers.put(name, p);
}
public static SubWayInterface getService(String name) {
SubwayProviderInterface p = providers.get(name);
if (p == null) {
throw new IllegalArgumentException(
"No provider registered with name:" + name);
}
return p.getService();
}
}
客戶端測試類:
Java代碼
/**
* 客戶端測試類
* @author Administrator
*
*/
public class Test {
/**
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("cn.netjava.cgl.subway.SubwayProviderImpl");
SubWayInterface swi = ServiceManager.getService("一卡通");
swi.in();
swi.out();
}
}
測試類Class.forName("")裏面的參數你可能跟個人不一樣,看你服務提供者實現類放在哪一個包下面了。個人是在:cn.netjava.cgl.subway包下面。