面经-SSM框架
常用注解
SpringBoot
@SpringBootApplication
1 | // 启动类上面加 |
@Configuration
1 | // config 包下的类都是配置类,这些类上面要加 @Configuration |
@Value(待完善)
1 | // @Value 用于注入外部属性值到 Spring 管理的 Bean 中。它可以读取配置文件(如.properties或.yml)、环境变量、系统属性,或直接指定默认值。 |
SpringMVC
@RestController(待完善)
1 | // 相当于 Restful + Controller |
@Controller
1 | // 在 controller 包下,一般用 RestController |
@RestControllerAdvice
1 | // 用于统一异常处理业务中的类名上 |
@ControllerAdvice
1 | // 用于统一异常处理业务中的类名上 |
@RequestMapping
1 | // 建立公共的请求路径 @RequestMapping("/depts") |
@ResponseBody
1 | // 若类用 @Controller 标注,需在方法上显式添加 @ResponseBody。 |
@RequestParm
1 | // 设置默认参数 |
@RequestBody & @Pathvariable
特性 | @PathVariable | @RequestBody |
---|---|---|
数据来源 | URL路径部分 | 请求体 |
常用场景 | GET/DELETE请求获取资源 | POST/PUT请求提交数据 |
数据格式 | 简单类型(String, Long等) | 复杂对象(JSON/XML等) |
1 | // 把前端传递的json数据填充到实体类中 |
Spring
基本注解(增加可读性)
注解 | 用途 | 适用场景 |
---|---|---|
@Component |
通用组件 | 普通 Bean |
@Service |
业务逻辑层 | Service 类 |
@Repository |
数据访问层 | DAO/Repository 类 |
@Controller |
Web 控制器 | MVC 的 Controller |
@Autowried
1 | // 自动注入 |
@Bean
1 | // 声明是一个 Bean 对象,告诉Spring:“此方法的返回值应注册为应用上下文中的一个Bean”,目前只在配置包下使用,方法名默认作为Bean的名称(可指定) |
@Aspect
1 | // 切面类,在AOP,如统计方法耗时的方法上使用 |
Spring
IOC
什么是 IOC
Spring的IOC,也就是控制反转,它的核心思想是让对象的创建和依赖关系由容器来控制,不是我们自己new出来的,这样各个组件之间就能保持松散的耦合。
这里的容器实际上就是个Map
, Map 中存放的是各种对象。Spring容器可以在运行时动态地将依赖注入到需要它们的对象中,而不是对象自己去寻找或创建依赖。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。举例来说,在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了。
如何配置
使用配置可以告诉Spring容器如何创建对象、如何管理对象的生命周期。Spring 时代我们一般通过 XML 文件来配置,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
总结来说,Spring的IOC容器是一个中央化的、负责管理应用中所有对象生命周期的强大工具
DI
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的.
DI**(依赖注入)其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。**
AOP
面向切面编程(Aspect Oriented Programming),或者面向方法编程。
面向切面编程,可以说是面向对象编程的补充和完善。OOP
(Object Oriented Programming) 引入封装、继承、多态等概念来建立一种对象层次结构。OOP
允许开发者定义纵向的关系,但并不适合定义横向的 关系,例如日志功能。AOP
技术恰恰相反,它利用一种称为”横切”的技术,剖解开封装的对象内部,将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为切面,降低模块之间的耦合度,有利于未来的操作和维护。
Spring
中AOP
代理由 Spring 的IOC
容器负责生成、管理,其依赖关系也由 IOC 容器负责管理。因此, AOP 代理可以直接使用容器中的其它 bean 实例作为目标。Spring 创建代理的规则为:
- 默认使用 JDK 动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
- 当需要代理类,而不是代理接口的时候,Spring 会切换为使用 CGLIB代理 ,也可强制使用 CGLIB
纵观 AOP 编程,程序员只需要参与三个部分:
- 定义普通业务组件
- 定义切入点,一个切入点可能横切多个业务组件
- 定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作
所以进行 AOP 编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP 框架将自动生成 AOP 代理,即: 代理对象的方法=增强处理+被代理对象的方法。
切入点代码
@Pointcut(“execution(* com.iweb.spring..(..))”)
Spring中AOP的通知类型
- @Around(“pointCut()”) :环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Before(“pointCut()”):前置通知,此注解标注的通知方法在目标方法前被执行
- @After(“pointCut()”):后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning(“pointCut()”): 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing(“pointCut()”): 异常后通知,此注解标注的通知方法发生异常后执行
设计模式
- 工厂设计模式 :
Spring
使用工厂模式通过BeanFactory
、ApplicationContext
创建bean
对象。 - 代理设计模式 :
Spring AOP
功能的实现。 - 单例设计模式 :
Spring
中的Bean
默认都是单例的。 - 模板方法模式 :
Spring
中jdbcTemplate
、hibernateTemplate
等以Template
结尾的对数据库操 作的类,它们就使用到了模板模式。 - 包装器设计模式 :我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式:
Spring
事件驱动模型就是观察者模式很经典的一个应用。 - 适配器模式 :
Spring AOP
的增强或通知(Advice)
使用到了适配器模式、Spring MVC
中也是用到了 适配器模式适配Controller
。
SpringMVC的执行流程
- 用户发送请求至前端控制器
DispatcherServlet
。 DispatcherServlet
收到请求调用HandlerMapping
处理器映射器。- 处理器映射器找到具体的处理器(可以根据
xml
配置、注解进行查找),生成处理器对象及处理器拦截 器(如果有则生成)一并返回给DispatcherServlet
。 DispatcherServlet
调用HandlerAdapter
处理器适配器。HandlerAdapter
经过适配调用具体的处理器(Controller
,也叫后端控制器)。Controller
执行完成返回ModelAndView
。HandlerAdapter
将controller
执行结果ModelAndView
返回给DispatcherServlet
。DispatcherServlet
将ModelAndView
传给ViewReslover
视图解析器。ViewReslover
解析后返回具体View
。DispatcherServlet
根据View
进行渲染视图(即将模型数据填充至视图中)DispatcherServlet
响应用户。
SpringBoot启动流程
- @SpringBootApplication
- SpringApplication.run()
- 实例化 ApplicationContext
- 加载 @EnableAutoConfiguration
- Bean 实例化,托管给 spring容器
SpringBoot Starter有什么用
Spring Boot Starter
的作用是简化和加速项目的配置和依赖管理。
Spring Boot Starter
可以理解为一种预配置的模块,它封装了特定功能的依赖项和配置, ,开发者只需引入相关的Starter
依赖,无需手动配置大量的参数和依赖项。常用的启动器包括spring-boot-starter-web
(用于Web应用)、spring-boot-starter-data-jpa
(用于数据库访问)等。 引入这些启动器后,Spring Boot
会自动配置所需的组件和Bean
,无需开发者手动添加大量配置。- Starter还管理了相关功能的依赖项,包括其他Starter和第三方库,确保它们能够良好地协同工作,避免版本冲突和依赖问题。
Spring Boot Starter
的设计使得应用可以通过引入不同的Starter来实现模块化的开发。每个Starter都关注一个特定的功能领域,如数据库访问、消息队列、Web开发等。- 开发者可以创建自定义的
Starter
,以便在项目中共享和重用特定功能的配置和依赖项。
Spring,Spring MVC,Spring Boot的区别
- spring 是容器,服务层框架
- springmvc 是基于 mvc 的web 框架,servlet
- springboot 快速构建,快速部署
Spring 循环依赖是怎么解决的
什么是循环依赖
两个或者两个以上的 bean
互相持有对方,最终形成闭环。比如 Bean A
依赖于 Bean B
,而 Bean B
又依赖于 Bean A
,形成了一个循环依赖关系。这种情况下,如果不处理,会导致 Spring
容器无法完成 Bean
的初始化,从而抛出循环依赖异常。

怎么检测是否存在循环依赖
检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明产生循环依赖了。
如何解决

构造器循环依赖:Spring容器在创建Bean时,如果遇到循环依赖,通常是无法处理的,因为这会导致无限递归创建Bean实例。所以,构造器注入是不支持循环依赖的。
字段注入或Setter注入:使用了三级缓存来解决循环依赖问题。
- 首先,Spring容器会创建一个Bean的原始实例,但此时Bean的属性尚未设置,这个实例被存放在一级缓存中。
- 当Bean的属性被设置时,如果属性值是其他Bean的引用,Spring会去检查二级缓存,看是否已经有该Bean的引用存在。
- 如果二级缓存中没有,Spring会尝试创建这个被引用的Bean,并将其放入三级缓存。
- 最后,当Bean的属性设置完成后,原始的Bean实例会被放入二级缓存,供其他Bean引用
使用
@Lazy
注解:通过@Lazy
注解,可以延迟Bean的加载,直到它被实际使用时才创建,这可以避免一些循环依赖的问题。
Bean的生命周期

背诵技巧:通天(填)A(Aware),B始(使)毁
Spring Bean的生命周期,其实就是Spring容器从创建Bean到销毁Bean的整个过程。这里面有几个关键步骤:
- 实例化Bean: Spring容器通过构造器或工厂方法创建Bean实例。
- 设置属性:容器会注入Bean的属性,这些属性可能是其他Bean的引用,也可能是简单的配置值。
- 检查Aware接口并设置相关依赖:如果Bean实现了
BeanNameAware
或BeanFactoryAware
接口,容器会调用相应的setBeanName
或setBeanFactory
方法。 BeanPostProcessor
的第一次调用:在Bean初始化之前,Spring会调用所有注册的BeanPostProcessor
的postProcessBeforeInitialization
方法。- 初始化
Bean
: 如果Bean实现了InitializingBean
接口,容器会调用其afterPropertiesSet
方法。同时,如果Bean定义了init-method
,容器也会调用这个方法。 BeanPostProcessor
的第二次调用:在Bean初始化之后,容器会再次调用所有注册的BeanPostProcessor
的postProcessAfterInitialization
方法。- 使用Bean:此时,Bean已经准备好了,可以被应用程序使用了。
- 处理
DisposableBean
和destroy-method
:当容器关闭时,如果Bean实现了DisposableBean
接口或者定义了destroy-method
,容器会调用其destroy
方法。 - Bean销毁:最后,Bean被Spring容器销毁,结束了它的生命周期。
Mybatis
$和# 区别
- $是字符串拼接
- #是参数传递,对sql语句进行了预编译,解决了sql注入
sql注入(SQL Injection)是一种常见的Web安全漏洞,形成的主要原因是web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句。
如”or “a”=”a
分页实现
基础分页
流程
注意:要查询数据库两次
- 查询全表数据
- SQL语句 limit
Pagehelper插件(⭐业务)
- 在 maven 文件中引入 pagehelper 依赖;
- 创建分页结果封装类 PageBean,包含两个参数,total 总记录数,rows 数据列表;
- 在 serviceImpl 类下的 分页方法中调用 PageHelper.startPage(page,pageSize);
- 返回 PageBean 对象。
在pom.xml引入依赖
1 | <dependency> |
创建分页结果封装类
1 | package com.itheima.pojo; |
ServiceImpl
1 |
|
Mapper
1 | public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end); |
Mapper.xml
1 | <!--条件查询--> |
动态sql的作用
特点
- 多条件查询
- 选择性插入
- 选择性修改
动态SQL的标签
where、set、if、trim