一. Netty客户端通过ssl方式连接服务端失败
最近在重构项目代码,在测试时在本地通过ssl的方式连接服务端,服务端通过SniHandler处理ssl连接时,报一下异常:
2019-05-27 17:32:26,104 110948 [nioEventLoopGroup-3-2] ERROR c.t.p.b.m.h.ChannelDisconnectedHandler(128) - Could not initialize class io.netty.handler.ssl.OpenSslEngine
二. debug代码分析问题
netty处理ssl解析的ChannelHandler是SniHandler,故debug代码分析问题,在SniHandler的decode解码方法设置断点:
![456e41e5a04c78d33ffe37c06ce9d0ce.png](https://i-blog.csdnimg.cn/blog_migrate/7dc263cdff9855e108f587334a65eaa1.jpeg)
然后运行服务端,并通过netty客户端连接服务端。
在debug过程中,首先调用到了抛出了java.lang.NoSuchMethodError的异常,表示没有io.netty.util.internal.PlatformDependent.newAtomicIntegerFieldUpdater方法的异常,由于catch掉了,故代码可以继续运行。
![2e36c3d7e5b0f08c0ef82ae7944c93ad.png](https://i-blog.csdnimg.cn/blog_migrate/f5b92c6208a785742b0579996c30cf22.jpeg)
然后出现java.lang.NoClassDefFoundError: Could not initialize class io.netty.handler.ssl.OpenSslEngine,如下图所示。异常NoClassDefFoundError为运行时加载不到类,说明在运行时,在项目中加载不到io.netty.handler.ssl.OpenSslEngine这个类,所以需要定位这个io.netty.handler.ssl.OpenSslEngine所在的包。
![14d108dd5f5a2715a21d114a685c635f.png](https://i-blog.csdnimg.cn/blog_migrate/554d730139408b8cd02ec5e89b5fb060.jpeg)
堆栈情况:
![c29fbfd7e60a74f18a263ee424af180b.png](https://i-blog.csdnimg.cn/blog_migrate/6c485ed8993ea195c33617d01fd3d607.jpeg)
三、包分析与定位问题
查找io.netty.handler.ssl.OpenSslEngine所在的包,如下在idea的External Libraries视图可以发现,io.netty.handler.ssl.OpenSslEngine这个类位于netty-all.jar包中:
![3969ab52bfba5b66823ad808e1e92a87.png](https://i-blog.csdnimg.cn/blog_migrate/f292a36be61873ba8dd7707160bee1aa.jpeg)
在项目目录下,通过mvn dependency:tree命令分析当前项目依赖的包关系:netty相关的包依赖如下,并没有netty-all.jar的依赖,所以可以定位出是由于不存在这个包导致的。如下对netty-common.jar包加红,后面会继续分析这个包。
![69bc716f858924168588b2961538c553.png](https://i-blog.csdnimg.cn/blog_migrate/74a96e385f349a8bcf702c78f91c2987.jpeg)
所以在项目的pom.xml文件中添加这个包的依赖,如下:在netty-codec-mqtt后面添加netty-all的包。
![de9bc299d02d0cf2c5bae3387bc8050e.png](https://i-blog.csdnimg.cn/blog_migrate/54e54619d71c819bba747d7467b57bfb.jpeg)
重新启动项目,发现还是报同样的错误,如下:
2019-05-27 20:32:29,104 110948 [nioEventLoopGroup-3-2] ERROR c.t.p.b.m.h.ChannelDisconnectedHandler(128) - Could not initialize class io.netty.handler.ssl.OpenSslEngine
但是通过mvn dependency:tree命令分析项目确实是已经有了netty-all.jar这个包,如下:netty-common.jar此时在netty-all.jar前面。
![8e13ffa8c3241bea6ebbf5f3326e4eb4.png](https://i-blog.csdnimg.cn/blog_migrate/a4fae33b93cfef72731024b5494aaf3c.jpeg)
所以此时可能的情况就是项目在运行的时候并没有使用到netty-all.jar里面的类,而是使用了其他netty相关包,其实此时使用的就是netty-codec-mqtt.jar包引入的netty-common.jar包里面的类。结合之前的方法io.netty.util.internal.PlatformDependent.newAtomicIntegerFieldUpdater找不到的异常:去netty-common.jar包发现里面也存在这个子包,如下:在idea查找newAtomicIntegerFieldUpdater这个方法,显示查找不到。故项目在运行的时候,定位到的是netty-common.jar包内部的io.netty子包,在这个子包里面查找:io.netty.util.internal.PlatformDependent.newAtomicIntegerFieldUpdater和io.netty.handler.ssl.OpenSslEngine都查找不到。
![caa30cb90665964bba11e29d05f62ce4.png](https://i-blog.csdnimg.cn/blog_migrate/3932e8014d8c46fd4b26bed258e7c53f.jpeg)
四、解决方法
通过在maven的pom.xml文件配置项目的包依赖关系有个规则:优先使用在pom.xml文件中,配置在前面的依赖包。刚刚没有使用netty-all.jar是因为netty-all.jar配置在了netty-codec-mqtt.jar的后面,故使用了netty-codec.mqtt.jar所引入的netty-common.jar包。
解决方法如下:将netty-all.jar和netty-codec-mqtt.jar的位置调换一下,netty-all.jar配置在前面。
![435dc3024029bb2b4e6df9b7f1b9fe98.png](https://i-blog.csdnimg.cn/blog_migrate/aae83470179a39db8fedf8beef580b96.jpeg)
如下:netty-all.jar在netty-common.jar前面了。
![d983e021372f47c811c8592d231d3bd9.png](https://i-blog.csdnimg.cn/blog_migrate/de55af6d3434033725151e6ffa7b411d.jpeg)
重启项目,通过netty客户端重新连接服务端,此时可以正常连接到了,到了项目自身的身份认证部分了,如下:
2019-05-27 21:07:25,249 52602 [nioEventLoopGroup-3-1] ERROR c.t.p.b.m.s.HttpsCredentialRealm(210) - user info:{"error_description":"很抱歉,身份验证失效,请重新登录