使用测试 
前面三篇主要是介绍如何设计的,如何实现的,这一篇,则主要集中在如何使用。实现得再好,如果不好用,也白搭
 
本篇介绍几个简单的使用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] ```     演示图     ## 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 
扫描关注