SSM框架深度解析:Spring MVC工作流程、MyBatis缓存与三级缓存实战
1. 项目概述为什么SSM依然是Java开发者的必修课在Java企业级开发领域SSM框架组合Spring Spring MVC MyBatis是一个绕不开的经典技术栈。即便在Spring Boot大行其道的今天深入理解SSM依然是每一位Java开发者夯实基础、理解框架演进脉络的关键。很多面试官喜欢问Spring MVC的工作流程、MyBatis的一二级缓存或者Spring的IoC原理其根源就在于SSM代表了Java Web开发从“配置地狱”走向“约定优于配置”的中间态理解了它你才能明白Spring Boot为何要那样设计也才能更从容地应对那些看似“过时”却直指核心的八股文问题。简单来说SSM是一个整合框架它试图在保持灵活性的同时提供一套相对标准化的Web应用开发方案。Spring作为核心容器负责管理所有Java对象Bean的生命周期和依赖关系Spring MVC基于Spring专门处理Web层的请求分发和视图渲染而MyBatis则作为数据持久层框架负责将Java对象与数据库记录进行映射。这个组合在几年前几乎是Java Web后台开发的“标配”无数电商、管理、金融系统都构建于其上。因此无论是为了维护历史项目还是为了打牢基础以学习更现代的架构吃透SSM都至关重要。2. SSM框架核心组件深度拆解2.1 Spring不只是IoC容器更是生态基石很多人对Spring的理解停留在“一个通过XML配置Bean的IoC容器”这其实大大低估了它的价值。Spring的核心设计思想是依赖注入DI和面向切面编程AOP它通过这两个利器实现了对象间解耦和横切关注点如日志、事务的集中管理。IoC容器的运作机制你可以把Spring容器想象成一个超级工厂。在传统开发中对象A需要对象B得自己new B()。而在Spring里你只需要告诉容器“我需要一个B类型的对象”容器就会在适当的时机比如A被创建时把创建好的B“注入”给A。这个“告诉”的方式早期是XML后来是注解如Autowired。容器内部维护着一个巨大的Map存放着所有Bean的定义和实例。三级缓存解决循环依赖这是Spring面试的经典问题。假设A依赖BB也依赖ASpring如何解决这个“先有鸡还是先有蛋”的问题它依靠的是三级缓存一级缓存singletonObjects存放已经完全初始化好的单例Bean。这是最终取Bean的地方。二级缓存earlySingletonObjects存放早期暴露的Bean已实例化但未完成属性填充和初始化。三级缓存singletonFactories存放Bean的工厂对象用于生成早期引用。当创建A时实例化后此时还是一个“半成品”Spring会将其工厂放入三级缓存。接着开始为A注入属性B发现B不存在则去创建B。创建B的过程中又需要注入属性A此时Spring会从三级缓存中找到A的工厂生成一个A的早期代理对象可能是通过AOP创建的代理并将其放入二级缓存然后把这个早期引用注入给B。B创建完成后再注入回AA得以完成初始化最终移入一级缓存并清理二、三级缓存。这个过程精妙地避免了死锁是理解Spring Bean生命周期和AOP代理创建时机的最佳案例。注意三级缓存主要为了解决单例Bean的属性注入循环依赖。对于构造器注入的循环依赖Spring是无能为力的会在启动时直接抛出BeanCurrentlyInCreationException异常。2.2 Spring MVC请求是如何被处理的Spring MVC是一个基于DispatcherServlet前端控制器的MVC框架。它的工作流程是面试必考题但死记硬背流程图没用关键要理解每个环节的意图和可扩展点。一个请求的完整旅程用户发起请求浏览器发出http://localhost:8080/app/user/list。DispatcherServlet拦截在web.xml中配置的DispatcherServlet会拦截所有请求通常配置为/。HandlerMapping查找处理器DispatcherServlet询问所有注册的HandlerMapping“这个URL该由哪个方法Handler处理” 最常用的是RequestMapping注解映射。HandlerAdapter执行处理器找到Handler后DispatcherServlet再找一个能执行它的HandlerAdapter例如支持RequestMapping注解的RequestMappingHandlerAdapter。这个适配器会负责调用目标方法并在调用前后进行参数解析、数据绑定、模型填充等工作。执行Controller方法你的Controller类中的方法被调用处理业务逻辑并返回一个逻辑视图名如success或一个ModelAndView对象。ViewResolver解析视图DispatcherServlet拿到视图名后交给ViewResolver视图解析器去解析成具体的View对象如JSP、Thymeleaf模板。视图渲染View对象负责渲染将模型数据填充到视图中生成最终的HTML。返回响应将渲染结果通过HttpServletResponse返回给用户。拦截器Interceptor的应用这是Spring MVC提供的强大扩展点类似于Filter但更贴近Spring生态。你可以在三个时点插入自定义逻辑preHandleController方法执行前。常用于权限校验、日志记录。返回false则中断流程。postHandleController方法执行后视图渲染前。可以对模型数据进行二次处理。afterCompletion整个请求完成后。常用于资源清理、性能监控。例如一个简单的登录校验拦截器public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); Object user session.getAttribute(currentUser); if (user null) { response.sendRedirect(/login); return false; // 中断请求 } return true; // 放行 } }然后在Spring MVC配置中注册这个拦截器并指定它拦截的路径。2.3 MyBatisSQL与Java对象的优雅映射MyBatis的核心优势在于它完美平衡了灵活性和便捷性。与Hibernate这种全自动ORM框架不同MyBatis要求开发者自己编写SQL但它负责将SQL执行结果与Java对象POJO进行自动映射。核心组件与工作流程SqlSessionFactory这是MyBatis的“发动机”通过读取全局配置文件mybatis-config.xml和所有Mapper XML文件来构建。一个应用通常只有一个。SqlSession代表一次数据库会话通过SqlSessionFactory创建。它提供了执行SQL、获取Mapper接口代理对象的方法。重要它不是线程安全的每次请求都应该创建新的用完后必须关闭。Mapper接口与XML文件这是MyBatis的灵魂。你定义一个Java接口如UserMapper然后在同名的XML文件中编写具体的SQL语句。MyBatis会在运行时为这个接口生成动态代理对象将接口方法的调用映射到XML中对应ID的SQL语句上。一级缓存与二级缓存一级缓存本地缓存默认开启作用域是SqlSession。在同一个SqlSession中执行两次相同的查询第二次会直接从缓存中取数据。这里有一个大坑在开启事务的情况下如果你在同一个事务中先更新了某条数据紧接着又查询它MyBatis为了保证数据一致性会清空一级缓存导致你查不到刚刚更新的数据实际上会去数据库查但开发者可能误以为缓存没更新。这是“开启事务后mybatis一级缓存导致数据查询不到”问题的根源。解决方案通常是1. 关闭一级缓存不推荐2. 在更新后手动调用sqlSession.clearCache()3. 设计上避免在同一个短事务中既更新又查询同一数据。二级缓存作用域是MapperNamespace级别可以被多个SqlSession共享。需要手动在XML中配置cache/标签。它的实现机制更复杂涉及序列化/反序列化在分布式环境下容易产生数据一致性问题使用需谨慎。动态SQL这是MyBatis非常强大的特性让你能在XML中编写灵活的SQL。常用标签有if条件判断。choose/when/otherwise类似Java的switch-case。foreach遍历集合常用于IN查询或批量插入。where、set智能地处理WHERE和SET子句避免SQL语法错误如多余的AND或逗号。例如一个多条件查询select idselectUsers resultTypeUser SELECT * FROM user where if testname ! null and name ! AND name like concat(%, #{name}, %) /if if teststatus ! null AND status #{status} /if /where ORDER BY id DESC /select3. SSM整合实战从零搭建一个后台管理系统理解了理论我们动手整合一个最简单的SSM项目实现用户的增删改查CRUD。这里使用Maven管理依赖IDE以IntelliJ IDEA为例。3.1 环境准备与项目结构1. 创建Maven Web项目 在IDEA中选择创建Maven项目选择maven-archetype-webapp原型。创建完成后手动补全标准的src/main/java和src/test/java目录。2. 核心依赖pom.xml 你需要引入Spring核心、Spring MVC、MyBatis以及它们的整合包、数据库驱动、连接池等。properties spring.version5.3.23/spring.version mybatis.version3.5.11/mybatis.version mybatis-spring.version2.0.7/mybatis-spring.version /properties dependencies !-- Spring Core -- 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-test/artifactId version${spring.version}/version scopetest/scope /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 groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.16/version /dependency !-- Servlet API -- 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 !-- 日志 -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-api/artifactId version1.7.36/version /dependency dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.2.11/version /dependency !-- 工具 -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.14.2/version /dependency /dependencies3. 项目结构src/main/java com.example.demo controller/ -- 控制层 service/ -- 业务层接口 service/impl/ -- 业务层实现 dao/ -- 数据访问层接口Mapper接口 entity/ -- 实体类POJO config/ -- Java配置类可选替代XML src/main/resources spring/ -- Spring配置文件 mybatis/ -- MyBatis映射文件 db.properties -- 数据库连接属性 logback.xml -- 日志配置 src/main/webapp WEB-INF web.xml -- 部署描述符 views/ -- JSP页面 static/ -- 静态资源3.2 配置文件的编写与整合1. web.xml - 配置DispatcherServlet和ContextLoaderListener 这是SSM整合的入口。DispatcherServlet加载Spring MVC的配置ContextLoaderListener加载Spring根容器的配置主要管Service、DAO等。?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 配置Spring根容器父容器 -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/applicationContext-*.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener !-- 配置Spring MVC的前端控制器DispatcherServlet子容器 -- servlet servlet-namedispatcherServlet/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcherServlet/servlet-name url-pattern//url-pattern /servlet-mapping !-- 字符编码过滤器 -- filter filter-namecharacterEncodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-namecharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping /web-app2. Spring根容器配置 (applicationContext.xml) 这里主要配置数据源、事务管理器、以及MyBatis的SqlSessionFactory。?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:txhttp://www.springframework.org/schema/tx xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd !-- 1. 扫描Service层组件 -- context:component-scan base-packagecom.example.demo.service/ !-- 2. 加载数据库属性文件 -- context:property-placeholder locationclasspath:db.properties/ !-- 3. 配置数据源Druid -- bean iddataSource classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ property nameinitialSize value5/ property nameminIdle value5/ property namemaxActive value20/ /bean !-- 4. 配置事务管理器 -- bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean !-- 开启注解驱动的事务管理 -- tx:annotation-driven transaction-managertransactionManager/ !-- 5. 配置MyBatis的SqlSessionFactory -- bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ !-- 指定MyBatis全局配置文件位置可选 -- property nameconfigLocation valueclasspath:mybatis/mybatis-config.xml/ !-- 指定Mapper XML文件的位置 -- property namemapperLocations valueclasspath:mybatis/mapper/*.xml/ !-- 配置实体类别名包 -- property nametypeAliasesPackage valuecom.example.demo.entity/ /bean !-- 6. 配置Mapper扫描器自动创建Mapper接口的代理Bean -- bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.example.demo.dao/ property namesqlSessionFactoryBeanName valuesqlSessionFactory/ /bean /beans3. Spring MVC配置 (spring-mvc.xml) 这里配置控制器扫描、视图解析器、静态资源处理等。?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:mvchttp://www.springframework.org/schema/mvc xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd !-- 1. 扫描Controller层组件 -- context:component-scan base-packagecom.example.demo.controller use-default-filtersfalse context:include-filter typeannotation expressionorg.springframework.stereotype.Controller/ /context:component-scan !-- 2. 开启MVC注解驱动自动注册RequestMappingHandlerMapping等 -- mvc:annotation-driven !-- 配置消息转换器解决ResponseBody返回JSON的中文乱码问题 -- mvc:message-converters bean classorg.springframework.http.converter.StringHttpMessageConverter property namesupportedMediaTypes list valuetext/html;charsetUTF-8/value valueapplication/json;charsetUTF-8/value /list /property /bean bean classorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter/ /mvc:message-converters /mvc:annotation-driven !-- 3. 静态资源处理不经过DispatcherServlet -- mvc:default-servlet-handler/ !-- 4. 配置视图解析器JSP -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean !-- 5. 配置拦截器可选 -- mvc:interceptors mvc:interceptor mvc:mapping path/**/ mvc:exclude-mapping path/login/ mvc:exclude-mapping path/static/**/ bean classcom.example.demo.interceptor.LoginInterceptor/ /mvc:interceptor /mvc:interceptors /beans4. MyBatis全局配置 (mybatis-config.xml) 这个文件不是必须的很多配置可以整合到Spring里。这里可以放一些全局设置比如开启驼峰命名映射。?xml version1.0 encodingUTF-8 ? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration settings !-- 开启驼峰命名自动映射数据库user_name字段自动映射到Java的userName属性 -- setting namemapUnderscoreToCamelCase valuetrue/ !-- 打印查询日志配合logback -- setting namelogImpl valueSLF4J/ /settings /configuration3.3 编写业务代码以用户管理为例1. 实体类 (User.java)package com.example.demo.entity; import java.util.Date; public class User { private Long id; private String username; private String password; private String email; private Integer status; private Date createTime; // 省略getter/setter和toString方法 }2. Mapper接口 (UserMapper.java)package com.example.demo.dao; import com.example.demo.entity.User; import org.apache.ibatis.annotations.Param; import java.util.List; public interface UserMapper { int insert(User user); int deleteById(Long id); int update(User user); User selectById(Long id); ListUser selectAll(); // 动态SQL查询示例 ListUser selectByCondition(Param(username) String username, Param(status) Integer status); }3. Mapper XML (UserMapper.xml)?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.demo.dao.UserMapper resultMap idBaseResultMap typeUser id columnid propertyid/ result columnusername propertyusername/ result columnpassword propertypassword/ result columnemail propertyemail/ result columnstatus propertystatus/ result columncreate_time propertycreateTime/ /resultMap insert idinsert parameterTypeUser useGeneratedKeystrue keyPropertyid INSERT INTO user (username, password, email, status, create_time) VALUES (#{username}, #{password}, #{email}, #{status}, #{createTime}) /insert select idselectByCondition resultMapBaseResultMap SELECT * FROM user where if testusername ! null and username ! AND username LIKE CONCAT(%, #{username}, %) /if if teststatus ! null AND status #{status} /if /where ORDER BY id DESC /select !-- 其他基础的CRUD SQL省略 -- /mapper4. Service层接口与实现// UserService.java package com.example.demo.service; import com.example.demo.entity.User; import java.util.List; public interface UserService { boolean addUser(User user); boolean deleteUser(Long id); boolean updateUser(User user); User getUserById(Long id); ListUser getUsersByCondition(String username, Integer status); } // UserServiceImpl.java package com.example.demo.service.impl; import com.example.demo.dao.UserMapper; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; Service Transactional // 声明式事务管理 public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override public boolean addUser(User user) { user.setCreateTime(new Date()); return userMapper.insert(user) 0; } // 其他方法实现... }5. Controller层package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.List; Controller RequestMapping(/user) public class UserController { Autowired private UserService userService; // 跳转到用户列表页 GetMapping(/list) public String listUsers(RequestParam(required false) String username, RequestParam(required false) Integer status, Model model) { ListUser users userService.getUsersByCondition(username, status); model.addAttribute(users, users); return user/list; // 对应 /WEB-INF/views/user/list.jsp } // 处理新增用户的AJAX请求 PostMapping(/add) ResponseBody // 返回JSON public MapString, Object addUser(RequestBody User user) { MapString, Object result new HashMap(); try { boolean success userService.addUser(user); result.put(success, success); result.put(message, success ? 添加成功 : 添加失败); } catch (Exception e) { result.put(success, false); result.put(message, 系统错误: e.getMessage()); } return result; } }3.4 部署与运行IDEA集成Tomcat配置Tomcat在IDEA中点击“Add Configuration”添加一个“Tomcat Server - Local”。部署工件在“Deployment”标签页点击“”选择“Artifact”添加你的项目生成的WAR包或WAR exploded推荐后者支持热更新。配置上下文路径可以设置为/或/ssm-demo。解决潜在问题“源发行版 17 需要目标发行版 17”警告在pom.xml中配置Maven编译插件或在IDEA的Project Structure中确保项目的Language level和Modules的Target bytecode version都是17。内存不足OutOfMemoryError在Tomcat配置的“VM options”中增加参数例如-Xms512m -Xmx1024m -XX:MaxMetaspaceSize256m。静态资源404确保spring-mvc.xml中配置了mvc:default-servlet-handler/或mvc:resources mapping/static/** location/static//。启动Tomcat访问http://localhost:8080/user/list即可看到页面。4. 进阶话题与生产环境避坑指南4.1 事务管理Transactional的正确使用姿势在SSM中事务通常通过Spring的Transactional注解来声明式管理。但使用不当事务会失效。事务失效的常见场景方法非publicTransactional只能用于public方法。自调用问题在同一个类中一个非事务方法A调用事务方法B事务不会生效。因为Spring的事务管理基于AOP代理自调用不走代理。异常类型不对默认只对RuntimeException和Error回滚。如果方法抛出了受检异常Exception事务不会回滚。需要用Transactional(rollbackFor Exception.class)。数据库引擎不支持如MySQL的MyISAM引擎不支持事务。多数据源未指定如果项目配置了多个数据源需要在Transactional中指定transactionManager。实操建议将事务注解放在Service层实现类的方法上而不是接口上虽然接口上也有效但Spring团队建议放在具体类上。明确指定回滚异常Transactional(rollbackFor Exception.class)。对于只读查询使用Transactional(readOnly true)数据库可能会做一些优化。4.2 解决SSM后台空值问题前端传参到后台经常遇到空字符串被映射成null或者日期格式解析失败的问题。1. 空字符串转null Spring MVC在数据绑定时默认会将空字符串转为null。如果你希望区分“用户没填”和“用户填了空字符串”可以自定义PropertyEditor或使用InitBinder在Controller中处理。InitBinder public void initBinder(WebDataBinder binder) { // 设置空字符串不转为null binder.registerCustomEditor(String.class, new StringTrimmerEditor(false)); }更常见的做法是在前端校验时避免提交空字符串或者在业务逻辑中统一按null处理。2. 日期类型绑定 前端传2023-10-01后台用Date接收会报错。解决方法使用DateTimeFormat注解PostMapping(/add) public String add(RequestParam DateTimeFormat(pattern yyyy-MM-dd) Date birthDate) { // ... }全局配置在配置类中实现WebMvcConfigurer接口重写addFormatters方法注册一个全局的日期格式化器。3. JSON序列化/反序列化问题 使用RequestBody接收JSON时Jackson库负责转换。空值处理可以在配置Jackson时设置// 在Spring MVC配置中配置ObjectMapper Bean public ObjectMapper objectMapper() { ObjectMapper mapper new ObjectMapper(); // 忽略null值字段不序列化到JSON mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 反序列化时忽略JSON中存在的未知属性 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper; }4.3 性能优化与监控1. MyBatis SQL监控 使用mybatis-log-free这类插件或在日志配置中直接输出MyBatis执行的SQL语句及参数是调试和性能分析的利器。在logback.xml中配置logger namecom.example.demo.dao levelDEBUG/ !-- 你的Mapper接口包 -- logger namejava.sql.Connection levelDEBUG/ logger namejava.sql.Statement levelDEBUG/ logger namejava.sql.PreparedStatement levelDEBUG/2. Druid连接池监控 Druid提供了强大的监控功能。在web.xml中配置Druid的StatViewServlet即可通过/druid/index.html访问监控后台查看SQL执行情况、连接池状态等。servlet servlet-nameDruidStatView/servlet-name servlet-classcom.alibaba.druid.support.http.StatViewServlet/servlet-class /servlet servlet-mapping servlet-nameDruidStatView/servlet-name url-pattern/druid/*/url-pattern /servlet-mapping务必记得配置访问白名单和账号密码切勿直接暴露在生产环境3. 分页查询优化 MyBatis可以使用PageHelper插件实现物理分页。它能自动将查询语句改写为带有LIMIT的分页语句避免内存分页的性能问题。整合PageHelper后在Service层只需PageHelper.startPage(pageNum, pageSize); // 紧跟在查询语句前 ListUser users userMapper.selectByCondition(username, status); PageInfoUser pageInfo new PageInfo(users);4.4 从SSM平滑迁移到Spring Boot的思考Spring Boot的本质是“约定大于配置”它内嵌了Tomcat提供了海量的Starter来简化依赖并提供了自动配置。如果你已经熟悉SSM迁移到Spring Boot会非常顺畅。核心变化配置方式从多个XML文件变为一个application.yml或application.properties文件。依赖管理从手动管理一堆dependency变为引入一个spring-boot-starter-web包含了Spring MVC、Tomcat等。MyBatis整合引入mybatis-spring-boot-starter几乎零配置即可使用。部署从打WAR包部署到外部Tomcat变为打可执行的JAR包内嵌Tomcat通过java -jar运行。迁移步骤创建一个Spring Boot项目。在pom.xml中添加spring-boot-starter-web和mybatis-spring-boot-starter依赖。将原来的applicationContext.xml和spring-mvc.xml中的配置转化为application.yml中的属性或Java配置类使用Configuration。将UserMapper.xml文件放在src/main/resources/mapper/目录下。在启动类上添加MapperScan(com.example.demo.dao)注解。删除web.xml。Spring Boot并没有颠覆SSM而是将其标准化和自动化了。理解SSM的每一个配置项在Spring Boot中是如何被自动配置的能让你在使用Spring Boot时更有底气遇到问题也能快速定位。例如当你需要自定义一个Filter时在SSM中是在web.xml里配置在Spring Boot中则是通过一个Configuration类来注册一个FilterRegistrationBean。其底层原理是相通的。