组件mssclient初始化失败
我一开始以为是组件版本不兼容。mssclient 2.3和2.4的始化失败配置文件格式有差异,2.4把心跳间隔从heartbeat改成了heartbeat_interval,组件如果拿旧配置跑新版本,它不会报参数错误,而是直接吞掉,然后初始化流程走到一半就退出。我把jar包版本和配置逐项比对,没问题。
那就查代码。翻到mssclient的初始化源码,发现它内部有个步骤是加载SPI实现类。它用ServiceLoader加载一个叫MessageHandler的接口实现,如果classpath下没有对应的META-INF/services文件,或者文件里写的类名不存在,它不会抛ClassNotFoundException,而是默默跳过,然后初始化状态就停留在“未就绪”。
这个坑我踩过。去年有个模块也是mssclient连不上,最后发现是打包时resources目录没把services文件打进去。但这次我特意解压了jar包,services文件在,类也在。
再往下追,初始化逻辑里有个步骤是读取本地缓存文件,用来做消息重发补偿。路径写的是user.dir/data/msgcache。如果这个目录没有写权限,或者父目录不存在,它会捕获IOException然后继续,但缓存管理器初始化失败,整个客户端就拒绝启动。我检查了部署目录,权限是755,属主也对。
正打算放弃,突然注意到日志里有一行被忽略的警告——WARN: charset GBK not supported, fallback to default。这行字在启动早期一闪而过,谁都没在意。但问题就在这。mssclient初始化时有个步骤是解析配置文件里的中文注释,它默认用GBK解码配置文件。如果Linux服务器的默认字符集是UTF-8,而配置文件本身是UTF-8编码,GBK解码就会产生乱码,遇到某些特殊字符时解析直接中断,但异常被吞了,只留警告。
我打开配置文件看了下,里面确实有一段中文注释,写的是“# 消息超时时间(秒)”,那个括号是全角括号。GBK解码时全角括号和UTF-8的字节序列冲突,解析器直接跳过整个键值对。结果超时参数没被设置,初始化校验时发现关键参数缺失,返回失败。
解决办法很简单,把配置文件的编码改成GBK,或者删掉那行中文注释。我选择删注释,因为干净。
这事的教训是:初始化失败别老盯着配置值本身,配置文件怎么被读取的更重要。mssclient的代码质量不算好,异常处理太粗,很多错误被吞成警告。遇到这种问题,把日志级别调到DEBUG,启动时全量输出,一行一行看,比瞎猜快得多。
现在组件能连上了,消息收发正常。但我心里清楚,下次再遇到类似问题,我第一件事就是看配置文件编码,而不是检查IP和端口。经验就是这么来的,被坑一次,长记性一次。