ServiceLoader與ClassLoader是Java中2個即相互區別又相互聯繫的加載器.JVM利用ClassLoader將類載入內存,這是一個類聲明週期的第一步(一個java類的完整的生命週期會經歷加載、鏈接、初始化、使用、和卸載五個階段,固然也有在加載或者鏈接以後沒有被初始化就直接被使用的狀況)。詳情請參閱:詳解Java類的生命週期 html
那ServiceLoader又是什麼呢?ServiceLoader:一個簡單的服務提供者加載設施。服務 是一個熟知的接口和類(一般爲抽象類)集合。服務提供者 是 服務的特定實現。提供者中的類一般實現接口,並子類化在服務自己中定義的子類。服務提供者能夠以擴展的形式安裝在 Java 平臺的實現中,也就是將 jar 文件放入任意經常使用的擴展目錄中。也可經過將提供者加入應用程序類路徑,或者經過其餘某些特定於平臺的方式使其可用。……惟一強制要求的是,提供者類必須具 有不帶參數的構造方法,以便它們能夠在加載中被實例化。 java
經過在資源目錄META-INF/services中放置提供者配置文件 來標識服務提供者。文件名稱是服務類型的徹底限定二進制名稱。該文件包含一個具體提供者類的徹底限定二進制名稱列表,每行一個。忽略各名稱周圍的空格、製表符和空行。註釋字符爲'#'('\u0023', NUMBER SIGN);忽略每行第一個註釋字符後面的全部字符。文件必須使用 UTF-8 編碼。
web
以延遲方式查找和實例化提供者,也就是說根據須要進行。服務加載器維護到目前爲止已經加載的提供者緩存。每次調用 iterator 方法返回一個迭代器,它首先按照實例化順序生成緩存的全部元素,而後以延遲方式查找和實例化全部剩餘的提供者,依次將每一個提供者添加到緩存。能夠經過 reload 方法清除緩存。 緩存
首 先這個類是 final 不能繼承的。常常咱們會有一個接口許多實現類,好比: UserDao接口有UserDaoImpl1 、UserDaoImpl2 ....等多個實現。這時候咱們只能本身new,可是有了ServiceLoader<S>就很是方便,他會幫咱們把實現類放入一個集合方便 遍歷 。可是這又有什麼用呢,這個配合命令模式就有大用了: 編碼
首先在src文件夾下面建立一個META-INF文件夾裏面再建立一個services文件夾裏面放着一個你接口的全類名 的文件 好比 org.web.UserDao spa
而文件裏面放着這個接口的實現類 好比 org.web.UserDaoImpl1 org.web.UserDaoImpl2 .net
而後一句代碼就OK了
code
ServiceLoader<UserDao>list=ServiceLoader.load(UserDao.class);
而後就能夠遍歷list了 htm
接下來介紹一下這個ServiceLoader的經常使用用途 對象
好比咱們要判斷傳過來來的值是什麼類型的
if(a == 1){ //處理的事 } else if(a == 2){ //處理的事 }else if(a == 2){ //處理的事 }
這樣的話之後多一種狀況就多一種else if 不利於擴展
因此能夠把每一個if 作成命令模式
首先建立一個藉口 Interface
public interface inte{ //判斷是否用這個實現類的解決方案 public boolean is(int num); //解決方案 public void result(); }
而後建立2個實現類
public class inteImpl1 implements inte{ public boolean is(int num){ //代替了多重if if(num == 1) return true; return false; } public void result(){ //這裏是 1的解決方案 } }
public class inteImpl2 implements inte{ public boolean is(int num){ //代替了多重if if(num == 2) return true; return false; } public void result(){ //這裏是 2的解決方案 } }
寫好services裏面的對應接口和實現類的全類名:
xx.xx.inteImpl1 xx.xx.inteImpl2
而後就可使用了:
ServiceLoader<Inte> list=ServiceLoader.load(Inte.class); for(Inte in :list){ if(in.is(1)){ in.result(); } }
這樣之後要擴展就多寫一個實現類,多加一項配置,更好的體現了面向對象的思想。