主题
SSM 框架 待完善
什么是 SSM 框架?
SSM = Spring + Spring MVC + MyBatis
Spring 概述
什么是 Spring?
Spring 是一个分层的轻量级开源框架。
Spring 核心:控制翻转 IoC 和面向切面编程 AOP
IoC:Inversion of Control
AOP:Aspect Orient Programming
使用 Spring 的好处是什么?
提示
高耦合低内聚(通过DI)、模块化、AOP、集成框架、社区
- Spring 实现了高耦合低内聚,Spring 采用依赖注入的方式管理组件依赖关系。
- Spring 采用模块化设计,各个模块之间相互独立,可以灵活使用。
- 支持面向切片编程,将系统服务和业务逻辑分开
- Spring 对主流框架进行了集成和支持
- Spring 拥有庞大的开发者社区
Spring 有哪些模块,层次架构是怎样的?
Spring 具有七大模块。
- Spring Core:核心模块,实现 IoC 和 DI
- Spring Beans:管理 Bean 对象
- Spring Context:提供框架式的对象访问方法
- Spring JDBC:用于简化 JDBC 操作
- Spring AOP:提供面向切片编程
- Spring Web:支持 Web 开发
- Spring Test:集成 Junit 测试框架
Spring 用了哪些设计模式?
- 工厂模式:Spring 通过工厂模式使用 BeanFactory、ApplicationContext 创建 Bean 对象。
- 代理模式:Spring 使用代理模式实现了 AOP 面向切面编程。
- 单例模式:Spring 创建的 Bean 对象都是单例的,便于管理和使用。
- 模板模式:Spring 中提供了如 JDBCTemplate 的模板类。
- 观察者模式:Spring 事件驱动模型(类似消息队列)。
- 适配器模式:Spring MVC 使用了适配器模式适配 Controller,通过不同的实现类统一调用不同类型的实现类。
- 策略模式:Spring 有一个 Resource 接口,不同的实现类会以不同策略访问资源。
Spring IoC
什么是 IoC?说一说你对 IoC 的理解
提示
IoC 的核心是程序要依赖于接口,而不是具体实现类。
IoC 主要实现方式为 DI 依赖注入,程序代码只需要声明对象的依赖关系,Spring 容器负责创建对象和管理依赖。
IoC 是控制翻转。核心是程序要依赖于接口,而不是具体实现类。作用是降低代码耦合度。Spring IoC 是 Spring 框架的核心,用于管理 Bean 对象。
Spring 容器负责创建对象,管理依赖关系等,实现控制翻转。应用只需要声明对象依赖关系,降低了代码耦合度。
IoC 主要实现方式为 DI 依赖注入。对于依赖的对象,不通过 new 的方式创建对象,而是在外部创建好后传入。有 Setter 方法注入、构造方法注入、字段注入等方式。
另一种实现是依赖查找,通过容器的 API 查找依赖的对象。
什么是依赖注入 DI?
依赖注入是指,在需要其他对象时,不在代码中创建新对象,而是通过 Spring 容器传入已经创建好的对象。
IoC 的实现原理是什么?
提示
扫描注解 → 解析依赖 → 反射创建对象
- 扫描和解析配置或注解,转换成内部对象定义和依赖关系
- 根据关系使用反射动态创建对象,并注入到需要的地方
IoC 和 DI 有什么关系?
IoC 控制翻转是实现思想,DI 依赖注入是实现 IoC 的具体方式之一
Spring Bean
什么是 Spring Bean
Spring Bean 是托管在 Spring IoC 容器中的对象。
Spring Bean 是 Spring 的基本单元,程序是由多个 Bean 对象构成的。
注入 Bean 的注解有哪些?
有两个,分别是 @Autowire
和 @Resource
- Autowire 是 Spring 的注解,Resource 是 JDK 提供的注解
- Autowire 默认通过类型匹配,Resource 默认通过名称匹配
- Autowire 支持在构造函数、方法、字段和参数上注入,Resource 只能在字段和方法上注入。
- 当一个接口有多个实现类,两者都需要通过指定名称,可以显式(注解中指定)和隐式(变量名)声明。
将一个类声明为 Bean 的方式有什么?
- @Component:任意类
- @Repository:Dao 层
- @Service:服务层
- @Controller:MVC 控制器层
Bean 的作用域有哪些?
- singleton(单例)
- prototype(原型):每次获取都创建新实例
- request(请求):每次 HTTP 请求都会创建新实例,在当前 HTTP 请求内有效。
- session(会话):每个 HTTP 会话都会创建新实例,在当前会话内有效
- websocket:每次 ws 产生新实例
- global session(全局会话):在 Web 应用运行中有效。
Bean 的生命周期是什么
- 实例化:通过反射创建对象,调用无参构造方法
- 属性赋值:依赖注入
- 初始化:执行初始化逻辑
- 初始化前:@PostConstruct
- 初始化:继承 InitializingBean
- 初始化后:执行 AOP
- 使用 Bean 实例
- 销毁
什么是 FactoryBean?
FactoryBean 是 Spring 提供的一种创建 Bean 的方式。
可以通过实现 FactoryBean 接口中的 getObject()
方法来返回一个 Bean 对象。
BeanFactory 和 FactoryBean 区别是什么?
BeanFactory:用于创建和管理 Bean 实例
用于策略模式中,通过名称在 BeanFactory 中获取 Bean。
FactoryBean:一种创建 Bean 的方式
一个实现 FactoryBean 接口的特殊 Bean,负责创建其它的 Bean。
BeanFactory 和 ApplicationContext 的关系是什么?
BeanFactory 是 Spring 框架中的容器,提供 IoC 和 DI 的支持,用于⽣成Bean、维护Bean。
ApplicationContext 基于 BeanFactory,并提供了更多的功能和特性,比如获取系统环境变量、国际化、事件发布等。
Bean 是线程安全的吗?
对于多例 Bean(原型 Bean),每次获取都会生成新的对象,所以是线程安全的。
对于单例 Bean,对于无状态(不包含可变的成员变量)的 Bean 是线程安全的。如果需要包含成员变量,可以使用 ThreadLocal 保存成员变量保证安全。
❓Spring 的三级缓存是什么?
TDB...
❓为什么 Spring 需要三级缓存?
TDB...
❓Spring 如何解决循环依赖的问题?
TDB...
❓Spring 可以存在两个 ID 相同的 Bean 吗?
TDB...
Spring AOP
什么是 AOP?
AOP 是面向切片编程。通过代理的方式,在方法调用时进行拦截处理,先执行切入的逻辑,再调用方法。
说一说对 AOP 的理解
AOP 面向切片编程通过在运行期间动态代理目标对象,将横切关注点织入到系统中,实现了业务逻辑与横切关注点的分离。
AOP 有哪些实现方式?
AOP 分为静态代理和动态代理。
- 静态代理:在编译期生成代理类,比如 AspectJ。代理对象需要和目标对象实现相同的接口,需要维护两个类的代码。
- 动态代理:在运行时动态生成代理类。
- JDK 动态代理:必须实现一个接口,通过反射实现。
- CGLIB 动态代理:通过继承的方式生成代理子类
Spring AOP 和 AspectJ AOP 有什么区别?
Spring AOP 是运行时增强,AspectJ AOP 是编译时增强。
AspectJ AOP 有更好的性能。
谈一谈动态代理
Java 动态代理可以在运行时动态生成代理类和对象,无需编写静态代理类。
- JDK 动态代理:基于接口的动态代理
- CGLIB 动态代理:基于类的动态代理
Spring 注解
有哪些常用的 Spring 注解
- 控制器类:@Controller、@RestController、@RequestMapping、@PathVariable、@ResponseBody
- 服务类:@Service
- 依赖注入:@Resource、@Autowired
- 声明 Bean:@Bean
- 切面编程:@Aspect、@Before、@After、@Around
@Componet 和 @Bean 的区别?
@Component 可以用在类上,通过类路径扫描注入到 Spring 容器。
@Bean 用在方法上,在配置类中声明单个 Bean 对象。
@Configuration 和 @Component 有什么区别?
@Component
用于将该类定义为 Bean。
@Configuration
该类内部的方法可以使用 @Bean
注解来定义 Bean。
@Required 注解有什么用?
@Required
注解用于标注在 Spring Bean 的 setter 方法上,表示该属性是必须的。
java
public class MyBean {
private String name;
@Required
public void setName(String name) {
this.name = name;
}
}
@Autowired 和 @Qualifier 注解有什么用?
@Autowired
:用于自动装配 Bean,可以标注在字段、setter 方法或者构造方法上
@Qualifier
:与 @Autowired
结合使用,用于在有多个相同类型的 Bean 时,指定具体要注入的 Bean
java
public class MyService {
@Autowired
@Qualifier("specificBeanName")
private MyRepository myRepository;
}
@RequestMapping 注解有什么用?
用于将特定的 HTTP 请求方法和路径映射到特定的方法和类上。
- 用于类上:映射当前类请求的 URL
- 用于方法上:映射当前方法请求的 URL 和 HTTP 请求方法
@Controller 注解有什么用?
@Controller
注解用来标记该类为 Spring MVC 控制器类。Spring 会扫描该类中标记 @RequestMapping
的方法,创建控制器对象。
@RestController 和 @Controller 有什么区别?
@RestController
在 @Controller
的基础上添加了 @ResponseBody
注解。适合使用在前后端分离架构中,提供 Restful API 并返回 JSON 数据。
@RequestParam 和 @PathVariable 两个注解的区别?
@RequestParam
:在请求 URL 中携带的参数获取
@PathVariable
:在请求 URL 路径中获取
❓Spring 事务
Spring 实现事务方式有什么?
- 编程式事务:通过
TransactionTemplate
和TransactionManager
手动管理事务 - 声明式事务
- 创建事务管理器
- 在接口方法上使用
@Transactional
注解 - 在配置类中声明开启事务注解
@EnableTransactionManagement
Spring MVC
什么是 Spring MVC?
Spring MVC 是一个实现了 MVC 模型的请求驱动型 Web 框架。
MVC 模型是把 "模型-视图-控制器" 分离,通过职责进行解耦。
请求驱动型:在接收到请求后,会执行相应的操作并返回结果
说一说 Spring MVC 的执行流程
- 用户发送出请求到前端控制器 DispatcherServlet(前端控制器)
- DispatcherServlet(前端控制器)收到请求调用 HandlerMapping(处理器映射器)
- HandlerMapping(处理器映射器)找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给 DispatcherServlet(前端控制器)
- DispatcherServlet(前端控制器)调用 HandlerAdaptor(处理器适配器)
- HandlerAdaptor(处理器适配器)经过适配调用具体的处理器(Handler/Controller)
HandlerMapping(处理器映射器):将请求路由到正确的处理器。
HandlerAdapter(处理器适配器):调用 Handler 的方法来处理请求。
返回视图 View 的流程:
Spring MVC 拦截器是什么?
Spring MVC 拦截器是一种机制,用于在请求和响应进行预处理和后处理。
常用于一些场景:
- 鉴权
- 刷新 token 有效期
- 重定向
- 缓存
- 记录日志 / 计算请求时长
Spring MVC 如何配置拦截器?
实现 HandlerInterceptor 接口,在 MVC 配置类中添加拦截器,配置拦截路径。
过滤器和拦截器的差异?
- 使用范围
- 过滤器是 Servlet 规范,依赖于 Tomcat 容器
- 拦截器是 Spring 组件
- 触发时机:先触发过滤器,再触发拦截器
- 底层实现
- 过滤器通过方法回调实现
- 拦截器通过动态代理反射实现
如何实现拦截器?
过滤器可以使用 @WebFilter 注解,配置过滤的 URL 规则,实现Filter接口,再重写接口中的 vdoFilter 方法。
java
@Component
@WebFilter("/*") // 这个过滤器将拦截所有请求
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 过滤器初始化逻辑(如果有需要的话)
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 在请求到达目标 Servlet 之前执行一些操作
System.out.println("Request intercepted by MyFilter");
// 继续执行过滤链
chain.doFilter(request, response);
// 在响应返回给客户端之前执行一些操作
System.out.println("Response intercepted by MyFilter");
}
@Override
public void destroy() {
// 过滤器销毁逻辑(如果有需要的话)
}
}
说一说 Spring MVC 异常处理
异常处理可以拦截和处理控制器中的异常,返回自定义的错误响应。
- @RestControllerAdvice:返回 JSON
- @ControllerAdvice:返回视图或模板
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public BaseResponse handleRuntimeException(RuntimeException e) {
return ResponseUtils.error("API Error: RuntimeException");
}
}
MyBatis
什么是 MyBatis?
Mybatis 是一个封装了 JDBC 的 ORM 框架,用于数据库的数据和 Java 对象的映射。
MyBatis 的优点是什么?
- 基于 SQL,使用灵活
- 降低了 JDBC 的使用成本
- 实现数据库数据和 Java 对象的映射
Mybatis 和 Hibernate 的区别是什么?
MyBatis 是半自动化 ORM 框架,需手写 SQL,精细度较高。
Hibernate 是全自动化 ORM 框架,生成 SQL 并提供完整的对象关系映射。
MyBatis 使用了哪些设计模式?
- 缓存模块使用了装饰器模式,通过多个装饰类对缓存对象进行增强
- 日志模式使用了适配器模式(策略模式),适配 SLF4J、Log4J等
- BaseExecutor 使用了模板方法模式,实现了大部分的 SQL 执行逻辑
- Mapping 使用了代理模式
- 反射模块使用了工厂模式和装饰器模式
- SqlSessionFactoryBuilder 使用了建造者模式
- ErrorContext 用于记录错误信息,是线程级别的单例模式
MyBatis 工作原理是什么?
- 加载 Mybatis 全局配置文件(mybatis-config.xml)和映射文件(xxxMapper)
- 构造会话工厂
SqlSessionFactory
,创建会话对象SqlSession
- 调用 SqlSession 提供的执行器,执行 Mapper 中定义的 SQL 操作数据库
- 将输入输出参数映射到 Java 对象
介绍一下 MyBatis 的缓存
MyBatis 的缓存可以减低数据库的负载,提高响应速度。
MyBatis 的缓存使用了装饰者模式,用于扩展缓存的功能。
Mybatis 默认使用一级缓存(Session 级别),且支持二级缓存(SqlSessionFactory 级别 / 进程级别)。
缓存顺序:二级缓存 → 一级缓存 → 数据库。
先查询二级缓存的原因:二级缓存是 SqlSessionFactory 级别,缓存的内容比一级缓存多,提高查询效率。
在 mybatis-config.xml 中配置缓存。
Mybatis 都有哪些 Executor 执行器?
- SimpleExecutor:每次执行都创建 Statement 对象,用完关闭。
- ReuseExecutor:创建完 Statement 对象存入 map 复用。
- BatchExecutor:批量创建 Statement 对象,用于批处理。
Mybatis 是否支持延迟加载?原理是什么?
MyBatis 支持延迟加载
延迟加载:多表联查时,如果暂时没有用到其他表的信息,就先不查询,当用到的时候在查询。提高性能。
延迟加载的原理:使用 CGLIB 创建代理对象,当调用 get 返回 null 时,就会进行 SQL 查询,并 set 值。
什么是 MyBatis 的接口绑定?有哪些实现方式?
接口绑定是 MyBatis 中,将接口和 SQL 语句绑定,查询时直接调用方法。
有两种绑定方式:
- 在接口上使用注解,比如 @Select、@Update
- 使用 xml 配置绑定,namespace 需要是接口的全路径名
Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
- 通过 resultMap 映射,逐一定义列名和属性字段关系。
- 通过 sql 列别名,通过别名找到属性字段
之后通过反射的方式创建对象,并对其赋值。
MyBatis 是如何进行分页的?原理是什么?
为什么需要分页:用户不需要太多数据,且数据多的性能较差。通过拼接 limit 关键字实现分页。
MyBatis 实现分页的方式:
- 逻辑分页:使用 RowBounds 进行内存分页(没啥用)
- 物理分页:通过拦截器或插件实现
MyBatis 实现分页的原理:通过拦截器拼接 limit 0, 10
Spring Boot
Spring Boot 是什么?有什么特点
Spring Boot 是一个基于 Spring 的框架,简化了 Spring 框架的配置、搭建和开发。类似于脚手架。
特点:
- 根据依赖进行自动配置,比如数据库连接
- 内嵌了 Tomcat 容器,可以直接打包运行,不依赖其他容器
- 提供了 starter 依赖,可以快速整合依赖
- 不需要 Spring 和 Spring MVC 繁琐的配置文件
Spring Boot 核心注解
@SpringBootApplication
:Spring Boot 主启动类@SpringBootConfiguration
:Spring Boot 配置类,用于定义 Bean@ComponentScan
:定义 Spring 包扫描路径,实现 Bean 的自动配置
谈一谈 Spring Boot 自动装配
自动装配是值,通过项目依赖自动创建并配置所需的 Bean,无需手动编写 XML 或配置类来设置 Spring 容器。
比如添加了 spring-boot-starter-web
依赖之后,Spring Boot 会自动配置一个 Servlet 容器以及相关的 Web 环境所需的 Bean,简化开发流程。
Spring Boot 自动化配置的原理是什么?
- 主启动类 @SpringBootApplication 注解中包含 @EnableAutoConfiguration 注解。启动后会加载 AutoConfigurationlmportSelector.class。
- 这个类会加载所有 jar 包中 META-INF/spring-factories 配置文件、
- SpringBoot 会通过配置信息,按需加载 @Configuration 配置类,创建并自动注入 Bean。
❓说一说 Spring Boot 启动流程
Spring Boot 项目如何热部署?
热部署:不重启应用的情况下,重新加载更新的代码。
通过添加 devtools 依赖实现,常用于开发环境。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
Spring Boot 打包成的 jar 和普通的有什么区别?
Spring Boot 项目最终打包成的 jar 包是可执行的 jar 包。
这种 jar 包可以直接通过 java-jar xxx.jar
命令来运行,但是这种 jar 包不可以作为普通的 jar 包被其他项目依赖,无法使用其中的类。