公司动态
SSM整合jar包全解:版本搭配与Maven依赖冲突排查指南
简介面向Java Web开发者的SSM整合依赖包集合专门解决Spring、Spring MVC、MyBatis集成时依赖库分散、版本兼容难匹配的问题帮助快速搭建SSM项目基础环境。压缩包共109个文件RAR格式约24.34MB其中包含64个jar包、14个XML配置文件、8个Java源文件与8个class文件另有properties、JSP等辅助资源jar包覆盖框架核心及常见第三方依赖XML配置对应Spring的beans.xml、Spring MVC的servlet-context.xml、MyBatis的mybatis-config.xml等典型文件。这些jar包按功能对应Spring核心容器、AOP、Web、MVC、MyBatis及数据库驱动、连接池和日志组件等XML中定义组件扫描、数据源、SqlSessionFactory与事务管理器等关键Bean包内还带有Eclipse工程配置所需的classpath、project、component等文件整体目录结构清晰方便直接导入开发工具阅读调试。资源已有274人浏览学习尤其适合正在学习SSM整合的初中级开发者既可直接引入所需jar包又能参考配置文件、实体类、Mapper接口与业务层示例理解依赖注入、声明式事务、MyBatis映射等关键配置从而减少从零收集和排查版本冲突的时间快速搭建SSM项目。无论是对SSM各层关系尚不清晰的学习者还是需要快速搭建项目骨架的开发者都能从中获得实际帮助。 SSM整合的jar包问题几乎每个Java后端开发都绕不过去。不管你是刚接触SSM组合的学生还是在维护老项目的在职开发第一步要面对的就是那一堆依赖Spring、SpringMVC、MyBatis再加上数据库驱动、连接池、日志、JSON解析……版本选不对、jar包重复、依赖冲突轻则项目启动报错重则线上环境直接翻车。这篇内容我把SSM整合涉及的所有核心jar包资源、版本搭配逻辑、Maven配置写法、手动收集方案以及常见的冲突排查方法一次性整理清楚保证你拿到就能直接用。1. SSM整合的依赖全景搞清楚到底需要哪些jar包1.1 技术栈本质决定依赖边界SSM只是三个框架的缩写但整合起来牵扯的jar包远比“三个框架”多得多。Spring负责IoC容器和AOP切面SpringMVC负责Web层的请求分发和参数绑定MyBatis负责持久层的SQL映射。这三者各管一段各自又带着自己的一堆附属依赖。Spring核心需要spring-core、spring-beans、spring-context、spring-aop、spring-expression这几个基础模块。SpringMVC需要spring-web和spring-webmvc。MyBatis本身需要mybatis主包但要跟Spring整合还必须引入mybatis-spring这个桥接包否则你没法把SqlSessionFactory交给Spring容器管理。数据库层面的jar包更绕。JDBC驱动比如MySQL的mysql-connector-java是必须的但如果你不用连接池项目跑起来性能会很差。所以一般还要加Druid或者HikariCP这类连接池依赖。再往上是事务管理Spring的spring-jdbc和spring-tx模块虽然看起来跟MyBatis关系不大但没它们Transactional注解就是摆设。日志和JSON解析往往是被忽略的重灾区。Spring底层依赖commons-loggingMyBatis底层依赖slf4j-api如果你没引入对应的实现绑定启动时会看到各种ClassNotFoundException。而REST接口返回JSON又需要jackson-databind这套依赖。再加上Servlet API、JSTL、Lombok这些辅助库一套完整的SSM依赖清单轻松超过20个jar包。1.2 版本兼容矩阵不能随便挑版本组合很多新手栽在版本上是因为SSM不像Spring Boot那样由官方帮你锁死版本。Spring、SpringMVC、MyBatis、MyBatis-Spring各自独立发版版本之间没有强制的对应关系但有实际兼容验证过的组合。我整理了一套经过实测、稳定运行的主流版本搭配方案直接照着用就好组件推荐版本关键说明Spring / SpringMVC5.3.x如5.3.39这是最后一个全面支持Java 8的Spring 5小版本MyBatis3.5.x如3.5.163.5.5以后对JDK 8支持稳定MyBatis-Spring2.1.x如2.1.2不要用1.3.x配Spring 5会有兼容问题MySQL Connector/J8.0.x如8.0.338.0驱动兼容MySQL 5.7和8.0连接池Druid 1.2.x 或 HikariCP 4.0.3Druid国内资料多HikariCP性能更强Jackson2.15.x适配JDK 8JSON序列化稳定Log4j2 / SLF4J2.20.0 / 1.7.36注意SLF4J绑定不能重复Lombok1.18.30需要配套IDEA插件Servlet API4.0.1必须用provided作用域防止和容器冲突这里有一个核心原则Spring和SpringMVC必须使用同一个版本号因为spring-webmvc依赖spring-web以及spring-context的特定接口一旦两个主版本不一致运行时极易出现NoSuchMethodError。Maven的依赖仲裁机制有时候会把Spring其它模块拉高或拉低所以最稳妥的做法是在pom.xml里用dependencyManagement统一锁定Spring版本。另一个容易忽略的点如果你用JDK 17甚至更高版本Spring 5.x的某些反射逻辑会遇到模块化限制需要额外加--add-opens参数。老项目建议老老实实停在JDK 8新项目则强烈建议直接上Spring Boot 2.7或3.x不是一个技术路线。2. 两种依赖管理方式对比手动收集jar包还是Maven统一管理2.1 手动下载jar包的老路什么时候还有用SSM整合的早期阶段很多教程会教手动下载jar包然后把它们丢到WEB-INF/lib目录下。这种方式的优点是“所见即所得”项目里有什么依赖清清楚楚也能在完全没有Maven私服的离线环境下开发。缺点是维护成本极高依赖的传递性依赖得自己一条条找漏一个就启动报错。我见过一些公司内网开发环境切断了外网访问连仓库镜像都连不上。这种场景下手动整理一套SSM的jar包资源就非常实际了。你要做的就是把所有jar包按功能分组存好放到一个公共的lib目录或者共享盘里谁要用直接复制。后面我会给出一份完整的jar包清单就是冲着这个场景准备的。但手动管理有个致命问题jar包重复和版本冲突。同一个jar包的两个版本同时出现在WEB-INF/lib下运行时会随机加载其中一个出问题极其难排查。所以如果你走手动路线务必做好分组和版本命名规范文件名里必须带版本号如spring-context-5.3.39.jar不要用spring-context.jar这种不带版本的命名方式。2.2 Maven/Gradle统一管理推荐方案除非你的环境被限制到没法用Maven否则我强烈推荐用Maven管理SSM依赖。理由很简单Maven自带传递依赖机制你引入mybatis-spring它会自动把mybatis、spring-jdbc等传递依赖拉下来你引入druid它自动把slf4j-api拉进来。项目里依赖长什么样pom.xml写得明明白白换机器、换同事、换CI环境都能一键还原。Maven带来的另一个优势是依赖冲突的可排查性。mvn dependency:tree可以输出整棵依赖树精确看到每个jar包的版本来源。如果有两个不同版本的同名jar包Maven会按“最短路径优先”原则仲裁但仲裁结果不一定是你要的这时可以用exclusion排除掉不需要的传递依赖。我用一个表对比两种方式的差异方便你根据实际情况选型对比维度手动收集jar包Maven统一管理环境要求可完全离线需联网或私服依赖透明度目录下可见需看pom和依赖树传递依赖处理手动收集易遗漏自动拉取版本冲突处理人工比对易出错仲裁排除机制可维护性低新增依赖麻烦高改pom即可适合场景离线内网、培训教学绝大多数实际项目如果你在纠结学哪种我的建议是Maven必须会这是工业化开发的基础。手动收集jar包可以作为理解依赖结构的一种训练方式但别在生产项目里这么干。3. Maven方式核心实现完整pom.xml依赖配置3.1 直接可用的pom.xml依赖段下面这段是我在多个SSM项目里实际用过的依赖配置版本组合经过兼容验证。复制到你的pom.xml里配合后续的数据库等配置就能跑起来properties spring.version5.3.39/spring.version mybatis.version3.5.16/mybatis.version mybatis-spring.version2.1.2/mybatis-spring.version mysql.version8.0.33/mysql.version jackson.version2.15.4/jackson.version log4j2.version2.20.0/log4j2.version slf4j.version1.7.36/slf4j.version /properties dependencies !-- Spring核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-tx/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-aspects/artifactId version${spring.version}/version /dependency !-- MyBatis -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version${mybatis.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version${mybatis-spring.version}/version /dependency !-- 数据库驱动与连接池 -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version${mysql.version}/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.20/version /dependency !-- JSON 序列化 -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version${jackson.version}/version /dependency !-- 日志 -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-api/artifactId version${slf4j.version}/version /dependency dependency groupIdorg.apache.logging.log4j/groupId artifactIdlog4j-slf4j-impl/artifactId version${log4j2.version}/version /dependency dependency groupIdorg.apache.logging.log4j/groupId artifactIdlog4j-core/artifactId version${log4j2.version}/version /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependency !-- Servlet 与 JSP 相关 -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies3.2 依赖分组逻辑与scope使用要点上面的依赖看着多实际上可以分成四个逻辑组Spring组、MyBatis组、数据访问组、辅助工具组。每组的职责边界要清晰这样后续排查问题时能快速定位到是哪个环节出了问题。特别要说一下scope的概念。javax.servlet-api的scope是provided表示编译时需要、打包时不需要因为Tomcat这类Servlet容器已经内置了Servlet API。如果你把provided的依赖打进了WAR包极有可能跟容器的类产生冲突导致启动时出现重复类定义。Lombok的provided同理它只参与编译期注解处理运行期根本不需要。连接池方面Druid和HikariCP二选一即可。Druid在国内使用广泛自带监控页面适合需要可视化数据源状态的管理类系统HikariCP以性能著称Spring Boot默认内置适合追求极致响应速度的场景。我这里用了Druid是因为它在SSM老项目中更常见资料也更丰富。3.3 依赖锁定与版本覆盖的额外建议如果你公司内部有多个项目共用同一套SSM框架强烈建议抽一个parent pom或者bom模块把上述dependencyManagement统一放进去。这样所有子项目继承父pom后只需要声明groupId和artifactId不需要重复写version既能统一版本又能避免各项目自行升级导致的维护混乱。另外Maven的依赖仲裁是“就近原则”如果某个传递依赖把你锁定的版本覆盖了可以在pom里显式声明该依赖的版本就会优先使用你写的版本。还有一个技巧是定期执行mvn dependency:tree把整棵依赖树导出来审一遍能发现很多隐藏的问题。4. 离线环境手动收集jar包完整的jar资源清单4.1 按功能分组整理jar清单虽然Maven是主流但仍有部分培训、教学和严格内网环境需要离线jar包。下面是根据Maven依赖关系和实际测试整理的SSM整合完整jar包清单按功能分组你可以以此为基准批量收集。版本号建议和前面表格保持一致Spring核心组共6个spring-core、spring-beans、spring-context、spring-aop、spring-expression、spring-jcl。注意spring-jcl是Spring 5开始才分离出来的日志适配包遗漏它会导致启动时ClassNotFound。Spring Web与事务组共4个spring-web、spring-webmvc、spring-jdbc、spring-tx。其中spring-web是spring-webmvc的底层依赖两者必须同版本。spring-aspects用于支持Aspect注解风格的AOP配置排错时容易被忽略。MyBatis组共2个mybatis主包、mybatis-spring桥接包。mybatis-spring里的关键类包括SqlSessionFactoryBean和MapperScannerConfigurer没有这个包Spring和MyBatis就是两条平行线。数据库与连接池组共2个mysql-connector-j或mysql-connector-java、druid或HikariCP。mysql 8.0.x驱动以后Maven坐标从mysql:mysql-connector-java变成了com.mysql:mysql-connector-j手动下载时注意不要拿错版本。JSON、日志、Web辅助组共6个jackson-databind、jackson-core、jackson-annotations这三个是一套缺一不可slf4j-api、log4j-slf4j-impl、log4j-core这三个组成日志链路。jackson-databind会传递依赖另外两个但手动收集时容易漏掉传递依赖所以要一起下载。4.2 目录结构规范与检查技巧手动管理jar包时项目目录建议这样组织src/main/webapp/WEB-INF/lib下按功能子目录存放jar包例如lib/spring、lib/mybatis、lib/database、lib/log。虽然Tomcat默认会把WEB-INF/lib下所有jar全部加载但分目录不会影响加载却能极大提升人眼排查的效率。收集完毕后有一个必备检查动作用解压工具打开每个jar包查看META-INF/MANIFEST.MF文件中的Implementation-Version字段确认版本确实是你想要的。很多教程网站标注的版本号和实际文件版本不一致踩过这个坑的都知道有多痛苦。还有一个实操技巧把所有jar包的文件名输出到一个txt里命令是ls -1 jar-list.txt然后存根备份。项目出问题时把这份清单和Maven项目的dependency:tree输出对比能快速发现差异。5. 版本冲突与依赖问题的排查技巧实录5.1 高频率出现的报错与原因速查依赖问题最让人头疼的是“启动时没报错一跑功能就炸”。我把SSM整合过程中常见的报错和原因整理成了一张排查表列在下面典型报错场景问题根因解决思路启动报ClassNotFoundException: org.springframework.web.context.ContextLoaderListener缺少spring-web或spring-webmvc检查是否引入spring-webmvc依赖启动报NoClassDefFoundError: org/springframework/jdbc/datasource/DriverManagerDataSource缺少spring-jdbc引入spring-jdbc事务管理也依赖它Mapper接口扫描不到注入报NoSuchBeanDefinitionException缺少mybatis-spring 或 mapper扫描配置有误确认mybatis-spring版本检查MapperScan配置报错SLF4J: Class path contains multiple SLF4J bindings多个日志绑定包共存排除多余的slf4j绑定保留一个实现执行SQL时报Unsupported conversion from TIMESTAMP to java.sql.TimestampMySQL驱动版本和服务端版本不匹配升级mysql-connector-j到8.0.x报错NoSuchMethodError: javax.servlet.http.HttpServletRequest.isAsyncStartedServlet API版本在编译期和容器里不一致将servlet-api改为provided作用域报错Invalid value type for attribute factoryBeanObjectTypeSpring与MyBatis版本组合太老按前面推荐版本组合调整JSON返回报错No serializer found for classJackson缺少JavaBean的getter方法检查实体类是否有getter或引入jackson-databind5.2 用Maven依赖树精准定位冲突如果你用的Maven排查依赖冲突的第一利器是dependency:tree。执行mvn dependency:tree -Dverbose输出结果里会出现类似“maven-dependency-plugin:2.8:tree”的日志每条依赖后面会标记它的来源路径。比如你看到两个不同版本的spring-core同时出现在树里一条路径是直接依赖另一条是通过druid或者其它库传递进来的这时就要决定保留哪个然后在pom里用exclusion排除多余的那个。我遇到过一个典型问题项目里同时导入了druid和一个老旧的commons-dbcp两个连接池的类都存在于classpath数据源初始化时Random杀掉了一条连接诡异的是连接池里另一个连接又被其它线程用到导致偶发性的连接泄漏。用依赖树排查后发现是commons-dbcp通过一个内部工具包传递进来的排除后问题消失。5.3 不用Maven时怎么排查冲突如果是手动管理jar包的项目排查冲突就要靠工具辅助。老牌工具是JD-GUI可以直接打开jar包反编译class文件或者查看jar包内的类列表。具体操作是File - Open File选一个jar包然后在左下角的class列表里找目标类右键选择View Source能直接看到反编译后的代码判断它来自哪个版本。JDK自带的jar命令也可以查看jar包里的内容适合快速确认某个类是否存在jar tf spring-core-5.3.39.jar | grep -i ContextLoader这个命令输出的是jar包内所有条目路径如果包含org/springframework/web/context/ContextLoaderListener.class说明该类在该jar中。用这种方式比对两个同名jar包能确定它们的类集合差异也是解决NoSuchMethodError的最后一招。IDEA自带的依赖分析功能同样好用。打开项目结构CtrlAltShiftS在Libraries面板里能看到所有jar包路径和来源。如果项目是Maven管理的IDEA的Maven面板还会显示“Show Dependencies”图虽然不是Mermaid但能直观看到传递依赖关系。6. 项目结构调整框架层代码抽离到私库的思路6.1 为什么不建议各项目直接copy jar包很多公司在维护多套SSM系统时会发现每个项目pom.xml里都维护着一份几乎相同的Spring、MyBatis版本号。当某个CVE漏洞爆出来或者需要统一升级框架版本时就要挨个项目改pom再发版非常痛苦。这也是“框架调整”类热词背后真实的业务诉求把框架层代码和公共组件从各业务项目中剥离出来固化成一个独立的可复用模块。思路其实很简单先建一个独立的项目比如叫做ssm-common-framework把所有框架层代码比如统一的BaseDao、分页拦截器、公共异常处理、返回结果封装都放进去。然后通过Maven的install或deploy命令打成jar包传到公司的私有仓库中。业务项目里只需要依赖这个framework坐标就能复用全部框架能力不再重复维护。6.2 传到私库的Maven配置与操作流程如果你公司有Nexus私服部署操作很简单。在框架项目的pom.xml里配置私服地址distributionManagement repository idreleases/id nameReleases Repository/name urlhttp://nexus.xxx.com/repository/maven-releases//url /repository snapshotRepository idsnapshots/id nameSnapshots Repository/name urlhttp://nexus.xxx.com/repository/maven-snapshots//url /snapshotRepository /distributionManagement然后在项目根目录执行mvn clean install mvn deploy仓库地址要对releases和snapshots仓库通常分开快照版本号要带-SNAPSHOT后缀。deploy成功之后业务项目里直接声明依赖dependency groupIdcom.company/groupId artifactIdssm-common-framework/artifactId version1.0.0/version /dependency这就完成了从“copy jar包”到“中央依赖”的转变后续框架升级只需要发布新版本业务项目按需拉取即可。6.3 依赖管理演进的实践经验从SSM整合所有jar包资源到Maven统一管理再到私库体系这其实是一条清晰的工程化演进路径。初期项目少手动管理没问题项目数量上来了就开始需要Maven的版本锁定能力到了多团队多系统协作阶段私库是必然选择。在这个演进过程中我最想强调的一点是不要神化任何一种方案工具始终是为人服务的。手动收集jar包适合极简教学场景Maven依赖管理适合绝大多数项目私库则解决了多项目的一致性问题。关键是理解每个阶段要解决什么问题然后选择对应的工具和策略。我自己的实战体会是SSM整合的坑主要集中在依赖混乱而不是框架本身。把版本组合固定好、用Maven管理传递依赖、必要时抽离公共模块这三个动作能帮你省下大量排查时间。最后再分享一个经验每次搭新项目时先把pom.xml的依赖树导出一份存到项目根目录版本变更时做diff这个习惯能让你在依赖维护上游刃有余。本文还有配套的精品资源点击获取