Spring

Spring bean容器的生命周期

  1. Spring容器根据配置中的bean定义实例化bean
  2. Spring使用依赖注入填充所有属性
  3. 如果bean实现BeanNameAware接口,则工厂通过传递bean的id来调用setBeanName()
  4. 如果bean实现BeanFactoryAware接口,工厂通过传递自身的实例来调用setBeanFactory()
  5. 如果存在与bean关联的任何BeanPostProcessors,则调用preProcessAfterInitialization()方法
  6. 如果为bean指定了init方法,则调用它
  7. 如果存在与bean关联的任何BeanPostProcessors,则调用postProcessAfterInitialization()方法
  8. 如果bean实现DisposableBean接口,当Spring容器关闭时,会调用destroy()
  9. 如果为bean指定了destroy方法,则调用它

Spring的事务什么情况下会失效

  1. 异常被try catch
  2. 事务传播 属性设置不当
  3. 多数据源事务管理
  4. 非public方法
  5. 同一个类,this调用
  6. 非runtimeException
  7. 多线程调用

BeanFactory和ApplicationContext

BeanFactory ApplicationContext
使用懒加载 使用即时加载
它使用语法显示提供资源对象 自动创建和管理资源对象
不支持国际化 支持国际化
不支持基于依赖的注解 支持基于依赖的注解

SpringBoot自动配置

SpringBoot所有自动配置都是在启动的时候扫描并加载,spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,
只要导入对应的starter,就有对应的启动器,有了启动器,我们自动配置就会生效,然后就配置成功。

  1. SpringBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定值
  2. 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置
  3. 整合javaEE,解决方案和自动配置都在spring-boot-autoconfigure-2.2.0.RELEASE.jar
  4. 把所有导入的组件以类名方式返回,这些组件会添加到容器中
  5. 容器中也会存在很多xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入这个场景需要的所有组件,并自动配置。

SpringBoot注解失效

  • @ComponentScan 配置错误
  • 类没有被代理

spring事务回滚

  • 数据库事务回滚 @Transactional
  • Redis缓存回滚 TransactionSynchronizationManager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Transactional
public void updateUser(Long userId, String newName) {
userRepository.updateNameById(userId, newName);

// 注册事务同步回调
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务提交成功后才更新 Redis
redisTemplate.opsForValue().set("user:" + userId, newName);
}

@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
System.out.println("事务回滚,Redis 不更新");
}
}
});

throw new RuntimeException("模拟异常");
}

Mybatis

查询性能优化

SQL语句优化:避免SELECT *,优化WHERE条件,避免LIKE ‘%XX%’
MyBatis配置优化:开启二级缓存,使用resultMap,避免N+1查询(多个查询合并为关联查询或批量查询)
索引优化:创建合适的索引,遵循最左前缀原则
批量查询优化:使用JOIN,IN查询,MyBatis 批量查询
MySQL配置优化:开启SQL预编译,提高查询效率
Redis缓存:缓存热点数据,减少数据库查询压力

一级缓存和二级缓存

一级缓存(本地缓存)

在一个SqlSession生命周期内,如果执行相同的查询SQL(且参数相同),MyBatis会直接从缓存中取数据,而不是再次发起数据库查询。

  • 默认开启,不能关闭,使用statement可每次查询自动清空缓存。
  • 作用范围:同一个 SqlSession
  • 缓存级别:本地缓存(LocalCache)
  • 生命周期短:随着 SqlSession 的关闭而销毁。
  • 若执行了 update/insert/delete 操作,会清空该缓存,防止脏读。

二级缓存(跨 SqlSession 缓存)

是Mapper级别的缓存,通过配置开启,可以在多个SqlSession间共享数据,提升系统整体查询性能。

  • 默认关闭,需要手动开启。
  • 缓存级别:Mapper映射级别(基于namespace)
  • 生命周期长:存在于整个Mapper生命周期内。
  • 底层是可插拔缓存实现(默认是PerpetualCache + LRU缓存策略)
  • 二级缓存是基于序列化存储的,对象需要实现Serializable接口

分布式

分布式事务

  • XA协议:TM事务管理器,RM资源管理器,应用程序
  • 2PC:
    1. 投票阶段:各参与者都执行SQL,但不提交事务,执行成功返回YES,否则返回NO
    2. 执行阶段:各参与者都返回YES,就执行commit,有一个NO就回滚事务
      缺陷:1.同步阻塞 2.TM单点问题 3.数据不一致
  • 3PC:增加先询问数据库是否执行事务,投票阶段增加超时机制,超时后默认提交
  • TCC: Try,Confirm,Cancel。应用层实现,实际少有人用

事务消息

  1. 使用RocketMQ
  2. 使用TransactionSynchronizationManager确认事务提交后执行afterCommit

微服务

服务熔断、降级

  • 服务熔断:当服务A调用服务B时,如果服务B不可用,那么上游A为了保证自己不受影响,切断服务B,直到B服务恢复.
  • 服务降级:当系统负载过高时,对非核心的业务进行关闭,保证核心业务正常运行。

接口幂等性

  1. 使用唯一索引防止幂等性问题
  2. Token+Redis的幂等性
  3. 防重表实现幂等性(数据库分布式锁)

认证

accessToken防止窃取

  1. 使用https
  2. 存放在cookie,使用http-only
  3. 设置Content-Security-Policy头部限制脚本来源,使用Cookie时加上SameSite属性
  4. 过期时间,使用Refresh Token,绑定设备信息和IP
  5. 强制登出,重制密码