SSM框架
SSM = Spring + Spring MVC + MyBatis,是Java Web开发最经典的三大框架组合。Spring管理Bean和事务,SpringMVC处理Web层请求分发,MyBatis负责数据库持久层。三者整合形成完整的三层架构(表现层→业务层→持久层)。
一、Spring 核心
1.1 IoC(控制反转)与 DI(依赖注入)
IoC(Inversion of Control):将对象的创建和依赖关系管理权从程序代码交给Spring容器,实现解耦。DI(Dependency Injection)是IoC的具体实现方式,容器在运行时将依赖注入到目标对象中。
依赖注入的三种方式
|
方式 |
实现 |
推荐度 |
|---|---|---|
|
构造器注入 |
@Autowired 或 @RequiredArgsConstructor + final字段 |
✅ 推荐(不可变、空指针安全) |
|
Setter注入 |
@Autowired 标注setter方法 |
可选依赖时使用 |
|
字段注入 |
@Autowired 直接标注字段 |
❌ 不推荐(反射注入、难测试、隐藏依赖) |
1.2 Spring Bean
Bean的作用域(Scope)
|
作用域 |
说明 |
|---|---|
|
singleton(默认) |
整个IoC容器中只有一个实例(单例)。Spring容器启动时创建,线程不安全,字段不能存状态 |
|
prototype |
每次getBean/createBean都创建新实例。容器不管理完整生命周期(初始化和销毁回调需自行调用) |
|
request |
每次HTTP请求创建新实例(Web应用) |
|
session |
每个HTTP Session一个实例(Web应用) |
|
application |
ServletContext生命周期内一个实例 |
Bean的生命周期
- 实例化:反射创建对象(推断构造器 → newInstance)
- 属性填充:依赖注入,填充@Autowired注解的属性
- Aware回调:调用BeanNameAware → BeanFactoryAware → ApplicationContextAware
- 前置处理:BeanPostProcessor.postProcessBeforeInitialization()(@PostConstruct在此之后调用)
- 初始化:@PostConstruct 或 InitializingBean.afterPropertiesSet() 或 @Bean(initMethod = "init")
- 后置处理:BeanPostProcessor.postProcessAfterInitialization()(AOP在此阶段生成代理对象)
- 就绪:Bean可用,被应用程序使用
- 销毁:@PreDestroy 或 DisposableBean.destroy() 或 @Bean(destroyMethod)
循环依赖:Spring通过三级缓存(singletonObjects→earlySingletonObjects→singletonFactories)解决构造器注入无法解决的循环依赖。只有单例且Setter注入的循环依赖可以解决,prototype和构造器注入的循环依赖抛BeanCurrentlyInCreationException。
1.3 AOP(面向切面编程)
AOP通过动态代理在方法前后插入横切逻辑(日志、事务、权限、缓存),将核心业务与通用逻辑分离,消除重复代码。
核心概念
|
术语 |
说明 |
|---|---|
|
切面(Aspect) |
横切逻辑的类,包含通知+切入点。@Aspect注解标记 |
|
连接点(JoinPoint) |
程序执行过程中的点(方法调用、异常抛出)。Spring AOP仅支持方法级别的JoinPoint |
|
切入点(Pointcut) |
匹配连接点的表达式。execution(* com.example.service.*.*(..))匹配service包下所有方法 |
|
通知(Advice) |
切面在特定连接点上执行的动作(Before/AfterReturning/AfterThrowing/After/Around) |
|
织入(Weaving) |
将切面应用到目标对象创建代理的过程。编译时(AspectJ)、类加载时、运行时(Spring AOP默认) |
5种通知类型
|
通知 |
执行时机 |
|---|---|
|
@Before |
目标方法执行前。不能阻止方法执行 |
|
@AfterReturning |
目标方法正常返回后。可以获取返回值(returning属性) |
|
@AfterThrowing |
目标方法抛出异常后。可以获取异常信息(throwing属性) |
|
@After(最终通知) |
目标方法执行后(无论正常返回还是异常)。类似finally |
|
@Around(环绕通知,最强) |
包裹目标方法前后。通过ProceedingJoinPoint.proceed()控制方法执行。可修改参数、返回值、吞异常 |
Spring AOP底层原理:JDK动态代理 vs CGLIB
|
对比 |
JDK动态代理 |
CGLIB代理 |
|---|---|---|
|
要求 |
目标类必须实现接口 |
目标类不能被final修饰(通过继承创建子类) |
|
实现 |
java.lang.reflect.Proxy + InvocationHandler |
ASM字节码技术生成子类 |
|
Spring默认 |
Spring Boot 1.x默认JDK |
Spring Boot 2.x起默认CGLIB(proxy-target-class=true) |
|
性能 |
反射调用,微慢 |
直接调用,微快 |
|
局限性 |
只能代理接口方法 |
final类/方法不能代理;构造器被调用两次 |
1.4 Spring 事务管理
声明式事务(@Transactional)基于AOP实现。方法开始→开启事务→执行业务逻辑→正常返回则提交→异常则按rollbackFor决定回滚或提交。
@Transactional核心属性
|
属性 |
说明 |
|---|---|
|
propagation |
事务传播行为。REQUIRED(默认,加入或无则新建)、REQUIRES_NEW(挂起当前,新建事务)、NESTED(嵌套savepoint)、SUPPORTS/NOT_SUPPORTED/NEVER/MANDATORY |
|
isolation |
隔离级别。DEFAULT(数据库默认)、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE |
|
rollbackFor |
指定哪些异常回滚。默认只回滚RuntimeException和Error,受检异常不回滚(需显式指定) |
|
timeout |
事务超时时间(秒)。-1表示不限制 |
|
readOnly |
只读事务(true时不允许修改,性能优化)。默认false |
事务失效的6种场景:(1) 类内部非事务方法调事务方法(自调用,this调用不经过代理) → 注入自身/AopContext.currentProxy() (2) 非public方法 → CGLIB不能代理 (3) 异常被catch吞掉 → 事务收不到异常 (4) rollbackFor指定错误 (5) 多线程(新线程不在事务内) (6) 数据库引擎不支持事务(MyISAM)。
二、Spring MVC
2.1 核心架构:DispatcherServlet
Spring MVC基于前端控制器模式,DispatcherServlet作为唯一入口,统一接收所有请求并分发给对应的Controller处理。
请求处理全流程
- 请求到达:所有请求首先到达DispatcherServlet(前端控制器)
- 映射查找:DispatcherServlet调用HandlerMapping,根据URL找到对应的Controller和方法(Handler)
- 处理器适配:通过HandlerAdapter调用具体的Controller方法(适配不同类型的Handler)
- 业务处理:Controller调用Service层执行业务逻辑,返回ModelAndView(或@ResponseBody直接返回JSON)
- 视图解析:ViewResolver将逻辑视图名解析为实际View(JSP/Thymeleaf/FreeMarker)
- 渲染输出:View渲染模型数据,生成HTML/JSON响应返回客户端
2.2 核心组件
|
组件 |
作用 |
|---|---|
|
DispatcherServlet |
前端控制器,所有HTTP请求的统一入口和调度中心 |
|
HandlerMapping |
负责URL→Controller映射。RequestMappingHandlerMapping处理@Controller和@RequestMapping注解 |
|
HandlerAdapter |
调用Handler(Controller方法),适配不同类型的处理器。RequestMappingHandlerAdapter处理注解方式 |
|
Handler(Controller) |
具体的业务处理器,处理请求返回结果 |
|
ViewResolver |
将逻辑视图名解析为实际View。InternalResourceViewResolver处理JSP,ThymeleafViewResolver处理Thymeleaf |
|
HttpMessageConverter |
HTTP请求/响应体的序列化/反序列化。@RequestBody/@ResponseBody用MappingJackson2HttpMessageConverter处理JSON |
|
HandlerExceptionResolver |
统一异常处理。@ExceptionHandler → @ControllerAdvice → 全局异常处理 |
|
Interceptor(拦截器) |
请求前后拦截处理(日志、权限、跨域)。preHandle→postHandle→afterCompletion |
2.3 核心注解
|
注解 |
作用 |
|---|---|
|
@Controller + @ResponseBody = @RestController |
标记控制器类,所有方法返回JSON。@RestController = @Controller + @ResponseBody(Spring 4.0+) |
|
@RequestMapping |
URL映射(可指定method/params/headers/produces)。简化版:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping |
|
@RequestParam |
获取URL参数 ?key=value。required=false时可选,defaultValue设置默认值 |
|
@PathVariable |
获取路径变量 /user/{id}。与@RequestParam区分 |
|
@RequestBody |
获取POST/PUT请求体的JSON,自动反序列化为Java对象 |
|
@RequestHeader |
获取请求头信息。@RequestHeader("Authorization") |
|
@CookieValue |
获取Cookie值 |
|
@ModelAttribute |
将请求参数绑定到对象(表单提交) |
2.4 拦截器 vs 过滤器
|
对比 |
Filter(过滤器) |
Interceptor(拦截器) |
|---|---|---|
|
所属 |
Servlet规范,Tomcat容器管理 |
Spring MVC框架提供 |
|
执行顺序 |
先执行(在Servlet之前/之后) |
后执行(在DispatcherServlet后,Controller前) |
|
能否获取Bean |
不能直接获取(是Servlet容器管理的) |
可以(Spring管理的Bean可通过@Autowired注入) |
|
适用场景 |
编码设置、XSS过滤、CORS、请求日志 |
登录校验、权限验证、日志AOP、性能监控 |
|
粒度 |
只能拿到request/response(没有请求方法信息) |
能拿到Handler(Controller+方法),更精准控制 |
三、MyBatis
3.1 核心架构
MyBatis是半自动ORM框架,开发者自己写SQL,框架负责SQL解析、参数映射、结果集映射。相比全自动ORM(Hibernate),MyBatis对SQL有完全控制力,适合复杂查询和性能优化场景。
3.2 核心组件
|
组件 |
作用 |
|---|---|
|
SqlSessionFactory |
根据配置文件构建,线程安全,全局唯一。解析mybatis-config.xml和Mapper XML |
|
SqlSession |
一次数据库会话,非线程安全,用完即关。提供selectOne/selectList/insert/update/delete等方法 |
|
Executor |
执行器,负责SQL执行、缓存维护、事务管理。SIMPLE(默认)/REUSE(缓存Statement)/BATCH(批处理) |
|
MappedStatement |
封装了SQL、参数映射、结果映射、缓存配置等元信息(每个<select>/<insert>/<update>/<delete>对应一个) |
|
StatementHandler |
处理JDBC Statement,设置参数、执行SQL、映射结果。含ParameterHandler和ResultSetHandler |
|
TypeHandler |
Java类型 ↔ JDBC类型转换。如java.util.Date ↔ java.sql.Timestamp |
3.3 XML映射 vs 注解
#{} vs ${}:#{}是预编译占位符,安全防止SQL注入,自动加引号。${}是字符串拼接替换,有SQL注入风险,仅用于表名/列名等动态标识符。生产环境优先使用#{}。
3.4 动态SQL
|
标签 |
作用 |
|---|---|
|
<if test="条件"> |
条件判断,满足条件时拼入SQL片段。test中用OGNL表达式,and/or连接 |
|
<where> |
包裹<if>等标签,自动处理WHERE关键字,去除开头的AND/OR |
|
<choose>/<when>/<otherwise> |
类似switch-case-default,多选一 |
|
<foreach> |
遍历集合。collection=list/array/@Param名;item=元素;open/close=首尾字符;separator=分隔符 |
|
<set> |
动态UPDATE,自动处理SET关键字,去除末尾逗号 |
|
<trim> |
更灵活的字符串截取。prefix/suffix(前缀/后缀)、prefixOverrides/suffixOverrides(去除首/尾指定字符) |
|
<sql> + <include> |
SQL片段复用。<sql id="cols">id,name,email</sql> → <include refid="cols"/> |
3.5 缓存机制
一级缓存(SqlSession级别,默认开启)
- 作用范围:同一个SqlSession内,同样的查询只执行一次SQL,后续从缓存取
- 失效条件:执行增删改操作(commit)、手动清缓存(clearCache())、不同SqlSession
二级缓存(Mapper级别,默认关闭)
- 作用范围:同一个namespace(Mapper接口)下,不同SqlSession共享
- 启用:mybatis-config.xml中 setting cacheEnabled=true + Mapper XML中加<cache/>
- 要求:实体类必须实现Serializable(因为需要序列化存储)
- 命中顺序:二级缓存 → 一级缓存 → 数据库
- 注意:在生产环境不推荐使用,用Redis等分布式缓存替代(跨实例一致性)
3.6 MyBatis工作流程
- 加载mybatis-config.xml和Mapper XML → 解析为Configuration对象 → 构建SqlSessionFactory
- SqlSessionFactory.openSession()创建SqlSession(同时创建Executor和Transaction)
- getMapper(UserMapper.class) → JDK动态代理生成Mapper代理对象
- 调用mapper.selectById(1) → 代理拦截 → 根据全限定名+方法名查找MappedStatement
- Executor执行:查二级缓存 → 查一级缓存 → 执行SQL → StatementHandler设置参数 → JDBC执行
- ResultSetHandler将ResultSet映射为Java对象(通过ResultMap或自动映射)
- 返回结果 → 放入一级缓存 → 关闭SqlSession
3.7 MyBatis-Plus
MyBatis-Plus是MyBatis的增强工具,在MyBatis基础上只做增强不做改变。提供通用CRUD(BaseMapper)、条件构造器(Wrappers)、分页插件(PaginationInnerInterceptor)、自动填充等开箱即用功能。
|
特性 |
使用方式 |
|---|---|
|
通用CRUD |
extends BaseMapper<User>,无需写SQL即可获得insert/deleteById/updateById/selectById/selectList |
|
条件构造器 |
Wrappers.<User>lambdaQuery().eq(User::getName, "张三").gt(User::getAge, 18) |
|
分页插件 |
Page<User>.of(pageNum, pageSize) → selectPage → 自动分页COUNT+LIMIT |
|
逻辑删除 |
@TableLogic,delete自动转为UPDATE SET deleted=1(逻辑删除而非物理删除) |
|
自动填充 |
@TableField(fill = FieldFill.INSERT),配合MetaObjectHandler自动填充createTime/updateTime |
|
乐观锁 |
@Version 注解 + version字段,update时自动WHERE version = #{et.version} AND SET version = version + 1 |
四、SSM整合
4.1 三层架构
表现层(Controller):SpringMVC接收HTTP请求,参数校验,调用Service → 业务层(Service):Spring管理事务(@Transactional),编排业务逻辑 → 持久层(Dao/Mapper):MyBatis执行SQL操作数据库。
4.2 典型配置
4.3 Spring Boot整合要点
|
功能 |
核心注解/配置 |
|---|---|
|
Spring容器 |
@SpringBootApplication(包含@Configuration + @EnableAutoConfiguration + @ComponentScan) |
|
SpringMVC |
自动配置,spring-boot-starter-web依赖。@RestController处理请求 |
|
MyBatis |
mybatis-spring-boot-starter。@MapperScan("com.example.mapper") 扫描Mapper接口 |
|
事务 |
spring-boot-starter-jdbc / aop,@EnableTransactionManagement + @Transactional |
|
数据源 |
application.yml 配置 spring.datasource.url/username/password/driver-class-name。默认HikariCP连接池 |
面试高频梳理:
- Spring必问:IoC/DI概念、Bean生命周期、AOP原理(JDK/CGLIB)、@Transactional事务失效场景、循环依赖
- SpringMVC必问:DispatcherServlet处理流程、Filter vs Interceptor、@RestController注解组合
- MyBatis必问:#{}和${}区别、一级/二级缓存、动态SQL、工作流程
- 整合:三层架构职责划分、Spring Boot自动配置原理