微服务之短信验证服务配置完后junit单元测试短信发送失败

总之岁月漫长,然而值得等待。

主要是版本冲突问题,具体报错与解决方法如下:

报错前:
启动失败

短信服务测试报错:

解决后:
启动成功

短信服务测试发送成功:

在使用 SpringBoot 开发时,我们经常会引入各种依赖以满足功能需求。然而,依赖版本不一致的问题可能会导致一些复杂的错误。最近在项目中,我遇到了一个典型的 NoClassDefFoundError 问题,经过排查发现其根本原因是依赖版本冲突。

一、问题描述

bash 复制代码
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2024-11-29 00:53:51.262  INFO 19140 --- [           main] c.a.alicloud.oss.OssApplicationListener  : 0 OSSClients will be shutdown soon
2024-11-29 00:53:51.278 ERROR 19140 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'OSSController': Unsatisfied dependency expressed through field 'ossClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ossClient' defined in class path resource [com/alibaba/alicloud/context/oss/OssContextAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.aliyun.oss.OSS]: Factory method 'ossClient' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/http/ssl/SSLContextBuilder
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.12.jar:5.3.12]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.12.jar:5.3.12]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.12.jar:5.3.12]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771) [spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763) [spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) [spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) [spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) [spring-boot-2.4.12.jar:2.4.12]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1318) [spring-boot-2.4.12.jar:2.4.12]
	at com.chhei.mall.third.MallThirdPartyApplication.main(MallThirdPartyApplication.java:12) [classes/:na]
bash 复制代码
Caused by: java.lang.NoClassDefFoundError: org/apache/http/ssl/SSLContextBuilder

详细堆栈信息提示 SSLContextBuilder 类无法被加载,而该类属于 Apache 的 httpclient 包。在分析日志后,定位到问题是阿里云 OSS 客户端(com.aliyun.oss.OSS)在初始化时无法正确加载 org.apache.http.ssl.SSLContextBuilder 类。

二、问题分析

1.定位问题依赖 报错中提到的 SSLContextBuilder 位于 org.apache.httpcomponents 的 httpclient 包中。通过查看 Maven 仓库可知,它需要以下两个核心依赖:

httpclient
httpcore

2.版本冲突 项目中直接或间接引入了多个版本的 httpcore,分别是:
通用工具类:

bash 复制代码
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.14</version>
</dependency>

第三方服务类:

bash 复制代码
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.2.1</version>
</dependency>

这两个依赖版本要统一或接近,统一完后就不报错了,具体统一可以直接改成一模一样的版本,子 类pom像父类看齐,也可以参考一下其他方法。

三、解决方案(其他)

排除冲突依赖 对于引入旧版本 httpcore 的依赖,通过排除方式在子类pom文件中移除冲突版本:

bash 复制代码
<dependency>
    <groupId>某依赖的groupId</groupId>
    <artifactId>某依赖的artifactId</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
        </exclusion>
    </exclusions>
</dependency>

再引入自己独立的版本:

bash 复制代码
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.2.1</version>
</dependency>

版本不要相差太大一般不会有什么问题。

最后终端进入对应的第三方模块输入:

bash 复制代码
mvn clean install
相关推荐
龙智DevSecOps解决方案5 小时前
TESSY基于需求的单元测试教程:需求关联、覆盖率与可疑测试处理
单元测试·视频教程·tessy
努力努力再努力wz8 小时前
【Lua 入门系列】从顺序执行到分支与循环:一文理解 Lua 控制结构、作用域与跳转规则
junit·单元测试·lua
火22511 小时前
# C++ 微服务即时通讯系统(四):MySQL、Redis 与 Elasticsearch——数据分工与一致性
c++·mysql·微服务
xiaoye-duck1 天前
《C++ 工具库实战》GTest 单元测试:断言、全局环境、局部夹具与底层原理
c++·单元测试·第三方库
我不会起名字3221 天前
服务注册了却调不通:注册中心与心跳的 3 个时间参数
微服务·nacos·注册中心·排查
知已难寻1 天前
第 5 篇 · 云原生生态与实践:微服务、DevOps、可观测性与 Serverless
大数据·linux·服务器·微服务·云原生·云计算·devops
努力努力再努力wz1 天前
【Lua入门系列】从动态类型到变量作用域:彻底理解 local、全局变量与跨文件访问
开发语言·junit·lua
利威尔xu1 天前
Go IM 源码实战(7):断线三天重连,水位算错就漏消息
redis·后端·微服务·面试·golang
pt10431 天前
Cisco设备网络安全系列-16:微服务、Kubernetes与无服务器架构安全
网络·安全·微服务·架构