SPI簡單解析
阿新 • • 發佈:2020-09-01
什麼是SPI
一種服務載入方式,全名為Service Provider Interface,Service提供者介面
如果我們要抽象裡面的模組,在面對物件程式設計當中,我們模組之間,一般推薦模組之間基於介面程式設計,模組之間不對實現類進行硬編碼。
一旦程式碼裡涉及具體的實現類,就違反了可拔插的原則,如果需要替換一種實現,就需要修改程式碼。
為了實現在模組裝配的時候能不在程式裡動態指明,這就需要一種服務發現機制。
有點類似IOC的思想,就是將裝配的控制權移到程式之外,在模組化設計中這個機制尤其重要。所以SPI的核心思想就是解耦
通俗例子解釋:
例子: JDK中有支援音樂播放,假設只支援mp3的播放,有些廠商想在這個基礎之上支援mp4播放,有的想支援mp5播放, 而這些廠商都是第三方廠商,如果沒有提供SPI這種實現標準,那就只有修改JAVA的原始碼了。 有了SPI標準,JDK的爸爸SUN公司只需要提供一個播放介面,在實現播放的功能上通過ServiceLoad的方式載入服務, 那麼第三方只需要實現這個播放介面,再按SPI標準的約定進行打包,再放到classpath下面就OK了
SPI的機制約定:
1) 在jar包的META-INF/services/目錄中建立以介面全限定名命名的檔案該檔案內容為Api具體實現類的全限定名 2) 服務呼叫方用java.util.ServiceLoader,用服務介面為引數,去動態載入具體的實現類到JVM中 3) 如SPI的實現類為Jar則需要放在主程式classPath中 4) 定義服務的通用介面,針對通用的服務介面,提供具體的實現類
//通用介面, public interface SendMessage { void send(String msg); }
package com.quan.spi.emailimp; import com.quan.spi.api.SendMessage; //通用介面的實現類1 public class SendMessageEmail implements SendMessage { @Override public void send(String msg) { System.out.println("send " + msg +" use email"); } }
package com.quan.spi.phoneimp; import com.quan.spi.api.SendMessage;//通用介面的實現類2 public class SendMessagePhone implements SendMessage { @Override public void send(String msg) { System.out.println("send " +msg +" use phone"); } }
//通過工廠模式去獲得sendmessage public class SendMessageFactory { public SendMessageFactory() { } public static SendMessage getsend(){ SendMessage sendMessage = null; ServiceLoader<SendMessage> sendMessages = ServiceLoader.load(SendMessage.class); Iterator iterator = sendMessages.iterator(); while (iterator.hasNext()){ sendMessage = (SendMessage) iterator.next(); sendMessage.send("quan"); } return sendMessage; } }
META-INF/services:
名字為:com.quan.spi.api.SendMessage
com.quan.spi.emailimp.SendMessageEmail
com.quan.spi.phoneimp.SendMessagePhone
測試:
package com.quan.spi; import com.quan.spi.api.SendMessage; import org.junit.Test; import java.util.ServiceLoader; public class TestMessage { @Test public void Test(){ SendMessageFactory.getsend(); } @Test public void Test2(){ ServiceLoader<SendMessage> sendMessages = ServiceLoader.load(SendMessage.class); for (SendMessage s : sendMessages) { s.send("quanquan"); } } }