SPI框架實(shí)現(xiàn)之旅三:實(shí)現(xiàn)說明
前一篇 《SPI框架實(shí)現(xiàn)之旅二:整體設(shè)計(jì)》中浩考,介紹了幾個(gè)定義的接口婶肩,注解;敘述了實(shí)現(xiàn)流程说搅;并簡(jiǎn)單的介紹了
SpiLoader
中的部分實(shí)現(xiàn)炸枣; 本篇?jiǎng)t主要介紹SpiLoader
類的實(shí)現(xiàn)
類圖結(jié)構(gòu)如下:
SpiLoader 全解析
spiImpl選擇的核心類,包括初始化選擇器,初始化spiImpl實(shí)現(xiàn)列表适肠,解析spiImpl的選擇條件霍衫,返回具體的實(shí)現(xiàn)類等
1. 獲取spiLoader對(duì)象
SpiLoader
是一個(gè)泛型對(duì)象,每個(gè)SPI接口侯养,對(duì)應(yīng)一個(gè)SpiLoader<T>
對(duì)象敦跌,我們提供了一個(gè)靜態(tài)方法來(lái)獲取這個(gè)對(duì)象
實(shí)現(xiàn)
優(yōu)先從緩存中獲取, 如果緩存沒有逛揩,則新建一個(gè)柠傍;緩存中有, 則直接返回
/**
* spiLoader緩存, 其中key為 spi接口, value為對(duì)應(yīng)的Loader對(duì)象
*/
private static final ConcurrentMap<Class<?>, SpiLoader<?>> loaderCache = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public static <T> SpiLoader<T> load(Class<T> type) {
if (null == type) {
throw new IllegalArgumentException("common cannot be null...");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("common class:" + type + " must be interface!");
}
if (!withSpiAnnotation(type)) {
throw new IllegalArgumentException("common class:" + type + " must have the annotation of @Spi");
}
SpiLoader<T> spiLoader = (SpiLoader<T>) loaderCache.get(type);
if (spiLoader == null) {
loaderCache.putIfAbsent(type, new SpiLoader<>(type));
spiLoader = (SpiLoader<T>) loaderCache.get(type);
}
return spiLoader;
}
說明
- 上面有幾個(gè)校驗(yàn)辩稽,前一篇已經(jīng)說明惧笛,不再贅述
- 上面新建對(duì)象,不是線程安全的
2. 新建 SpiLoader
對(duì)象
創(chuàng)建對(duì)象逞泄,主要會(huì)初始化選擇器
實(shí)現(xiàn)
private SpiLoader(Class<T> type) {
// 初始化默認(rèn)的選擇器, 為保留項(xiàng)目, 必然會(huì)提供的服務(wù)
selectorInstanceCacheMap.putIfAbsent(DefaultSelector.class, DEFAULT_SELECTOR);
this.spiInterfaceType = type;
initSelector();
}
private void initSelector() {
Spi ano = spiInterfaceType.getAnnotation(Spi.class);
if (ano == null) {
currentSelector = initSelector(DefaultSelector.class);
} else {
currentSelector = initSelector(ano.selector());
}
Method[] methods = this.spiInterfaceType.getMethods();
currentMethodSelector = new ConcurrentHashMap<>();
SelectorWrapper temp;
for (Method method : methods) {
if (!method.isAnnotationPresent(SpiAdaptive.class)) {
continue;
}
temp = initSelector(method.getAnnotation(SpiAdaptive.class).selector());
if (temp == null) {
continue;
}
currentMethodSelector.put(method.getName(), temp);
}
}
private SelectorWrapper initSelector(Class<? extends ISelector> clz) {
// 優(yōu)先從選擇器緩存中獲取類型對(duì)應(yīng)的選擇器
if (selectorInstanceCacheMap.containsKey(clz)) {
return selectorInstanceCacheMap.get(clz);
}
try {
ISelector selector = clz.newInstance();
Class paramClz = null;
Type[] types = clz.getGenericInterfaces();
for (Type t : types) {
if (t instanceof ParameterizedType) {
paramClz = (Class) ((ParameterizedType) t).getActualTypeArguments()[0];
break;
}
}
Assert.check(paramClz != null);
SelectorWrapper wrapper = new SelectorWrapper(selector, paramClz);
selectorInstanceCacheMap.putIfAbsent(clz, wrapper);
return wrapper;
} catch (Exception e) {
throw new IllegalArgumentException("illegal selector defined! yous:" + clz);
}
}
說明
- 持有一個(gè)選擇器緩存列表患整,
selectorInstanceCacheMap
- 保證每種類型的選擇器,在這個(gè)SpiLoader中炭懊,只會(huì)有一個(gè)實(shí)例存在
- 不做成全局唯一的原因是盡量隔離, 比如
ParamsSelector
內(nèi)部緩存了spi實(shí)現(xiàn)的列表并级,如果全局公用的話,就會(huì)混掉侮腹,導(dǎo)致這個(gè)列表中就出現(xiàn)非這個(gè)spi接口的實(shí)現(xiàn)類
- 類選擇器 + 方法選擇器
-
currentSelector
: 類選擇器, 解析@Spi
注解獲取嘲碧,適用于靜態(tài)選擇 + 動(dòng)態(tài)選擇兩種使用方式 -
currentMethodSelector
: 方法選擇器,解析@SpiAdaptive
注解獲取父阻, 僅適用于動(dòng)態(tài)選擇SPI實(shí)現(xiàn)的方式 - 優(yōu)先級(jí): 方法上定義的選擇器 由于 類上定義的選擇器愈涩; 方法上未定義時(shí),默認(rèn)使用類定義的選擇器
-
3. 靜態(tài)使用
靜態(tài)使用方式加矛,表示根據(jù)傳入的條件履婉,選擇一個(gè)滿足條件的實(shí)現(xiàn)返回
實(shí)現(xiàn)
/**
* 根據(jù)傳入條件, 選擇具體的spi實(shí)現(xiàn)類
* <p/>
* 這里要求conf的類型和選擇器的參數(shù)類型匹配, 否則會(huì)嘗試使用默認(rèn)的選擇器補(bǔ)救, 若補(bǔ)救失敗, 則拋異常
*
* @param conf
* @return
* @throws NoSpiMatchException
* @throws IllegalArgumentException
*/
@SuppressWarnings("unchecked")
public T getService(Object conf) throws NoSpiMatchException {
if (spiImplClassCacheMap == null || spiImplClassCacheMap.size() == 0) {
loadSpiService();
}
if (!currentSelector.getConditionType().isAssignableFrom(conf.getClass())) {
/**
* 參數(shù)類型不匹配時(shí), 判斷是否可以根據(jù)默認(rèn)的選擇器來(lái)獲取
*/
if (conf instanceof String) {
return (T) DEFAULT_SELECTOR.getSelector().selector(spiImplClassCacheMap, conf);
}
/**
* 參數(shù)類型完全不匹配, 則拋參數(shù)異常
*/
throw new IllegalArgumentException("conf spiInterfaceType should be sub class of [" + currentSelector.getConditionType() + "] but yours:" + conf.getClass());
}
return (T) currentSelector.getSelector().selector(spiImplClassCacheMap, conf);
}
說明
-
spiImplClassCacheMap
spi實(shí)現(xiàn)的緩存映射表,優(yōu)先判斷緩存映射表是否存在斟览,不存在時(shí)需要初始化毁腿;存在時(shí),則進(jìn)入校驗(yàn)邏輯
-
校驗(yàn)
校驗(yàn)傳入的參數(shù)苛茂,是否匹配當(dāng)前的選擇器參數(shù)類型已烤,為了保證選擇器可以正常運(yùn)行
當(dāng)不匹配時(shí),會(huì)有一個(gè)兼容邏輯妓羊,判斷傳參類型是否為String胯究, 是則采用默認(rèn)的選擇器,根據(jù)name來(lái)選擇spi實(shí)現(xiàn) (這種實(shí)現(xiàn)可能造成選擇的實(shí)現(xiàn)不是預(yù)期的)
-
靜態(tài)使用方式躁绸,使用類定義選擇器 :
currentSelector
靜態(tài)使用的方式裕循,目標(biāo)就是事前就確認(rèn)使用這個(gè)實(shí)現(xiàn)了臣嚣,不會(huì)出現(xiàn)變動(dòng)了; 相當(dāng)于一次確認(rèn)剥哑,所有的調(diào)用都是確認(rèn)的
-
靜態(tài)使用硅则,方法注解的選擇器無(wú)效。這個(gè)我們從逆向的思路進(jìn)行解釋
IPrint 是一個(gè)Spi接口株婴, 有兩個(gè)實(shí)現(xiàn) FilePrint, ConsolePrint 假設(shè) `currentSelector=DefaultSelector`抢埋, 方法 methodA 上定義的是 ParamsSelector 時(shí) 靜態(tài)使用方式,獲取一個(gè)spi實(shí)現(xiàn)督暂,希望在所有的spi接口使用處揪垄,都輸出到文件,用戶根據(jù) `FilePrint` 選擇 FilePrint 這個(gè)類來(lái)執(zhí)行具體的輸出邏輯逻翁, 如果在調(diào)用 methodA 方法執(zhí)行時(shí)饥努, 假設(shè)根據(jù) ParamsSelector 判斷, ConsolePrint 才滿足這兒條件八回,這是相當(dāng)于在具體實(shí)現(xiàn)時(shí)酷愧,換成了另一個(gè) ConsolePrint, 這下子就與我們的初衷背離了(如果目標(biāo)是想實(shí)現(xiàn)這個(gè)場(chǎng)景,顯然動(dòng)態(tài)適配的方式才是正確的使用姿勢(shì))
loadService 的邏輯后面詳細(xì)說明
4. 動(dòng)態(tài)使用
動(dòng)態(tài)使用區(qū)別于靜態(tài)的直接確定實(shí)現(xiàn)類缠诅, 通過
getService
獲取的并不是某個(gè)特定對(duì)的實(shí)現(xiàn)類溶浴,而是一個(gè)動(dòng)態(tài)生成的代理,每次具體執(zhí)行之前管引,會(huì)去判斷一下士败,應(yīng)該選擇哪一個(gè)實(shí)現(xiàn)來(lái)執(zhí)行
設(shè)計(jì)的出發(fā)點(diǎn)
可以考慮下,我們的目標(biāo)是在執(zhí)行方法之前褥伴,需要判斷一下哪個(gè)實(shí)現(xiàn)類滿足要求谅将,選擇這個(gè)實(shí)現(xiàn)類來(lái)執(zhí)行這個(gè)方法,那么我們可以怎么去做重慢?
考慮到切面的方式饥臂,如果有一種手段,在方法執(zhí)行之前似踱,織入一段業(yè)務(wù)邏輯隅熙,就可以達(dá)到上面的目的
最開始雖然是怎么想的,但是有點(diǎn)尷尬的是核芽,不知道怎么去實(shí)現(xiàn)囚戚;因此換了一個(gè)思路,我自己新生成一個(gè)接口的實(shí)現(xiàn)類狞洋,在這個(gè)實(shí)現(xiàn)類里面做選擇邏輯弯淘,然后把這個(gè)實(shí)現(xiàn)類對(duì)象返回
實(shí)現(xiàn)如下
和靜態(tài)實(shí)現(xiàn)的邏輯差不多绿店,一般流程如下:
- 判斷spi實(shí)現(xiàn)類的映射關(guān)系表是否初始化吉懊,若沒有則初始化
- 獲取選擇器
- 優(yōu)先從方法選擇器中查找庐橙, 若存在,則直接選中借嗽;
- 不存在态鳖,則使用類選擇器
- 校驗(yàn):判斷傳入條件參數(shù)類型是否滿足選擇器的參數(shù)類型匹配(將方法的第一個(gè)參數(shù),作為選擇器的選擇條件)
- 返回實(shí)現(xiàn)類
@SuppressWarnings("unchecked")
public T getService(Object conf, String methodName) throws NoSpiMatchException {
if (spiImplClassCacheMap == null || spiImplClassCacheMap.size() == 0) {
loadSpiService();
}
// 首先獲取對(duì)應(yīng)的selector
SelectorWrapper selector = currentMethodSelector.get(methodName);
if (selector == null) { // 自適應(yīng)方法上未定義選擇器, 則默認(rèn)繼承類的
selector = currentSelector;
currentMethodSelector.putIfAbsent(methodName, selector);
}
if (!selector.getConditionType().isAssignableFrom(conf.getClass())) { // 選擇器類型校驗(yàn)
if (!(conf instanceof String)) {
throw new IllegalArgumentException("conf spiInterfaceType should be sub class of [" + currentSelector.getConditionType() + "] but yours:" + conf.getClass());
}
selector = DEFAULT_SELECTOR;
}
if (spiImplMethodCacheMap.size() == 0) {
return (T) selector.getSelector().selector(spiImplClassCacheMap, conf);
}
try {
// 采用默認(rèn)的選擇器,根據(jù)指定name 進(jìn)行查詢時(shí), 需要兼容一下, 因?yàn)閙ethod對(duì)應(yīng)的緩存key為 SpiImpName_methodName
if (DEFAULT_SELECTOR.equals(selector)) {
if (spiImplMethodCacheMap.containsKey(conf)) {
return (T) selector.getSelector().selector(spiImplMethodCacheMap, conf);
}
if (spiImplClassCacheMap.containsKey(conf)) {
return (T) selector.getSelector().selector(spiImplClassCacheMap, conf);
}
return (T) selector.getSelector().selector(spiImplMethodCacheMap, conf + "_" + methodName);
} else {
return (T) selector.getSelector().selector(spiImplMethodCacheMap, conf);
}
} catch (Exception e) {
return (T) selector.getSelector().selector(spiImplClassCacheMap, conf);
}
}
說明
這個(gè)方法通常是由框架生成的代理實(shí)現(xiàn)類來(lái)調(diào)用(后面會(huì)說明動(dòng)態(tài)生成代理類的邏輯)
區(qū)別與靜態(tài)使用方式恶导, 優(yōu)先根據(jù)方法名浆竭,查找對(duì)應(yīng)的選擇器;當(dāng)未定義時(shí)惨寿,使用類選擇器
-
默認(rèn)選擇器邦泄,根據(jù)name來(lái)查詢實(shí)現(xiàn)時(shí),傳入的參數(shù)特殊處理下裂垦,主要是因?yàn)?
spiImplMethodCacheMap
中key的生成顺囊,有一個(gè)小轉(zhuǎn)換若實(shí)現(xiàn)類上沒有 @SpiConf注解,或者 @SpiConf的注解沒有定義 name 屬性蕉拢,則類的唯一標(biāo)識(shí)name為:簡(jiǎn)單類名特碳; 否則為指定的name屬性 若方法上顯示使用 @SpiConf 指定了name屬性,則key的生成規(guī)則為: 方法注解上指定的name晕换; 如果沒有 @SpiConf注解午乓,或其中沒有指定name屬性,則key生成規(guī)則: 類name屬性 + 下劃線 + 方法名
這一點(diǎn)單獨(dú)看可能不太好理解闸准,因此可以和下面的spi實(shí)現(xiàn)類映射關(guān)系的初始化結(jié)合起來(lái)
動(dòng)態(tài)生成代理類的邏輯益愈,放在最后進(jìn)行說明
5. spi實(shí)現(xiàn)類映射關(guān)系表初始化
為了避免每次選擇具體的實(shí)現(xiàn)類時(shí),都去加載一遍夷家,耗時(shí)耗力好性能腕唧,因此加一個(gè)緩存是很有必要的,這里主要說下這個(gè)實(shí)現(xiàn)邏輯瘾英,以及為啥這么干
緩存結(jié)構(gòu)
使用了兩個(gè)Map:
- 一個(gè)是類級(jí)別的映射關(guān)系
spiImplClassCacheMap
- 靜態(tài)使用時(shí)枣接,只會(huì)用搞這個(gè)
- 動(dòng)態(tài)適配時(shí),當(dāng)下面的映射關(guān)系中無(wú)法獲取滿足條件的實(shí)現(xiàn)時(shí)缺谴,會(huì)再次從這里進(jìn)行判斷
- key:
@SpiConf
注解中定義的name但惶; 或者spi實(shí)現(xiàn)類的簡(jiǎn)單類名
- 一個(gè)是方法的映射關(guān)系
spiImplMethodCacheMap
- 動(dòng)態(tài)適配時(shí), 選擇器優(yōu)先從這里進(jìn)行判斷
- key:
@SpiConf
注解中定義的name湿蛔; 或者是 實(shí)現(xiàn)類的 name + "_" + 方法名
/**
* name : spiImpl 的映射表
*/
private Map<String, SpiImplWrapper<T>> spiImplClassCacheMap;
/**
* 自適應(yīng)時(shí), 根據(jù)方法選擇實(shí)現(xiàn); name : spiImpl 的映射表
*/
private Map<String, SpiImplWrapper<T>> spiImplMethodCacheMap;
實(shí)現(xiàn)
private void loadSpiService() {
List<SpiImplWrapper<T>> spiServiceList = new ArrayList<>();
List<SpiImplWrapper<T>> spiServiceMethodList = new ArrayList<>();
ServiceLoader<T> serviceLoader = ServiceLoader.load(spiInterfaceType);
SpiConf spiConf;
String implName;
int implOrder;
for (T t : serviceLoader) {
spiConf = t.getClass().getAnnotation(SpiConf.class);
Map<String, String> map;
if (spiConf == null) {
implName = t.getClass().getSimpleName();
implOrder = SpiImplWrapper.DEFAULT_ORDER;
// 參數(shù)選擇器時(shí), 要求spi實(shí)現(xiàn)類必須有 @SpiConf 注解, 否則選擇器無(wú)法獲取校驗(yàn)條件參數(shù)
if (currentSelector.getSelector() instanceof ParamsSelector) {
throw new IllegalStateException("spiImpl must contain annotation @SpiConf!");
}
map = Collections.emptyMap();
} else {
implName = spiConf.name();
if (StringUtils.isBlank(implName)) {
implName = t.getClass().getSimpleName();
}
implOrder = spiConf.order() < 0 ? SpiImplWrapper.DEFAULT_ORDER : spiConf.order();
map = parseParms(spiConf.params());
}
// 添加一個(gè)類級(jí)別的封裝類
spiServiceList.add(new SpiImplWrapper<>(t, implOrder, implName, map));
// todo 改成 getMethods(), 但是過濾掉 Object類中的基礎(chǔ)方法
Method[] methods = t.getClass().getDeclaredMethods();
String methodImplName;
int methodImplOrder;
Map<String, String> methodParams;
for (Method method : methods) {
spiConf = method.getAnnotation(SpiConf.class);
if (spiConf == null) {
continue;
}
// 方法上有自定義注解, 且定義的name與類實(shí)現(xiàn)名不同, 則直接采用
// 否則采用 ServiceName_MethodName 方式定義
if (StringUtils.isBlank(spiConf.name()) || implName.equals(spiConf.name())) {
methodImplName = implName + "_" + method.getName();
} else {
methodImplName = spiConf.name();
}
// 優(yōu)先級(jí), 以最小的為準(zhǔn) (即一個(gè)類上的優(yōu)先級(jí)很低, 也可以定義優(yōu)先級(jí)高的方法)
// 方法注解未定義順序時(shí), 繼承類上的順序
methodImplOrder = Math.min(implOrder, spiConf.order() < 0 ? implOrder : spiConf.order());
// 自適應(yīng)方法的參數(shù)限制, 要求繼承類上的參數(shù)
methodParams = parseParms(spiConf.params());
if (map.size() > 0) { // 方法的參數(shù)限定會(huì)繼承類上的參數(shù)限定
if (methodParams.size() == 0) {
methodParams = map;
} else {
methodParams.putAll(map);
}
}
spiServiceMethodList.add(new SpiImplWrapper<>(t, methodImplOrder, methodImplName, methodParams));
}
}
if (spiServiceList.size() == 0) {
throw new IllegalStateException("no spiImpl implements spi: " + spiInterfaceType);
}
this.spiImplClassCacheMap = initSpiImplMap(spiServiceList);
this.spiImplMethodCacheMap = initSpiImplMap(spiServiceMethodList);
}
private Map<String, SpiImplWrapper<T>> initSpiImplMap(List<SpiImplWrapper<T>> list) {
// 映射為map, 限定不能重名
Map<String, SpiImplWrapper<T>> tempMap = new ConcurrentHashMap<>();
for (SpiImplWrapper<T> wrapper : list) {
if (tempMap.containsKey(wrapper.getName())) {
throw new IllegalArgumentException("duplicate spiImpl name " + wrapper.getName());
}
tempMap.put(wrapper.getName(), wrapper);
}
return tempMap;
}
上面的邏輯可以分為兩塊膀曾,一塊是上半邊的初始化,獲取spiImplClassCacheMap
;
下一塊則是掃描實(shí)現(xiàn)類的所有方法阳啥,將方法上標(biāo)有@SpiConf
注解的撈出來(lái)添谊,用于初始化 spiImplMethodCacheMap
說明
-
緩存結(jié)構(gòu)中value為
SpiImplWrapper
-
緩存value并不是簡(jiǎn)單的實(shí)現(xiàn)類,封裝類的定義如下察迟,將條件和排序也同時(shí)封裝進(jìn)去了
private T spiImpl; private int order; /** * spiImpl 的標(biāo)識(shí)name, 要求唯一 * <p/> * {@link com.hust.hui.quicksilver.spi.selector.DefaultSelector 選擇具體的SpiImpl 時(shí)使用} */ private String name; /** * 參數(shù)校驗(yàn)規(guī)則 * <p/> * {@link com.hust.hui.quicksilver.spi.selector.ParamsSelector} 選擇具體的SpiImpl 時(shí)使用 * 要求每個(gè)實(shí)現(xiàn)類都有注解 {@link SpiConf} */ private Map<String, String> paramCondition;
name 的定義斩狱,類與方法兩個(gè)緯度的緩存中耳高,定義規(guī)則不同,具體可以看《緩存結(jié)構(gòu)》這里的說明
-
采用
ParamsSelector
時(shí)所踊, 要求@SpiConf
注解必須存在-
注意掃描所有方法對(duì)應(yīng)的注解, spi實(shí)現(xiàn)類泌枪,如果存在繼承則會(huì)出現(xiàn)問題
// todo 改成 getMethods(), 但是過濾掉 Object類中的基礎(chǔ)方法 Method[] methods = t.getClass().getDeclaredMethods();
動(dòng)態(tài)代碼生成
上面在談?wù)搫?dòng)態(tài)使用的時(shí)候,采用的方案是秕岛,生成一個(gè)代理類碌燕,實(shí)現(xiàn)spi接口, 在具體的實(shí)現(xiàn)邏輯中继薛,使用選擇器來(lái)獲取滿足條件的實(shí)現(xiàn)類修壕,然后執(zhí)行相應(yīng)的方法
1. 代理類格式
采用倒推方式,先給出一個(gè)實(shí)際的代理類如下遏考,具體的實(shí)現(xiàn)中其實(shí)只有兩行代碼
- 獲取具體的實(shí)現(xiàn)類 (調(diào)用上面的
SpiLoader.getService(conf, methodName
) - 執(zhí)行實(shí)現(xiàn)類的接口
package com.hust.hui.quicksilver.spi.test.print;
import com.hust.hui.quicksilver.spi.SpiLoader;
public class IPrint$Proxy implements com.hust.hui.quicksilver.spi.test.print.IPrint {
public void print(java.lang.String arg0) {
try {
com.hust.hui.quicksilver.spi.test.print.IPrint spiImpl = SpiLoader.load(com.hust.hui.quicksilver.spi.test.print.IPrint.class).getService(arg0, "print");
spiImpl.print(arg0);
} catch (com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e) {
throw new java.lang.RuntimeException(e);
}
}
public void adaptivePrint(java.lang.String arg0, java.lang.String arg1) {
try {
com.hust.hui.quicksilver.spi.test.print.IPrint spiImpl = SpiLoader.load(com.hust.hui.quicksilver.spi.test.print.IPrint.class).getService(arg0, "adaptivePrint");
spiImpl.adaptivePrint(arg0, arg1);
} catch (com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e) {
throw new java.lang.RuntimeException(e);
}
}
}
上面給出了一個(gè)代理類的演示叠殷,那么剩下兩個(gè)問題,一個(gè)是如何生成代理類诈皿; 一個(gè)是如何運(yùn)行代理類(上面是java代碼林束,我們知道運(yùn)行得是字節(jié)碼才行)
代理類生成
對(duì)著上面的實(shí)現(xiàn),反推代碼生成稽亏,其實(shí)比較簡(jiǎn)單了壶冒,無(wú)非就是生成一大串的String罷了,這里真沒什么特殊的截歉,貼下實(shí)現(xiàn)胖腾,邏輯省略
/**
* 構(gòu)建SPI接口的實(shí)現(xiàn)代理類, 在執(zhí)行動(dòng)態(tài)適配的方法時(shí), 調(diào)用SpiLoader的 spiImpl選擇器, 選擇具體的實(shí)現(xiàn)類執(zhí)行
*
* @return
*/
public static String buildTempImpl(Class type) {
StringBuilder codeBuilder = new StringBuilder();
codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
codeBuilder.append("\nimport ").append(SpiLoader.class.getName()).append(";");
codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Proxy implements ").append(type.getCanonicalName()).append(" {\n");
Method[] methods = type.getMethods();
for (Method method : methods) {
Class<?> returnType = method.getReturnType(); //函數(shù)返回值
Class<?>[] parameterTypes = method.getParameterTypes();//函數(shù)參數(shù)列表
Class<?>[] exceptionTypes = method.getExceptionTypes();//函數(shù)異常列表
// build method code
StringBuilder code = new StringBuilder(512);
if (parameterTypes.length < 0) { //檢查該函數(shù)參數(shù)列表中,第一個(gè)參數(shù)作為選擇器參數(shù)
code.append("throw new IllegalArgumentException(\"there should be one argument for selector to choose spiImpl\")");
} else { // 沒有 SpiAdaptive注解的, 采用默認(rèn)的注解方式
code.append("try{\n");
code.append(type.getName()).append(" spiImpl=")
.append("SpiLoader.load(")
.append(type.getName()).append(".class")
.append(").getService(arg0,\"")
.append(method.getName())
.append("\");");
if (!"void".equals(returnType.getName())) {
code.append("return ");
}
code.append("spiImpl.").append(method.getName()).append("(arg0");
for (int i = 1; i < parameterTypes.length; i++) {
code.append(",").append("arg").append(i);
}
code.append(");");
code.append("\n} catch(com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e){\nthrow new java.lang.RuntimeException(e);\n}");
}
// build method signature
codeBuilder.append("\npublic ").append(returnType.getName()).append(" ").append(method.getName())
.append("(").append(parameterTypes[0].getName()).append(" arg0");
for (int i = 1; i < parameterTypes.length; i++) {
codeBuilder.append(", ").append(parameterTypes[i].getName()).append(" arg").append(i);
}
codeBuilder.append(") ");
if (exceptionTypes.length > 0) {
codeBuilder.append("throw ").append(exceptionTypes[0].getName());
for (int i = 1; i < exceptionTypes.length; i++) {
codeBuilder.append(", ").append(exceptionTypes[i].getName());
}
}
codeBuilder.append("{\n");
codeBuilder.append(code.toString()).append("\n}");
}
codeBuilder.append("\n}");
return codeBuilder.toString();
}
動(dòng)態(tài)編譯運(yùn)行
動(dòng)態(tài)編譯瘪松,最開始想的是利用jdk的動(dòng)態(tài)編譯方式咸作,試來(lái)試去沒搞成功,然后選擇了一個(gè)折中的方案宵睦,把代理類看成是groovy代碼记罚,利用 GroovyEngine 來(lái)實(shí)現(xiàn)動(dòng)態(tài)運(yùn)行, 這一塊的邏輯也超級(jí)簡(jiǎn)單,下面的短短幾行代碼即可壳嚎; 后面有空單獨(dú)研究下java的動(dòng)態(tài)編譯
@SuppressWarnings("unchecked")
public static <T> T compile(String code, Class<T> interfaceType, ClassLoader classLoader) throws SpiProxyCompileException {
GroovyClassLoader loader = new GroovyClassLoader(classLoader);
Class clz = loader.parseClass(code);
if (!interfaceType.isAssignableFrom(clz)) {
throw new IllegalStateException("illegal proxy type!");
}
try {
return (T) clz.newInstance();
} catch (Exception e) {
throw new SpiProxyCompileException("init spiProxy error! msg: " + e.getMessage());
}
}
4. 其他
博客系列鏈接:
-SPI框架實(shí)現(xiàn)之旅一:背景介紹
-SPI框架實(shí)現(xiàn)之旅二:整體設(shè)計(jì)
-SPI框架實(shí)現(xiàn)之旅三:實(shí)現(xiàn)說明
-SPI框架實(shí)現(xiàn)之旅四:使用測(cè)試
源碼地址:
https://git.oschina.net/liuyueyi/quicksilver/tree/master/silver-spi