使用测试
前面三篇主要是介绍如何设计的,如何实现的,这一篇,则主要集中在如何使用。实现得再好,如果不好用,也白搭
本篇介绍几个简单的使用case,包括静态使用,动态适配,自定义选择器等
1. 简单的静态使用 定义一个SPI接口 IPrint
, 两个实现 FilePrint
, ConsolePrint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @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
, 内容如下
com.hust.hui.quicksilver.spi.test.print.ConsolePrint
com.hust.hui.quicksilver.spi.test.print.FilePrint
测试代码如下
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 @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); } }
输出如下
1 2 3 4 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
演示如下
2. 动态适配 与静态的使用有点区别,主要的区别点在于接口的定义(需要注意第一个参数是作为选择器选择SPI实现的参数),同样是上面这个spi接口
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 @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
, 其他的没有啥区别,测试代码如下
1 2 3 4 5 6 7 8 @Test public void testAdaptivePrint () throws SpiProxyCompileException { IPrint print = SpiLoader.load(IPrint.class ).getAdaptive () ; print.adaptivePrint("FilePrint" , "[file print]" ); print.adaptivePrint("ConsolePrint" , "[console print]" ); }
输出结果
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 file adaptivePrint: [file print] console adaptivePrint: [console print] ``` 演示图 ![http://s2.mogucdn.com/mlcdn/c45406/170531_54f638fkcl58c6lihl92adei31c78_1222x718.gif](http://s2.mogucdn.com/mlcdn/c45406/170531_54f638fkcl58c6lihl92adei31c78_1222x718.gif) ## 3. 自定义选择器 > 上面两个很简单的演示了下使用方式,最基本的方法, 没有加上 @SpiConf 注解, 没有显示指定选择器类 型,下面则演示下,如何自定义选择器 **SPI接口** 有一个欢迎方法,我们需求根据用户的来源显示不同的欢迎至此, 下面定义了一个 `UserSelector`选择器,这个就是我们自定义的选择器 ```java @Spi public interface IUser { @SpiAdaptive(selector = UserSelector.class) void welcome(UserDO userDO); }
spi实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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
选择器实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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的定义如下
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 @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; } }
测试代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @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)
演示如下:
3. 其他 博客系列链接:
项目: QuickAlarm
基于hexo + github pages搭建的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
声明 尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见识有限,如发现bug或者有更好的建议,随时欢迎批评指正,我的微博地址: 小灰灰Blog
扫描关注