SPI问题解决

问题表现

先看问题的表现(线上错误日志):

2018-09-25 18:48:35,791 ERROR [pool-9-thread-136] (AccountGlobalService.java:139) - verify from asia1 api failed java.lang.ClassCastException
2018-09-25 18:48:35,791 ERROR [pool-9-thread-170] (AccountGlobalService.java:139) - verify from us api failed java.lang.ClassCastException

当看到这个错误日志是表示一脸懵逼,是什么导致类型转化失败?

问题定位

该问题是在测试加解密登陆时候碰到的,故可以先大致判断登陆模块导致的错误,然后把堆栈信息打印出来。堆栈信息如下:

有空补齐

通过定位可以知道toolkit jar中的RestClient出现了问题。该类可实现使用接口(接口中定义相对路径)可以实现远程调用(吐槽一下,该类以前还存在内存泄漏问题)。
RestClient出问题的代码

  ResteasyWebTarget target;
     String uri = null;
     if (0 == url.getPort()) {
         uri = url.getProtocol() + "://" + url.getHost() + "/" + getContextPath(url);
     } else {
         uri = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/" + getContextPath(url);
     }
     target = client.target(uri);

而报错的代码如下图所示:
image_1coa6sscs1876jbo1322pdc1njt38.png-103.4kB
那UriBuilder转化ResteasyUriBuilder? 查看UriBuilders的子类如下:
image_1cog0lgt11k4i5cq17cd137l1ekt9.png-120.7kB
那运行的类就有可能是其他子类,比如JerseyUriBuilder 或者 UriBuilderImpl。
现在只能看UriBuilder类:
image_1cog11lhn1dgsm5d16jf545md2m.png-220kB
我们使用的方法是fromUri,而该方法使用动态代理加载一个类


  public static RuntimeDelegate getInstance() {
       RuntimeDelegate result = cachedDelegate;
       if (result == null) {
           Object var1 = RD_LOCK;
           synchronized(RD_LOCK) {
               result = cachedDelegate;
               if (result == null) {
                   cachedDelegate = result = findDelegate();
               }
           }
       }
       return result;
   }
   
   private static RuntimeDelegate findDelegate() {
       try {
       // 这个东西是啥
           Object delegate = FactoryFinder.find("javax.ws.rs.ext.RuntimeDelegate", "org.glassfish.jersey.internal.RuntimeDelegateImpl");
           if (!(delegate instanceof RuntimeDelegate)) {
               Class pClass = RuntimeDelegate.class;
               String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
               ClassLoader loader = pClass.getClassLoader();
               if (loader == null) {
                   loader = ClassLoader.getSystemClassLoader();
               }

               URL targetTypeURL = loader.getResource(classnameAsResource);
               throw new LinkageError("ClassCastException: attempting to cast" + delegate.getClass().getClassLoader().getResource(classnameAsResource) + " to " + targetTypeURL);
           } else {
               return (RuntimeDelegate)delegate;
           }
       } catch (Exception var5) {
           throw new RuntimeException(var5);
       }
   }

该类是存放在这里
image_1cog1mga9j87f9qg0t12qdg971g.png-208.4kB

image_1cog23vai8jn10tn1b0t1li1eul1t.png-143.9kB

为啥放在META-INF/service呢?经过谷歌一番后,才知道这个是SPI加载方式。这是SPI一篇博客
那预计是查找错了一个文件,导致加载了其他jar的实例,最终导致类型转化失败。
解决方法:
1.去除不使用的jar
2.修改RestClient代码,如下:

 ResteasyWebTarget target;
     UriBuilder uriBuilder = new ResteasyUriBuilder();
     String uri = null;
     if (0 == url.getPort()) {
         uri = url.getProtocol() + "://" + url.getHost() + "/" + getContextPath(url);
     } else {
         uri = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/" + getContextPath(url);
     }
     uriBuilder.uri(uri);
     target = client.target(uriBuilder);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值