前面三篇主要是介紹如何設計的,如何實現的,這一篇,則主要集中在如何使用。實現得再好,若是很差用,也白搭java
本篇介紹幾個簡單的使用case,包括靜態使用,動態適配,自定義選擇器等git
定義一個SPI接口 IPrint
, 兩個實現 FilePrint
, ConsolePrint
微信
@Spi public interface IPrint { void print(String str); } public class FilePrint implements IPrint { @Override public void print(String str) { System.out.println("file print: " + str); } } public class ConsolePrint implements IPrint { @Override public void print(String str) { System.out.println("console print: " + str); } }
添加配置文件 com.hust.hui.quicksilver.spi.test.print.IPrint
, 內容以下app
com.hust.hui.quicksilver.spi.test.print.ConsolePrint com.hust.hui.quicksilver.spi.test.print.FilePrint
測試代碼以下框架
@Test public void testPrint() throws NoSpiMatchException { SpiLoader<IPrint> spiLoader = SpiLoader.load(IPrint.class); IPrint print = spiLoader.getService("ConsolePrint"); print.print("console---->"); print = spiLoader.getService("FilePrint"); print.print("file---->"); try { print = spiLoader.getService("undefine"); print.print("undefine----"); Assert.assertTrue(false); } catch (Exception e) { System.out.println("type error-->" + e); } try { print = spiLoader.getService(123); print.print("type error----"); Assert.assertTrue(false); } catch (Exception e){ System.out.println("type error-->" + e); } }
輸出以下ide
console print: console----> file print: file----> type error-->com.hust.hui.quicksilver.spi.exception.NoSpiMatchException: no spiImpl match the name you choose! your choose is: undefine type error-->java.lang.IllegalArgumentException: conf spiInterfaceType should be sub class of [class java.lang.String] but yours:class java.lang.Integer
演示以下測試
與靜態的使用有點區別,主要的區別點在於接口的定義(須要注意第一個參數是做爲選擇器選擇SPI實現的參數),一樣是上面這個spi接口ui
@Spi public interface IPrint { void print(String str); void adaptivePrint(String conf, String str); } @Override public void print(String str) { System.out.println("file print: " + str); } @Override public void adaptivePrint(String conf, String str) { System.out.println("file adaptivePrint: " + str); } } public class ConsolePrint implements IPrint { @Override public void print(String str) { System.out.println("console print: " + str); } @Override public void adaptivePrint(String conf, String str) { System.out.println("console adaptivePrint: " + str); } }
主要是新增了一個接口 adaptivePrint
, 其餘的沒有啥區別,測試代碼以下this
@Test public void testAdaptivePrint() throws SpiProxyCompileException { IPrint print = SpiLoader.load(IPrint.class).getAdaptive(); print.adaptivePrint("FilePrint", "[file print]"); print.adaptivePrint("ConsolePrint", "[console print]"); }
輸出結果.net
file adaptivePrint: [file print] console adaptivePrint: [console print]
演示圖
上面兩個很簡單的演示了下使用方式,最基本的方法, 沒有加上 @SpiConf 註解, 沒有顯示指定選擇器類 型,下面則演示下,如何自定義選擇器
SPI接口
有一個歡迎方法,咱們需求根據用戶的來源顯示不一樣的歡迎至此, 下面定義了一個 UserSelector
選擇器,這個就是咱們自定義的選擇器
@Spi public interface IUser { @SpiAdaptive(selector = UserSelector.class) void welcome(UserDO userDO); }
spi實現類
public class QQUser implements IUser { @Override public void welcome(UserDO userDO) { System.out.println("qq 歡迎你! " + userDO); } } public class WeixinUser implements IUser { @Override public void welcome(UserDO userDO) { System.out.println("weixin 歡迎你! " + userDO); } }
META-INF/services/
目錄下的配置以下 com.hust.hui.quicksilver.spi.def.spi.IUser
com.hust.hui.quicksilver.spi.def.spi.QQUser com.hust.hui.quicksilver.spi.def.spi.WeixinUser
選擇器實現以下
public class UserSelector implements ISelector<UserDO> { @Override public <K> K selector(Map<String, SpiImplWrapper<K>> map, UserDO conf) throws NoSpiMatchException { if (conf == null || conf.getMarket() == null) { throw new IllegalArgumentException("userDo or userDO#market should not be null!"); } String name = conf.getMarket().getName(); if (map.containsKey(name)) { return map.get(name).getSpiImpl(); } throw new NoSpiMatchException("no spiImp matched marked: " + conf.getMarket()); } }
從上面的選擇器邏輯能夠看出,咱們是根據 UserDO的market參數來進行選擇的, UserDO的定義以下
@Getter @Setter @ToString public class UserDO { private String uname; private String avatar; private MarketEnum market; } public enum MarketEnum { WEIXIN("WeixinUser"), QQ("QQUser"); private String name; MarketEnum(String name) { this.name = name; } public String getName() { return name; } }
測試代碼以下
@Test public void testUserSPI() throws SpiProxyCompileException { SpiLoader<IUser> loader = SpiLoader.load(IUser.class); IUser user = loader.getAdaptive(); UserDO weixinUser = new UserDO(); weixinUser.setAvatar("weixin.avatar.jpg"); weixinUser.setUname("微信用戶"); weixinUser.setMarket(MarketEnum.WEIXIN); user.welcome(weixinUser); UserDO qqUser = new UserDO(); qqUser.setAvatar("qq.avatar.jpg"); qqUser.setUname("qq用戶"); qqUser.setMarket(MarketEnum.QQ); user.welcome(qqUser); System.out.println("-----over------"); }
輸出結果:
weixin 歡迎你! UserDO(uname=微信用戶, avatar=weixin.avatar.jpg, market=WEIXIN) qq 歡迎你! UserDO(uname=qq用戶, avatar=qq.avatar.jpg, market=QQ)
演示以下:
博客系列連接:
源碼地址:
https://git.oschina.net/liuyueyi/quicksilver/tree/master/silver-spi