常用框架知识
Spring
Spring IOC
IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。
为什么叫控制反转?
- 控制:指的是对象创建(实例化、管理)的权力
- 反转:控制权交给外部环境(Spring 框架、IoC 容器)
@Autowired和@Resource的区别
@Autowired是 Spring 提供的注解,@Resource是 JDK 提供的注解。Autowired默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为byName(根据名称进行匹配)。- 当一个接口存在多个实现类的情况下,
@Autowired和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired可以通过@Qualifier注解来显式指定名称,@Resource可以通过name属性来显式指定名称。 @Autowired支持在构造函数、方法、字段和参数上使用。@Resource主要用于字段和方法上的注入,不支持在构造函数或参数上使用。
注入Bean的方式
- 属性注入:
@Autowired注解直接注入字段(最常用,但易忽视依赖可见性)。 - Setter注入:通过Setter方法赋值(灵活性高,支持可选依赖)。
- 构造器注入:通过构造函数赋值(推荐,保证依赖不可变且避免空指针,lombok中使用
@RequiredArgsConstructor注解实现,属性添加final声明)
Bean的作用域
- singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续
getBean()两次,得到的是不同的 Bean 实例。 - request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
- application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
- websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
Bean是线程安全的吗
Spring Bean 的线程安全性取决于其作用域(Scope)和内部状态设计
单例 Bean(Singleton,默认作用域)
- 非线程安全:所有线程共享同一实例,若包含可变成员变量(如计数器、缓存对象),多线程并发修改会导致数据竞争
@Service
public class CounterService {private int count = 0; // 共享状态,线程不安全public void increment() { count++; }
}- 线程安全场景:无状态 Bean(无成员变量或仅含不可变对象)
// 定义了一个用户服务,它仅包含业务逻辑而不保存任何状态。
@Component
public class UserService {public User findUserById(Long id) {//...}//...
}原型 Bean(Prototype)
- 通常线程安全:每次请求创建新实例,普通成员变量线程隔离
- 例外情况:若包含静态变量,仍会共享导致不安全
解决线程安全问题的方案
- 避免可变成员变量: 尽量设计 Bean 为无状态。
- 使用
ThreadLocal: 将可变成员变量保存在ThreadLocal中,确保线程独立。 - 使用同步机制: 利用
synchronized或ReentrantLock来进行同步控制,确保线程安全
Bean的生命周期
Spring Bean的生命周期4个阶段
- 通过反射实例化对象
- 通过PopulationBean方法进行属性赋值
- 初始化
- 销毁

1. 创建 Bean 的实例:Bean 容器首先会找到配置文件中的 Bean 定义(XML/注解/Java Config),然后使用 Java 反射 API来创建Bean 的实例。
2. Bean 属性赋值/填充:通过Setter、字段注入(@Autowired)或构造器注入填充属性,解析@Value注入配置值。
3. Bean 初始化:
- Aware接口回调:注入容器基础设施信息。
BeanNameAware→BeanFactoryAware→ApplicationContextAware(顺序固定)。
- 初始化方法执行(按顺序调用):
-
@PostConstruct(JSR-250注解) -
InitializingBean.afterPropertiesSet() - 自定义
init-method(XML或@Bean(initMethod))。
-
- BeanPostProcessor增强:
- 前置处理(
postProcessBeforeInitialization):如@PostConstruct的解析。 - 后置处理(
postProcessAfterInitialization):如AOP代理对象的生成(AbstractAutoProxyCreator)。
- 前置处理(
4.销毁 Bean:销毁并不是说要立马把 Bean 给销毁掉,而是把 Bean 的销毁方法先记录下来,将来需要销毁 Bean 或者销毁容器的时候,就调用这些方法去释放 Bean 所持有的资源。
- 如果 Bean 实现了
DisposableBean接口,执行destroy()方法。 - 如果 Bean 在配置文件中的定义包含
destroy-method属性,执行指定的 Bean 销毁方法。或者,也可以直接通过@PreDestroy注解标记 Bean 销毁之前执行的方法。
Spring如何解决循环依赖
spring靠三级缓存解决循环依赖问题。
Bean的生命周期是:实例化 -> 属性赋值 -> 初始化 -> 销毁。循环依赖发生在属性赋值阶段。
一级缓存:
Map<String, Object> singletonObjects,成品对象单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例。二级缓存:
Map<String, Object> earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例。三级缓存:
Map<String, ObjectFactory<?>> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。
解决循环依赖过程
1. 创建 Bean A
- 实例化 A(调用构造器) → 将 A 的
ObjectFactory存入三级缓存(singletonFactories)。
2. 填充 A 的属性时发现依赖 B
- 触发创建 Bean B → 实例化 B → 将 B 的
ObjectFactory存入三级缓存。
3. 填充 B 的属性时发现依赖 A
- 从一级缓存查找 A(未找到)→ 从二级缓存查找(未找到)→ 从三级缓存获取 A 的
ObjectFactory → 生成 A 的早期引用 → 将 A 的引用存入二级缓存(earlySingletonObjects)→ 注入 B。
4. 完成 B 的初始化
- B 完成属性填充和初始化 → 将 B 放入一级缓存(
singletonObjects)→ 删除二/三级缓存中的 B。
5. 完成 A 的初始化
- A 获取完整的 B 引用 → A 完成属性填充和初始化 → 将 A 放入一级缓存 → 删除二/三级缓存中的 A。
只用两级缓存够吗? 在没有 AOP 的情况下,确实可以只使用一级和二级缓存来解决循环依赖问题。但是,当涉及到 AOP 时,三级缓存就显得非常重要了,因为它确保了即使在 Bean 的创建过程中有多次对早期引用的请求,也始终只返回同一个代理对象,从而避免了同一个 Bean 有多个代理对象的问题。(如果没有三级缓存,那么二级缓存存的是)
在 Spring 的三级缓存机制中,缓存存储的对象类型与代理层级无关。以下以 Proxy3 → Proxy2 → Proxy1 → 原始对象 的多级代理链为例,结合三级缓存的作用分析存储内容:
- 三级缓存:只会存储原始对象的
ObjectFactory工厂(与代理层级无关) - 二级缓存:首次从三级缓存生成的早期引用(即
Proxy1),而非每个层级的代理对象- 存储的是 半成品 Bean(可能为原始对象或单层代理),而非完整代理链。
- 对于多级代理链,二级缓存仅存
Proxy1,后续代理层级(如Proxy2/Proxy3)尚未生成
一级缓存:完整代理链的顶层代理对象(即
Proxy3),而非所有代理层级或原始对象- Bean 初始化完成后(
@PostConstruct执行完毕),通过BeanPostProcessor生成剩余代理层级,最终形成Proxy3并存入一级缓存。
- Bean 初始化完成后(
FactoryBean和BeanFactory区别
BeanFactory
Spring 的 IoC 容器根接口,管理所有 Bean 的生命周期(创建、依赖注入、销毁)
FactoryBean
一个特殊的 Bean 接口,本身是一个 Bean,但生产另一个对象,用于封装复杂对象的创建逻辑,例如:
- MyBatis 的
SqlSessionFactoryBean实现了FactoryBean<SqlSessionFactory> - Spring AOP 的
ProxyFactoryBean
Spring AOP
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
Aop通知顺序
正常流程:
@Around开始 → @Before → 目标方法 → @AfterReturning → @After → @Around结束
异常流程:
@Around始 → @Before → 目标方法 → @AfterThrowing → @After → @Around终
Spring 版本差异:
- Spring 4:
@After在@AfterReturning之前执行(现已过时)。 - Spring 5.2.7+:调整为
@AfterReturning → @After(正常流程)或@AfterThrowing → @After(异常流程)
Aop通知类型
- Before(前置通知):目标对象的方法调用之前触发
- After (后置通知):目标对象的方法调用之后触发
- AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
- AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
- Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法
Spring MVC工作流程
核心组件
DispatcherServlet:核心的中央处理器,负责接收请求、分发,并给予客户端响应。HandlerMapping:处理器映射器,根据 URL 去匹配查找能处理的Handler,并会将请求涉及到的拦截器和Handler一起封装。HandlerAdapter:处理器适配器,根据HandlerMapping找到的Handler,适配执行对应的Handler;Handler:请求处理器,处理实际请求的处理器。ViewResolver:视图解析器,根据Handler返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给DispatcherServlet响应客户端
视图阶段(JSP)流程

前后端分离阶段流程

Spring事务
Spring支持两种事务管理方式:
- 编程式事务:在代码中硬编码(在分布式系统中推荐使用) : 通过
TransactionTemplate或者TransactionManager手动管理事务,事务范围过大会出现事务未提交导致超时,因此事务要比锁的粒度更小。 - 声明式事务:在 XML 配置文件中配置或者直接基于注解(单体应用或者简单业务系统推荐使用) : 实际是通过 AOP 实现(基于
@Transactional的全注解方式使用最多)
事务的传播行为
REQUIRED(默认)
- 特点:若当前存在事务则加入,否则创建新事务。
- 场景:常规业务方法(如订单创建),保证多个操作原子性。
- 注意:嵌套方法异常会导致整个事务回滚。
SUPPORTS
- 特点:当前有事务则加入,没有则以非事务方式执行。
- 场景:查询操作(如数据查询),可兼容事务但无需强制。
MANDATORY
- 特点:强制要求当前必须存在事务,否则抛出异常。
- 场景:核心业务(如支付验证),确保方法在事务中执行。
REQUIRES_NEW
- 特点:无论当前有无事务,都创建独立新事务;若存在事务则挂起。
- 场景:日志记录、审计等需独立提交的操作。
- 注意:新事务与父事务完全隔离,互不影响提交/回滚。
NOT_SUPPORTED
- 特点:强制非事务执行,若当前存在事务则挂起。
- 场景:耗时操作(如大数据统计),避免事务开销。
NEVER
- 特点:必须在非事务环境中执行,否则抛出异常。
- 场景:严格非事务场景(如只读缓存更新)。
NESTED
- 特点:
- 当前有事务时,创建嵌套子事务(基于保存点机制)。
- 子事务回滚不影响父事务,父事务回滚则子事务必然回滚。
- 场景:部分操作需独立回滚(如订单创建成功但库存扣减失败)。
- 依赖:需数据库支持保存点(如MySQL的InnoDB引擎)。
事务的隔离级别
TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,MySQL 默认采用的REPEATABLE_READ隔离级别 Oracle 默认采用的READ_COMMITTED隔离级别.TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
事务失效的原因
1. 非public方法:Spring AOP默认只代理public方法,@Transactional标注在private/protected方法上无效。
2. 自调用问题(同类内部调用):同一个类中,非事务方法A直接调用事务方法B时,不经过Spring代理(AOP基于动态代理),事务失效。
解决方法:
- 注入自身代理对象:
@Autowired private UserService selfProxy;调用selfProxy.methodB()。 - 使用AOP工具:
((UserService)AopContext.currentProxy()).methodB()(需开启@EnableAspectJAutoProxy(exposeProxy=true))。 - 拆分方法到不同类中。
3. 异常类型不匹配:默认仅对RuntimeException和Error回滚。需指定回滚异常:@Transactional(rollbackFor = Exception.class)
4.异常被捕获未抛出:try-catch捕获异常后未重新抛出,事务拦截器无法触发回滚。
5.数据库底层需要支持事务
Spring中的设计模式
一、创建型模式
单例模式(Singleton):Spring容器默认以单例模式管理Bean(如
@Service、@Component),确保每个Bean定义仅有一个实例,节省资源并提高性能。工厂模式(Factory):
BeanFactory和ApplicationContext作为核心工厂接口,负责Bean的创建、配置和管理,解耦对象实例化过程。原型模式(Prototype):通过
@Scope("prototype")声明原型作用域的Bean,每次请求时创建新实例,适用于需要状态隔离的场景。
二、结构型模式
代理模式(Proxy):Spring AOP的核心实现,通过JDK动态代理(接口)或CGLIB(类)生成代理对象,实现日志、事务等横切逻辑。
适配器模式(Adapter):
Spring MVC:
HandlerAdapter适配多种控制器(如@Controller、HttpRequestHandler)。AOP:适配不同通知类型(如
MethodBeforeAdviceAdapter)。
装饰器模式(Decorator):
BeanPostProcessor在Bean初始化前后动态增强功能(如缓存、监控),不修改原始类代码。门面模式(Facade):
JdbcTemplate封装复杂数据库操作(连接管理、异常处理),提供简洁API。
三、行为型模式
模板方法模式(Template Method):
JdbcTemplate、RestTemplate等定义算法骨架(如事务流程),子类仅需实现特定步骤(如SQL执行)。观察者模式(Observer):事件驱动模型(
ApplicationEventPublisher发布事件,ApplicationListener监听响应),实现组件间松耦合通信。策略模式(Strategy):
视图解析:
ViewResolver根据请求类型(JSP、Thymeleaf)选择不同实现。事务管理:支持JDBC、JTA等多种事务策略。
责任链模式(Chain of Responsibility):Spring Security的过滤器链(
FilterChain)和Spring MVC的拦截器(HandlerInterceptor),按顺序处理请求。
Spring Boot
Spring Boot 约定大约配置怎么理解
约定的内容及作用
约定项目结构和命名规范:
- Spring Boot鼓励开发者使用一致的项目结构,避免手动配置Spring组件扫描路径。例如,
@SpringBootApplication注解默认会扫描同级包及子包中的组件。 - 配置文件只需用
application.yml格式即可自动加载;使用application-环境.yml时,它会根据环境判断是否加载,省去了XML配置。
- Spring Boot鼓励开发者使用一致的项目结构,避免手动配置Spring组件扫描路径。例如,
自动配置:
- 根据项目的依赖、类路径等条件,Spring Boot能自动配置各种组件。如默认使用SLF4J并集成logback作为日志实现,若需其他日志框架则需排除此包并引入新包。
- 引入
spring-boot-starter-web包后,程序会自动识别为servlet项目并创建servlet容器;引入数据库依赖时,会自动配置数据源、事务管理器等组件。自动装配是这一思想的体现。
Starter:
starter约定了spring.factories配置中需要注册的类,使我们快速整合组件到Spring中。Spring Boot提供了许多现成的starter,只需引入相应依赖即可生效。- 许多组件还附带了配置类(如
MultipartProperties),其中包含默认值(如最大上传文件大小为1M),仅在需要修改时才需配置。
Spring Boot自动装配原理
核心机制,三个注解组成
大概可以把 @SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类@ComponentScan:扫描被@Component(@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。
@EnableAutoConfiguration 是实现自动装配的重要注解
自动装配流程
1.加载自动配置类
@EnableAutoConfiguration 通过@Import导入AutoConfigurationImportSelector类。- 该类调用
SpringFactoriesLoader.loadFactoryNames(),扫描所有META-INF/spring.factories文件,加载其中声明的自动配置类(如org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration)
2.条件化筛选配置类
自动配置类使用条件注解动态决定是否生效,例如:
-
@ConditionalOnClass:类路径存在指定类时生效(如存在DataSource才加载数据库配置)。 -
@ConditionalOnMissingBean:容器中无指定Bean时生效(避免重复覆盖用户自定义Bean)。 -
@ConditionalOnProperty:配置文件属性匹配时生效(如spring.datasource.url存在)
3.注册Bean与属性绑定
1.通过@Configuration类中的@Bean方法向容器注册Bean
2.属性绑定:配置类结合@EnableConfigurationProperties加载XxxProperties类,将application.properties中的属性(如server.port)注入到Bean中
如何实现一个Starter
创建 Maven 项目,例如
配置
pom.xml,引入Spring Boot相关依赖定义配置属性类
实现核心服务类
创建自动配置类,使用@Conditional等条件注解控制 Bean 加载
注册自动配置,在项目的resource目录下添加 META-INF/spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.config.DemoAutoConfiguration
如何实现全局异常管理
Spring Boot 应用程序可以借助 @RestcontrollerAdvice和 @ExceptionHandler 实现全局统一异
常处理。
