Summary
一、分布式系统
1. CAP
一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)
2. redis启用事务管理
redis配置
redisTemplate.setEnableTransactionSupport(true);
https://mp.weixin.qq.com/s/eK-9D7T1fMvrSXSGkC78xw
不建议开启事务管理,开启也建议开启两个bean,一个开启事务一个不开启
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean test(String id) {
redisClient.setObject("xiaoqi", "xiaoqi");
Valve valve = Valve.builder().id("777").model("123").size("777").certNumber("777")
.createTime(DateUtil.formatDatetime(new Date())).updateTime(DateUtil.formatDatetime(new Date()))
.ownerPhone("777").pressure("777").maxPressure("777").build();
valveMapper.insertSelective(valve);
int a = 10/0;
return true;
}
redis 主从 哨兵 集群模式
https://zhuanlan.zhihu.com/p/608288385
redis过期删除策略
过期删除策略:(默认采用 惰性删除+定期删除 )
(1)定时删除
(2)惰性删除
(3)定期删除
Redis 内存淘汰策略 (默认不淘汰)
(1) 不进行内存淘汰 达到最大内存会禁止写入新数据报错
(2)
设置过期的key
volatile-random:随机淘汰设置了过期时间的任意键值;
volatile-ttl:优先淘汰更早过期的键值。
volatile-lru(Redis3.0 之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值;
volatile-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰所有设置了过期时间的键值中,最少使用的键值;
在所有数据范围内进行淘汰:
allkeys-random:随机淘汰任意键值;
allkeys-lru:淘汰整个键值中最久未使用的键值;
allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰整个键值中最少使用的键值。
LRU 的全称是 Least Recently Used,LFU 的全称是 Least Frequently Used。这两个是缓存淘汰算法,用于决定缓存中哪些数据应该被替换出去。简单来说:
LRU(最近最少使用)算法是根据数据最近被访问的时间来决定淘汰哪些数据,即最久未被使用的数据优先被淘汰。 时间
LFU(最不经常使用)算法是根据数据被访问的频率来决定淘汰哪些数据,即使用频率最低的数据优先被淘汰。 次数
3. 变量命名 https://mp.weixin.qq.com/s/xOSitmrmn5eeeILDtNuXAw
2. unknown
1. kafka 搭建 zookeeper和kraft模式
2. @KafkaListener(topics = {topic}, groupId = "xiao2")
@KafkaListener(topics = {topic}, groupId = "xiao1")
不同的groupId订阅相同的topic可以同时消费1条数据
version: '3.5'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
container_name: kafka
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_HOST_NAME: 192.168.215.21 ## 广播主机名称,一般用IP指定
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_PORT: 9092
KAFKA_LOG_RETENTION_HOURS: 120
KAFKA_MESSAGE_MAX_BYTES: 10000000
KAFKA_REPLICA_FETCH_MAX_BYTES: 10000000
KAFKA_GROUP_MAX_SESSION_TIMEOUT_MS: 60000
KAFKA_NUM_PARTITIONS: 3
KAFKA_DELETE_RETENTION_MS: 1000
KAFKA_LISTENERS: PLAINTEXT://:9092
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://192.168.215.21:9092
KAFKA_BROKER_ID: 1
kafka-manager:
image: sheepkiller/kafka-manager
container_name: kafka-manager
environment:
ZK_HOSTS: 192.168.215.21 ## 修改:宿主机IP
ports:
- "9009:9000"
# 广播主机名称,一般用IP指定
KAFKA_ADVERTISED_HOST_NAME:
# Zookeeper连接地址,格式:zoo1:port1,zoo2:port2:/path
KAFKA_ZOOKEEPER_CONNECT:
# Kafka启动所使用的的协议及端口
KAFKA_LISTENERS:
# Kafka广播地址及端口,告诉客户端,使用什么地址和端口能连接到Kafka,不指定,宿主机以外的客户端将无法连接到Kafka
KAFKA_ADVERTISED_LISTENERS:
# 指定BrokerId,如果不指定,将会自己生成
KAFKA_BROKER_ID:
# topic的分区数
KAFKA_NUM_PARTITIONS: 3
# broker端的leader分区在想其他follower分区复制消息时候 ,允许的单条消息的最大值
KAFKA_REPLICA_FETCH_MAX_BYTES: 10000000
# broker的topic分区leader接受数据的时候,允许的单条消息的最大值,默认为1M
KAFKA_MESSAGE_MAX_BYTES: 10000000
# 日志文件保存120个小时
KAFKA_LOG_RETENTION_HOURS: 120
CREATE USER 'xiaoqi' IDENTIFIED BY 'xiaoqi';
GRANT ALL PRIVILEGES ON database_name.* TO 'xiaoqi';
CREATE USER 'xiaoqi'@'%' IDENTIFIED BY 'xiaoqi';
GRANT ALL PRIVILEGES ON *.* TO 'xiaoqi'@'%';
3. bean的生命周期
https://cloud.tencent.com/developer/article/2216932
Spring的生命周期大致分为:创建 -> 属性填充 -> 初始化bean -> 使用 -> 销毁
比如对象创建(IOC)、属性注入(DI)、初始化方法的调用、代理对象的生成(AOP)等功能的实现
实例化 → 属性填充 → Aware回调 → 初始化前 → 初始化 → 初始化后 → 使用 → 销毁
0.扫描 BeanDefinition (启动时扫描 @Component/@Service/@Controller/@Bean把类的信息保存起来。)
1. 实例化(new 对象)只执行构造方法
2. 属性注入(依赖注入) (@Autowired)
3. Aware接口回调
4. BeanPostProcessor 前置处理
5. 初始化(InitializingBean / init-method)
6. BeanPostProcessor 后置处理(AOP在这里)
7. Bean 就绪(可使用)
8. 容器关闭 → 销毁(DisposableBean / destroy-method)
CustomerBeanPostProcessor implements BeanPostProcessor, EnvironmentAware
重写bean初始化前后和设置环境变量
Spring Bean 生命周期主要包括:
1.BeanDefinition 注册
2.实例化 Bean
3.属性填充(依赖注入)
4.执行 Aware 接口回调
5.BeanPostProcessor 前置处理
6.执行初始化方法
7.BeanPostProcessor 后置处理
8.放入单例池
9.Bean 使用
10.容器关闭时执行销毁方法
其中 AOP 代理对象通常是在 BeanPostProcessor 的后置处理中生成的。
Spring 通过 BeanPostProcessor 提供了非常强大的扩展能力,很多核心功能例如 AOP、事务、Autowired 都是基于它实现的。

4. countdownlatch的使用
https://juejin.cn/post/7024422323159564302
一等多或者多等一
countDown()
如果当前计数器的值大于零,则将其减一,如果新的计数器值等于零,则释放所有等待的线程。
如果当前计数器为零,则什么都不做。
此方法不会阻塞。
await()
导致当前线程等待,直到计数器的值变为零,除非线程被中断。如果计数器已经为零了,则立即返回group by
List<UserOrgAuth> userOrgAuths = userOrgAuthMapper.selectAll();
Map<String, List<String>> keys = userOrgAuths.stream()
.collect(Collectors.groupingBy(UserOrgAuth::getUserId,
Collectors.mapping(UserOrgAuth::getOrgCode, Collectors.toList())));
5. springboot
1. springboot自动配置
Spring Boot 的自动配置机制通过 @EnableAutoConfiguration 和 spring.factories 配置,结合 @Conditional 条件注解,动态加载合适的 Bean,从而大幅减少手动配置工作。
你可以:
查看自动配置情况(使用 --debug)。
禁用不需要的自动配置(exclude)。
自定义自动配置(@ConditionalOnClass + spring.factories)。
Spring Boot 的自动配置原理是什么?
启动类上的 @SpringBootApplication 是一个组合注解,它包含了 @EnableAutoConfiguration。
@EnableAutoConfiguration 会通过 @Import 导入 AutoConfigurationImportSelector。
该类会读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件(Spring Boot 2.7+ 之后)中配置的所有自动配置类。
每个自动配置类上都带有条件注解(如 @ConditionalOnClass、@ConditionalOnMissingBean),这些注解决定了配置类是否生效。
2.
6. 问题记录
1. Monitor 是 JVM 中的同步机制,本质是一个互斥锁结构,
内部包含:
Owner(持有锁的线程)
EntryList(阻塞队列)
WaitSet(等待队列)
2. java集合基础知识
List:
List接口
Map实现类
JDK1.8 的 ConcurrentHashMap 相比 1.7 最大的变化是取消了 Segment 分段锁, 改为基于数组 + 链表/红黑树的结构,并结合 CAS 和 synchronized 实现更细粒度的并发控制, 从而提高了并发性能和扩展性。
同时引入了红黑树优化、支持多线程协助扩容,并改进了计数方式,
springboot用到了哪些设计模式
7. spring三级缓存
Spring 通过三级缓存解决单例 Bean 的循环依赖问题。一级缓存存放完整 Bean,二级缓存存放提前暴露的半成品 Bean,三级缓存存放对象工厂。在发生循环依赖时,通过三级缓存提前获取 Bean 的早期引用,并在必要时通过 ObjectFactory 创建代理对象,从而既解决依赖问题,又保证 AOP 代理的一致性。
一级缓存 singletonObjects → 完整 Bean(最终成品)
二级缓存 earlySingletonObjects → 提前暴露的 Bean(半成品)
三级缓存 singletonFactories → 生产“早期Bean”的工厂
创建A
↓
放入三级缓存(工厂)
↓
创建B
↓
B需要A
↓
三级缓存 → 提前拿A
↓
A放入二级缓存 (防止重复创建,否则每次都去三级工厂拿,保证 AOP 代理唯一性)
↓
B完成
↓
A完成
↓
全部进入一级缓存
类比:
三级缓存:生产机器(还能决定生产“普通A”还是“代理A”)
二级缓存:已经生产好的半成品A
一级缓存:最终成品A8. mbatis原理
整体架构
Mapper接口
↓(动态代理)
MapperProxy
↓
SqlSession
↓
Executor(执行器)
↓
StatementHandler
↓
JDBC
↓
数据库
完整流程:
读取配置文件,通过 SqlSessionFactoryBuilder 构建 SqlSessionFactory。
通过 SqlSessionFactory 打开 SqlSession。
1. 调用 Mapper 接口方法
2. 动态代理拦截(MapperProxy)
3. 找到对应的 SQL(MappedStatement)
4. 执行 SQL(Executor)
5. JDBC 查询数据库
6. 结果封装(ResultSet → 对象)
7. 返回结果
9. jvm
内存区域
JVM Runtime Data Area
┌─────────────────────────────────────┐
│ 方法区(Method Area) │ ← 线程共享
│ 类信息、常量、静态变量 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 堆(Heap) │ ← 线程共享
│ 对象实例 │
└─────────────────────────────────────┘
线程1:
┌──────────────┐
│ 程序计数器 │ ← 私有
├──────────────┤
│ JVM虚拟机栈 │ ← 私有
├──────────────┤
│ 本地方法栈 │ ← 私有
└──────────────┘
线程2:
┌──────────────┐
│ 程序计数器 │ ← 私有
├──────────────┤
│ JVM虚拟机栈 │ ← 私有
├──────────────┤
│ 本地方法栈 │ ← 私有
└──────────────┘
对象创建流程:
执行 new 时,
JVM 首先检查类是否已加载,
若未加载则进行类加载。
之后在堆的 Eden 区为对象分配内存,
分配方式可能是指针碰撞或空闲列表。
为了提高并发性能,
HotSpot 会使用 TLAB 为线程预分配内存。
对象分配后,
JVM 会先初始化零值,
然后设置对象头,
包括 Mark Word 和 Klass Pointer。
最后执行 <init> 方法完成对象初始化,
引用变量再指向该对象。1.jstack 常用命令(线程分析)
jstack <pid> 打印线程栈
jstack -l <pid> 带锁信息
jstack <pid> > thread.txt 重定向保存
2. jmap 常用命令(内存分析)
jmap -heap <pid> 查看堆信息
jmap -histo <pid> 查看对象分布 (类名 + 对象数量 + 占用内存)
jmap -dump:live,format=b,file=heap.hprof <pid> 生成dump信息
3.jstat 常用命令(GC / 运行状态)
jstat -gc <pid> 1000 GC状态 (1秒输出一次)
jstat -gccause <pid> GC 次数
常用场景
(1) CPU 100%
top -Hp <pid>
jstack <pid>
(2) 内存泄漏
jstat -gc <pid> 1000
jmap -histo <pid>
jmap -dump:live,format=b,file=heap.hprof <pid>
jstack → 看线程
jmap → 看对象
jstat → 看趋势
4.GC流程
GC流程 = 分配 → 存活判断 → 分代回收 → 释放内存
1. 对象在 Eden 分配
2. Eden 满 → Young GC(复制算法)
3. 存活对象进入 Survivor,并增加年龄
4. 达到阈值或空间不足 → 晋升 Old
5. 老年代满 → 触发 Full GC
6. Full GC 使用标记-整理算法
7. 通过 GC Roots 可达性分析判断对象存活
JVM 的垃圾回收流程包括对象在 Eden 区创建,当 Eden 满时触发 Young GC,通过复制算法将存活对象移动到 Survivor 区,多次存活后晋升到老年代。当老年代空间不足时触发 Full GC,对整个堆进行标记、清除和整理。JVM 通过可达性分析判断对象是否存活,并结合不同算法在新生代和老年代进行优化回收10. AQS
AQS(AbstractQueuedSynchronizer)是一个用于构建锁和同步器的基础框架,它通过“状态 + 队列(CLH)”来实现线程的排队和唤醒。
Java 里这些你熟悉的工具:
ReentrantLock
Semaphore
CountDownLatch
ReentrantReadWriteLock
👉 本质都基于 AQS 实现
AQS = state(资源) + 队列(排队) + CAS(竞争) + park(阻塞)
AQS 是 Java 并发包中的一个核心同步框架,通过一个 volatile 的 state 变量表示资源状态,并使用一个基于 CLH 的 FIFO 队列来管理线程的排队。线程获取锁时通过 CAS 修改 state,失败则进入队列并阻塞,释放锁时会唤醒队列中的线程。AQS 支持独占模式和共享模式,是 ReentrantLock、Semaphore 等同步器的基础。11. mvcc
MVCC 通过在每行数据中维护事务 ID 和 undo log 形成版本链,并在事务第一次读取时生成 Read View。查询时根据 Read View 判断数据版本的可见性,如果当前版本不可见,则通过 undo log 查找历史版本。由于同一事务内始终使用同一个 Read View,因此可以保证多次读取结果一致,从而实现可重复读。12. volatile
volatile 通过内存屏障和缓存一致性协议保证变量的可见性和有序性,防止指令重排序,但不保证复合操作的原子性。13. springboot启动流程
创建 Spring 容器
↓
读取配置
↓
自动装配
↓
注册 BeanDefinition
↓
实例化 Bean
↓
启动 Web 容器
↓
应用启动完成
详细流程
SpringApplication.run()
↓
创建 SpringApplication
↓
推断 Web 类型
↓
加载 SPI
↓
准备 Environment
↓
创建 IOC 容器
↓
prepareContext()
↓
refresh()
↓
解析配置类
↓
自动装配
↓
注册 BeanDefinition
↓
BeanPostProcessor
↓
实例化单例 Bean
↓
启动 Tomcat
↓
DispatcherServlet
↓
Runner 执行
↓
ApplicationReadyEvent
自动装配原理
@EnableAutoConfiguration
↓
AutoConfigurationImportSelector
↓
spring.factories
↓
条件注解
↓
加载配置类
总结
@SpringBootApplication
↓
@EnableAutoConfiguration
↓
@Import(AutoConfigurationImportSelector)
↓
读取 spring.factories
↓
加载 xxxAutoConfiguration
↓
条件注解过滤
↓
@Bean 注册
↓
放入 IOC 容器
AutoConfigurationImportSelector 做了什么?
这是自动装配核心类。
它主要干:
扫描所有自动配置类
↓
筛选符合条件的配置类
↓
导入 IOC 容器14. 请求流程
HTTP请求
↓
Tomcat(接收请求)
↓
Filter(通用过滤)
↓
DispatcherServlet(MVC调度)
↓
Interceptor(业务拦截)
↓
Controller(接收参数)
↓
Service(核心业务)
↓
AOP(事务/日志)
↓
DAO(操作数据库)
↓
MySQL15. Redis数据结构
| Redis类型 | 底层结构 |
| ------- | -------------------- |
| String | SDS |
| List | QuickList |
| Hash | HashTable / ListPack |
| Set | intset / HashTable |
| ZSet | SkipList + HashTable |
(1) String 底层是 SDS
(2) List 底层是 QuickList
(3) Hash 小数据时使用 listpack,大数据时使用 HashTable
(4) Set 小整数集合使用 intset,否则使用 HashTable
(5) ZSet 使用 SkipList + HashTable
Redis 这样设计的核心目的是:
在不同场景下兼顾:
时间复杂度
内存占用
操作效率16. Mybatis
主流程
Mapper接口
↓
代理对象
↓
Executor
↓
MappedStatement
↓
SQL
↓
JDBC
↓
数据库
| 组件 | 作用 |
| ----------------- | -------- |
| SqlSessionFactory | 工厂 |
| SqlSession | 会话 |
| Executor | SQL执行器 |
| StatementHandler | JDBC处理 |
| ParameterHandler | 参数处理 |
| ResultSetHandler | 结果处理 |
| MapperProxy | Mapper代理 |
| MappedStatement | SQL封装 |
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
晓!
喜欢就支持一下吧