- 博客(20)
- 收藏
- 关注
原创 从 SPI 到 Spring Boot 自动装配
SPI (Service Provider Interface) 是 Java 提供的一种服务发现机制,用于实现模块之间的解耦,基本思想是:我来定义接口,由你来提供实现,并通过标准配置注册,我再用 ServiceLoader 动态加载你的实现类。这种机制常用于第三方模块的自动发现和加载,典型场景包括 JDBC 驱动,日志系统等接口标准化、实现解耦、运行时动态加载。
2025-07-07 19:39:48
604
原创 从 Servlet 到 Spring Boot : Java Web 的演进
> 请求到达时仍由 DispatcherServlet 分发给 HandlerMapping、HandlerAdapter 等处理。浏览器请求 -> Web 容器读取 web.xml -> 找到映射的 Servlet -> 调用 doGet() / doPost()-> 创建内嵌 Tomcat,并将 DispatcherServlet 动态注册进 ServletContext。浏览器请求 -> DispatcherServlet(web.xml注册)浏览器请求 -> DispatcherServlet。
2025-07-06 17:24:32
481
原创 回顾最初的 Spring :事务机制
如果抛出的是 Checked Exception(如 IOException),事务不会回滚,除非加@Transaction(rollbackFor = Exception.class)Spring 通过 @Transactional(isolation = Isolation.xxx)设定当前事务的隔离级别,用于底层数据库连接。Spring 使用 ThreadLocal 管理事务,子线程不会继承父线程的事务上下文。被吞掉的异常,Spring无法感知,也不会回滚。提交后事务已经结束,无法回滚。
2025-07-06 00:15:20
334
原创 回顾最初的 Spring :IOC、AOP 与 Bean 生命周期
虽然 Spring 也会把 ObjectFactory 放到三级缓存中,但由于创建过程中没有其他对象引用A,所以这个工厂函数不会被调用,最终只会放入一级缓存,二级 、三级缓存不会真正生效。AOP 是 Spring 中另一个非常强大特性,它可以在不侵入业务代码的前提下,动态插入逻辑,完成诸如日志记录,权限校验,异常处理,性能监控等。,而是交给 Spring 容器。如果只有二级缓存,在刚才的第4步中,只能把没有增强的 A 原始对象给到 B,才能完成 B 对象的创建。三级缓存的引入,本质是为了解决。
2025-07-05 12:01:28
588
原创 ConcurrentHashMap 原理总结(部分)
3,如果桶是 ForwardingNode,说明正在扩容,跳转到 nextTable 重新查找。2,通过 CAS 将 sizeCtl 改为 -1,只有一个线程能成功进行初始化。计算 key 的 hash 值,用于判断当前 key 应该存在哪个位置。如果是 ForwardingNode,说明正在扩容,触发协助迁移逻辑。,摒弃了 JDK7 中使用的 Segment 分段锁设计,提高了。1,判断数组是否为 null,如果为 null,开始初始化。1,计算 key 的 hash,定位 table 中的桶。
2025-07-04 00:10:49
832
原创 Java 垃圾回收器入门与演进:Serial、CMS、G1
G1 支持 Young GC 和 Mixed GC,但不再固定 Eden,Survivor,Old 区的位置,而是通过 Region 标签动态管理。的场景,在GC完存活对象大于新生代总容量的5%(To Survivor的一半,就是5%),就会触发提前晋升。标记压缩是将存活的对象内存的一端移动,让所有活的对象紧凑地排在一起,然后将剩余的空间全部清除。CMS是第一个实现低延迟的老年代GC,解决了响应时间差的问题,但核心问题太多,最终被G1取代。移动复制对象,需要调整对象引用;只扫描一次,效率高,且没有碎片。
2025-06-29 15:54:50
678
原创 Java 内存结构概览
Metaspace用来存储类的结构信息(类名,方法,字段,继承结构等),常量池,类加载器等,其实Metaspace正常情况下都是安静的,它不像堆那样有对象不断创建和回收,一般情况下,程序启动时加载的类结构是固定的,对 Metaspace 的占用也基本确定。只有在加载新的class或动态生成新的类(动态代理,字节码框架),才会新增Metaspace中的内容。元数据区在1.8以前叫永久代,是JVM内部堆的一部分,但是有几个问题,容量固定,类卸载复杂,和堆共享GC配置,调优麻烦,所以从1.8开始,永久代被废除。
2025-06-27 22:33:16
698
原创 Synchronized 总结
在Java中,为了保证多线程共享资源的原子性,引入了synchronized关键字,但在JDK1.5之前,被实现为重量级锁。
2025-06-25 12:09:47
305
原创 Kafka在消息写入磁盘的情况下为什么还能这么快?
Kafka的写入是append-only的顺序写,避免了磁盘寻址开销,比随机写要快很多,同时消息是写入的操作系统的Page Cache,由操作系统来统一刷盘,进一步提高了写入速度。Kafka使用sendfile的系统调用,是直接将数据从磁盘传输到socket缓冲区,避免了数据在用户态和内核间的多次拷贝,提高数据传输效率。Kafka中的Producer,Consumer,以及Broken写磁盘,都是批量操作,一次处理多条数据,有效减少I/O次数,提升整体吞吐量。
2025-06-24 11:12:41
154
原创 Kafka 中如何保证消息不丢失、不重复?
Kafka的一主多从机制+ISR副本选举机制,可以最大程序地避免单点故障造成的数据丢失。默认情况下,消费端使用的是每5秒自动提交offset。Kafka每个Topic的Partition会由多个Broken共同存储。Producer将消息发送给Kafka,通过acks控制确认机制。消息重复消费是可以补救的,但是消息丢失不行。
2025-06-24 08:48:03
211
原创 RabbitMQ 从死信队列到延迟消息
举个例子,如果第一条消息A过期时间30秒,第二条消息B过期时间10秒,即便消息B先过期了,基于RabbitMQ TTL的。3,队列A没有消费者,这样队列A中的消息会在TTL到期时自动经过死信交换机转发到死信队列B。如上所述,消息过期会被转发到死信队列,这样我们可以按照以下步骤实现延迟队列。4,消息会在交换机中等待到达延迟时间后再路由到绑定队列。1,创建普通队列A,设置消息TTL,没有消费者。机制,也是消息A进入死信队列后,才会检查消息B。4,消费者监听死信队列B,实现延迟消费。2,给队列A设置死信交换机。
2025-06-23 17:22:50
258
原创 RabbitMQ 消息堆积的场景与解决方案
的情况下,虽然默认不会导致消息丢失,但是会导致内存占用过高,消费延迟变大,甚至RabbitMQ系统崩溃等问题。RabbitMQ中的消息堆积,是出现在。
2025-06-23 15:04:06
186
原创 RabbitMQ 重复消费的本质与解决方案
在每次消息处理前,先去数据库中查询messageId是否已经存在,如果不存在则执行业务处理,如果已经存在,则跳过,但这种情况存在性能瓶颈,在高并发的情况下,频繁查询数据库会对性能有很大影响。实现幂等判断,针对每条消息的messageId执行原子加锁(setnx),如果成功说明未处理,失败则说明已经处理或正在处理,缺点是Redis不具备长期存储和查询能力。这使得在网络抖动,手动ack遗漏,消费者宕机的情况下,都有可能导致一条消息被多次投递,重复消费。”,即一条消费被处理多次,但只产生一次有效结果。
2025-06-23 01:59:58
157
原创 Redis 为什么是单线程,依然很快?
Redis是内存数据库,大多数命令执行非常快,基本是微秒级别的,这种情况下如果使用多线程,反而会因为线程切换,锁竞争等操作带来额外开销,整体并发未必能得到提升,也因为此,Redis的瓶颈不在于CPU,而在IO。从Redis 6开始,引入了“IO 多线程”机制。多线程在很多程序中确实能提升并发,特别是每个请求要处理很久的,比如访问数据库,磁盘读写,调用接口等,这时切换线程和加锁的相对成本较低,换来的并发提升是划算的。
2025-06-22 00:44:11
193
原创 数据一致性
先删缓存,再删数据库,但是del cache和del db之间,可能有另外的线程读取了数据库,又将缓存设置回去了,同样会留下脏数据。Redis缓存设计的是弱一致性架构,在使用缓存的过程中,会存在缓存与数据库中的数据同步问题。一般在更新数据时,我们会选择删除缓存,以简化操作,这样在整个流程上,和删除数据是一样的。3,对数据库的操作一般认为是强保障+持久化+有事务机制的,但对缓存的操作不能保证成功。先删数据库,再删缓存,如果缓存删除失败,会留下脏数据,一直存在。新增数据会比较简单,插入数据库后,不写缓存,
2025-06-19 22:36:44
312
原创 主从复制和哨兵
当从节点首次加入主节点时,会触发全量复制psync,主节点会执行bgsave生成rdb文件发送从节点,并在此过程中,将新的写入命令缓冲在backlog中,在rdb文件加载完成后,再发送backlog中的写指令给从节点,实现数据同步。在主从复制模式下,能提升并发能力,但是如果主节点出现故障,需要人工指定新的主节点,哨兵的目标就是自动监控主节点状态,如果主节点出现故障,自动完成故障转移并通知客户端更新主节点信息。一个哨兵系统一般由奇数个哨兵组成以实现选举的高可用,主要负责监控主节点,从节点列表,还有其他哨兵。
2025-06-18 23:06:15
147
原创 全局哈希表和渐进式Rehash
Redis的Key和Value是使用全局哈希表组织存储的,其实就是一个数组,每个元素称为了一哈希桶,每个桶里就保存着我们看到的key-value数据,key是string型,value可能是string,hash,list,set,zset。随着数据增加,不可避免地会出现Hash冲突,Key值不一样,Hash值一样,Redis解决哈希冲突的方式是链式哈希,同一个哈希桶里有多个entry,使用链表来保存。优点:查找速度快,计算出key的hash值,就能知道对应的哈希桶位置。解决办法:Rehash。
2025-06-18 12:49:08
174
原创 Redis持久化
同时会把增量数据写入aof_rewrite_buf中,在aof文件写入完成后,将aof_rewrite_buf中的数据append到aof文件中。然后替换掉旧的aof文件。在aof逐渐变大,达到配置的阈值时,会触发重写操作,这里也是fork子线程去进行重写,从内存中读取数据转换为aof文件,在写aof文件过程中,主线程在进行写操作时,不仅为把命令记录在aof_buf中,还会记录在aof_rewrite_buf中,目的是为了写完aof文件后,将aof_rewrite_buf中的命令append进去。
2025-06-17 22:45:38
124
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人