JDK原始碼分析——Java的SPI機制分析與實戰
重點提示:在我部落格中的所有的原始碼分析的例項,我都將會放到github上,感興趣的朋友可以下載下來除錯執行,我相信還是可以有所收穫的。我的目的是讓所有讀到我部落格的朋友都可以瞭解到有價值的東西,學習到java核心的原理,使用起來更加得心應手。
所有例項的GitHub地址:https://github.com/mh47838704/JavaExample ,我會不定期的更新程式碼,所有大家可以長期關注一下。
前一段時間公司內部領導希望我們目前的產品的後臺開發使用微服務,讓我們調研分析一下,與此同時有朋友公司在使用dubbo,所以打算看看dubbo。
首先去dubbo的官網看一下官網的文件,文件描述的很詳細,對dubbo的整體的架構、運維部署、擴充套件機制等都做了詳細的介紹。並提出如何使用Java開發出穩定產品的一些心得體會,這些心得體會讓我深有同感,所以推薦大家也去看看,另外還強烈推薦把《Effective Java》反覆研讀。
在瞭解了dubbo的框架和設計順便下載了dubbo的原始碼看了之後呢,裡面有一個spi機制在之前沒有接觸過,通過檢視java的官方文件瞭解到這種機制也是java提供的一種可擴充套件的一種程式設計機制,通過這種機制類似於外掛機制,非常方便程式的擴充套件。
SPI機制分析
如果英文好而且又對Java理解的很深的,可以直接檢視oracle的官網的介紹https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html ,在該篇文章中對什麼是spi、spi的優點、如何開發自己的spi都進行詳細的介紹。本篇文章將按照官方的文件,設計並測試相應的spi例項,並通過介面和spi對比測試來區分兩者之間的區別。
首先我們定義一個HelloService的介面,並編寫兩個實現類,類的關係如下圖所示
HelloService.java
package com.mh.JavaExample.spi.imp;
/**
* SPI機制分析例項
* Start at: 2018/5/1 16:14
*
* @author muhong
*/
public interface HelloService {
void sayHello();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
ChinaHelloService.java
package com.mh.JavaExample.spi.imp;
/**
* 中國式的招呼
* Start at: 2018/5/1 16:17
*
* @author muhong
*/
public class ChinaHelloService implements HelloService {
@Override
public void sayHello() {
System.out.println("你好,世界!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
AmericaHelloService.java
package com.mh.JavaExample.spi.imp;
/**
* 美國式的招呼
* Start at: 2018/5/1 16:18
*
* @author muhong
*/
public class AmericaHelloService implements HelloService {
@Override
public void sayHello() {
System.out.println("Hello world!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
介面測試:
在我們平常程式設計的時候,我們使用統一介面自定義實現的方式進行擴充套件,下面是基於介面的實現方式:
package com.mh.JavaExample.spi;
import com.mh.JavaExample.spi.imp.AmericaHelloService;
import com.mh.JavaExample.spi.imp.ChinaHelloService;
import com.mh.JavaExample.spi.imp.HelloService;
import org.junit.Test;
/**
* 測試介面
* Start at: 2018/5/1 16:22
*
* @author muhong
*/
public class TestMain {
@Test
public void testInterface(){
HelloService ch = new ChinaHelloService();
ch.sayHello();
HelloService en = new AmericaHelloService();
en.sayHello();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
基於SPI的擴充套件的測試
package com.mh.JavaExample.spi;
import org.junit.Test;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* 測試SPI
* 關於SPI的jar包的打包方式,可以參考oracle的官網說明:https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html
* 本次SPI的測試jar包也是參考該說明打包的:
* 1、和spi相關的class檔案拷貝到一個臨時目錄下/tmp(使用者自定建立,和打包無關)
* 2、在該目錄下建立META-INF目錄,在META-INF目錄下建立services目錄,在目錄下建立com.mh.JavaExample.spi.HelloService檔案
* 3、在該檔案中輸入SPI介面的名字,如com.mh.JavaExample.spi.AmericaHelloService
* 4、進入到臨時根目錄/tmp中,執行命令jar cvf AmericaHelloService.jar -C . .
* 5、在該根目錄下就可以看到AmericaHelloService.jar了
* Start at: 2018/5/1 17:25
*
* @author muhong
*/
public class TestMain2 {
@Test
public void testSpi(){
ServiceLoader<HelloService> services = ServiceLoader.load(HelloService.class);
for (Iterator<HelloService> iterator = services.iterator(); iterator.hasNext(); ) {
HelloService helloService = iterator.next();
helloService.sayHello();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
原始碼分析
相關的原始碼我已經放到github上了,下面是和該例項相關的類和jar包,通過分析執行這些類和jar包可以對該機制有深入的瞭解,下面是程式碼結構圖:
在上面的圈中的檔案中:
test目錄下的spi.imp中的程式碼檔案是用於介面測試的。
在lib中的三個jar包是用於spi測試的,其中HelloService.jar是屬於介面包,ChinaHelloService.jar和AmericaHelloService.jar是SPI的實現類,編寫打包的格式如下:
總結
通過閱讀oracle官方的介紹,可以完成自定義spi的開發,如果英文不是特別好的朋友,可以先查閱相關的部落格資料,然後結合我的程式碼去除錯即可有深入的瞭解。
---------------------
作者:m47838704
來源:CSDN
原文:https://blog.csdn.net/m47838704/article/details/80160985
版權宣告:本文為博主原創文章,轉載請附上博文連結!