- 博客(214)
- 收藏
- 关注
原创 Spring-AOP(理论,实战)
核心业务逻辑(注册用户)与非业务逻辑(日志、安全)“纠缠”在一起,严重违反了单一职责原则 (Single Responsibility Principle) ,使得代码难以阅读、测试和维护。Spring AOP 选择在运行时织入,这意味着它不需要特殊的编译器,但它依赖于“动态代理”技术,这是 Spring AOP 易用性和局限性的根本来源.这可以是一个方法的执行、一个方法的调用、一个字段的访问,甚至是异常的处理。它回答了“做什么 (What)”和“什么时候 (When)”执行的问题。
2025-11-09 17:08:55
892
原创 临键锁的加锁与退化机制
- 查询不存在的记录1. 扫描索引查找 id=72. 找不到,定位到 id=10(第一个大于 7 的记录)3. 默认加 Next-Key Lock: (5, 10]4. 发现 id=10 不满足条件(10≠7)5. 退化为间隙锁: (5, 10)6. 不锁 id=10 这条记录最终加锁:│ (5, 10) ← 间隙锁 │场景查询类型记录状态加锁类型示例1唯一索引等值存在记录锁WHERE id=10(存在)2唯一索引等值不存在间隙锁。
2025-10-31 10:19:17
329
原创 Java 堆排序(Heap Sort)详解教程
堆是一种完全二叉树(complete binary tree)大顶堆(max heap):每个节点的值 ≥ 子节点。小顶堆(min heap):每个节点的值 ≤ 子节点。在堆排序中,我们使用大顶堆来进行升序排序。步骤说明核心1从n/2 - 1开始建堆因为这是最后一个非叶子节点2从下往上建堆确保子树先堆化3每次交换堆顶和末尾把当前最大元素放对位置4重建堆保证剩余部分仍是大顶堆5重复 n 次数组排序完成。
2025-10-24 00:07:47
466
原创 用户态和内核态切换开销详解(了解即可)
如果是Java开发,不需要了解特别深度,当个阅读资料即可,大概明白里面最大的开销是TLB,缓存失效和上下文保存于恢复即可.CPU周期是CPU执行一条最简单指令所需的基本时间单位。2GHz的CPU:1个周期 = 0.5纳秒一次态切换1000周期 = 500纳秒 = 0.5微秒程序计数器(PC/EIP):当前执行到哪行代码栈指针(SP/ESP):栈顶位置通用寄存器(EAX, EBX等):临时数据状态寄存器(EFLAGS):CPU状态标志。
2025-10-22 14:43:37
866
原创 Spring Bean创建流程
(Web请求范围)(Web会话范围)(ServletContext范围)/** 一级缓存: 存放完全初始化好的单例Bean *//** 三级缓存: 存放Bean工厂,用于创建早期Bean *//** 二级缓存: 存放早期暴露的Bean(已实例化,未填充属性) *//** 正在创建中的Bean名称集合 */// ========== 1. 自定义Scope实现 ==========@Override。
2025-10-22 10:48:16
1370
原创 7 - Spring三大核心PostProcessor深度解析
Spring的后处理器(PostProcessor)是Spring框架对外开放的最重要扩展点之一,它允许我们深度介入到Bean的整个生命周期中,实现动态注册BeanDefinition、动态修改BeanDefinition以及动态修改Bean实例等强大功能。本文将通过大量核心源码分析和详细的流程图,深入剖析Spring三大核心PostProcessor的执行原理。一、BeanFactoryPostProcessor (工厂后处理器)1.1 基本介绍 是Spring提供的第一个核心扩展点,它允许我们在
2025-10-21 10:46:05
736
原创 6 - Java SPI,Spring SPI 新旧版本流程图对比学习
✓ 向后兼容(2.7+仍支持spring.factories)✗ 配置文件路径固定(META-INF/services/)✓ 统一配置文件 spring.factories。✓ 支持条件装配(@Conditional)✗ 配置格式复杂(需要反斜杠续行)✗ 所有配置混在一个文件,维护困难。✓ JDK原生支持,无需额外依赖。✓ 配置格式简单(每行一个类名)✓ 支持多个实现类,自动合并。✓ 支持多个实现类自动发现。✓ 支持注释(# 开头)✓ 按注解分类,职责单一。✓ 懒加载,按需实例化。
2025-10-21 10:08:31
398
原创 4-Spring SPI机制解读
对比项Java SPISpring SPI配置文件META-INF/services/接口名文件数量每个接口一个文件统一一个文件文件格式纯文本(每行一个类名)加载类获取方式只能获取实例可获取类名或实例缓存机制简单HashMapConcurrentReferenceHashMap(弱引用)实例化时机遍历时立即实例化可延迟实例化排序支持❌✅ 支持@Order排序条件过滤❌✅ 配合@Conditional使用。
2025-10-20 21:09:10
732
原创 JVM 的启动器类解读 -- sun.misc.Launcher
在深入理解Launcher是JVM 启动应用程序的入口类创建并初始化扩展类加载器(ExtClassLoader)创建并初始化应用程序类加载器(AppClassLoader)设置线程上下文类加载器管理安全管理器(SecurityManager)提供访问 Bootstrap ClassPath 的能力static {// 注册为支持并行加载的类加载器// 这样多个线程可以同时使用此加载器加载不同的类// ...static {// 支持并行类加载。
2025-10-20 16:06:00
1141
原创 3-Spring - @Import 机制详解
Import注解用于导入一个或多个组件类,通常是配置类。它提供了类似于Spring XML中<import/>元素的功能。Class<?// 可以导入的类型##@Import支持的三种导入类型根据源码@Import普通的@Configuration配置类或组件类- 直接导入配置类ImportSelector接口实现类- 动态选择要导入的配置类ImportBeanDefinitionRegistrar接口实现类- 直接注册BeanDefinition模仿 Spring 的等注解。
2025-10-20 14:47:05
761
原创 BeanDefinition 详解
/ ========== 作用域相关 ==========// ========== 生命周期相关 ==========// 是否懒加载// ========== 依赖关系 ==========// 依赖的bean名称// ========== Bean类信息 ==========// Bean的类名// ========== 工厂方法相关 ==========// ========== 构造函数和属性 ==========// 构造参数// 属性值。
2025-10-17 20:51:39
810
原创 5 - SpringBoot2.7新版本SPI机制-ImportCandidates 类详细解析
步骤1: 创建自动配置类@Bean步骤2: 创建配置文件创建文件:# 我的自定义服务自动配置步骤3: 打包为 jar其他项目引入该 jar 后,会自动生效。
2025-10-17 15:24:57
483
原创 JDK9中StackWalker类解读和实战
本文分析了Spring Boot启动流程中通过StackWalker推断主应用类的实现。StackWalker是Java 9引入的高效栈遍历API,相比传统方法具有惰性求值、可配置选项和Stream API支持等优势。文章详细介绍了StackWalker的核心概念、API使用方法,并展示了通过RETAIN_CLASS_REFERENCE选项获取调用栈类引用的示例,解释了Spring Boot如何利用这一特性在启动时推断主配置类。
2025-10-17 15:21:42
1007
原创 Java SPI (Service Provider Interface) 机制
是Java提供的一种服务发现机制,允许第三方为接口提供实现。它是一种基于接口的编程 + 策略模式 + 配置文件的设计模式。✅高度解耦: 接口定义与实现完全分离✅易于扩展: 添加新实现无需修改代码✅插件化: 支持第三方扩展✅标准化: Java官方提供的机制。
2025-10-16 11:50:07
688
原创 Enumeration 接口详解
/ 使用✅优点简单轻量,只有两个方法明确的只读语义与遗留代码兼容❌缺点方法名较长(vshasNext不支持删除操作不是 fail-fast 的已被Iterator取代。
2025-10-16 11:47:29
936
原创 Java SPI 完整加载流程详解-JAR 包到类实例化
如果可以理解SPI,无论是学习Java SPI还是Spring SPI或者xxx SPI都有很大的帮助,最近想深究了一下,看了看源码的部分,觉得挺有帮助.项目就整了一个很简单了,能跑就行,代码什么的不用纠结,用AI随便生成一个就能跑.本篇文章不太适合纯新手阅读,最好有读源码的经验,不然可能会比较懵.配置发现扫描 classpath 上所有 JAR 包查找META-INF/services/服务接口全限定名文件返回所有匹配文件的 URL 列表配置解析打开 JAR 包内的配置文件。
2025-10-16 11:41:15
1063
原创 分库分表系列-核心内容
本文系统介绍了分库分表的常用解决方案及设计方法。主要内容包括:1)垂直切分(分库/分表)按业务维度拆分,可降低耦合但无法解决单表数据量问题;2)水平切分(分库/分表)通过数据路由解决单表过大问题,但增加查询复杂度;3)分片算法包括哈希分片(简单但扩容困难)、一致性哈希(支持动态扩缩容)和范围算法(适合有序数据)。文章通过具体案例和图示详细说明了各种方案的实现原理、优缺点及适用场景,为数据库分库分表设计提供了系统性的指导。
2025-08-23 18:59:38
1106
原创 分库分表系列-基础内容
分库分表是应对海量数据场景的系统性解决方案,主要解决数据库的物理资源瓶颈(CPU、IO、连接数)、数据量瓶颈(单表超千万行性能下降)和运维瓶颈(备份恢复困难)。其核心思想将数据分散到多个库表,包含水平拆分(按行分表)和垂直拆分(按业务分库)两种方式。实施时机需谨慎:单表超千万行、QPS突破单库极限、高并发写入热点是明确信号;若数据量小或查询复杂则不宜采用。技术决策应遵循"SQL优化→缓存→读写分离→垂直拆分→水平拆分"的渐进路径,避免过早引入架构复杂度。
2025-08-23 10:57:18
751
原创 深度学习设计模式:责任链(Chain of Responsibility)模式(例子+业务场景+八股)
责任链是我觉得比较好理解,也是开发中比较能经常看到的设计模式,我个人认为它的核心思想:把请求的发送者和接受者解耦,让多个对象都有机会处理这个请求.将这些对象连成一条链,沿着这条链传递请求,直到有一个对象处理它为止.责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着一个处理链传递,直到链中的某个对象处理它。这样,发送者无需知道哪个对象将处理请求,所有的处理对象都可以尝试处理请求或将请求传递给链上的下一个对象。/**
2025-08-22 14:11:32
903
原创 DTO 与 DO 转换的三种主流方案深度解析
日常开发中,多数人都会遵循分层架构的最佳实践,不同层之间的数据流转离不开对象的转换。最常见的场景之一便是将前端传入的转换为数据库持久化操作的。在我实习的时候负责过优惠券模块的开发,这里我就拿一个常见的业务场景为例子:“新增优惠券模板”手动 get/setMapStruct基于反射的工具(如 Hutool、Dozer)根据不同场景选择最优方案提供给你的官方文档的链接官方文档中核心内容的解释.Controller层接收到的是,而在Service。
2025-08-22 14:11:15
1053
原创 计算机网络-网络层
想象一下全球的邮政系统。你写好一封信(数据),写上收信人的地址(目标地址)和自己的地址(源地址),然后投进邮筒。邮政系统会负责把这封信通过各种交通工具(火车、飞机、汽车)和中转站(分拣中心),最终送到收信人手中,无论收信人在世界的哪个角落。网络层在计算机网络中就扮演着类似邮政系统的角色。OSI 模型和 TCP/IP 模型中的位置在经典的 OSI (Open Systems Interconnection) 七层参考模型中,网络层是第三层,位于数据链路层之上,传输层之下。
2025-06-01 18:08:36
1428
原创 缓存并发更新的挑战
这是最直观也最常见的问题。多个客户端(或线程/进程)几乎同时读取同一份数据的初始状态(例如,库存量为100)。它们各自基于这个初始状态进行修改(A减1变99,B减2变98),然后先后写回。由于B的写入操作发生在A之后,B写入的98会覆盖A写入的99。最终结果是库存为98,但逻辑上正确的库存应该是100 - 1 - 2 = 97。A的操作 фактически丢失了。// 初始库存: 100// 线程A// 读取到 100// 计算为 99// ... 可能有一些耗时操作 ...// 写入 99。
2025-04-27 16:20:07
1404
原创 Redis 缓存并发问题深度解析:击穿、雪崩与穿透防治指南
缓存击穿,简单来说,是指某个访问极其频繁的热点 Key,在它失效的瞬间,恰好有大量的并发请求访问这个 Key。由于缓存已过期(或被剔除),这些并发请求无法命中缓存,便会“击穿”缓存层,同时涌向后端的数据库或其他数据源,导致数据库压力瞬间剧增,甚至可能被打垮。想象一下某个电商平台的爆款商品详情页,这个商品 ID 就是一个典型的热点 Key。平时成千上万的用户请求都由 Redis 缓存扛着,毫秒级响应。
2025-04-27 14:57:07
1060
原创 Redis 有序集合 ZSet 深度解析教程
ZSet 是 Redis 提供的一种有序集合数据结构。你可以把它想象成一个集合,但这个集合里的每个元素(我们称之为成员 member)都额外绑定了一个浮点数类型的分数 score。ZSet 最重要的特性就是它会根据 score 对 member 进行排序。核心特性总结:和普通的 Set 一样,ZSet 中的 member 是唯一的,不允许重复。如果你尝试添加一个已经存在的 member,只会更新它的 score。每个 member 都必须关联一个 score。
2025-04-24 14:53:06
1257
原创 JVM-类加载机制
对于Java开发者来说,我们每天都在编写.java文件,然后通过编译器将其编译成.class文件。那么,这些.class文件是如何被加载到Java虚拟机(JVM)中,并最终变成我们可以在程序中使用的对象和方法的呢?这个过程就是类加载(Class Loading)。理解类加载机制,不仅仅是满足技术好奇心,更是解决实际问题的关键。你是否遇到过或异常?是否好奇为什么 Tomcat 等Web容器可以隔离不同应用的类库?是否想了解热部署、模块化等高级特性是如何实现的?这些问题的答案,都深藏在类加载机制之中。类加载。
2025-04-24 10:35:53
1527
原创 深入理解 G1 GC:已记忆集合(RSet)与收集集合(CSet)详解
RSet 解决了“如何找到指向特定 Region 的引用”的问题,使得 G1 可以独立评估每个 Region 的存活性。但 G1 并不会在一次 GC 中回收所有可回收的 Region。为了满足用户设定的暂停时间目标,G1 必须精心选择一部分 Region 来构成单次 STW 回收的集合。这个集合就是收集集合 (Collection Set, CSet)。在一次 GC 暂停 (STW)期间,G1 将要回收(Evacuate)的所有 Region 的集合。
2025-04-23 11:46:58
1365
原创 深入JVM内存分配-本地分配缓冲(LAB)与TLAB详解
虽然本文重点是 TLAB,但简单了解 GCLAB 和 PLAB 有助于我们理解 LAB 思想的一致性。在使用复制算法(如 Parallel Scavenge 的 Minor GC, G1 的 Mixed GC)或标记-复制算法进行垃圾回收时,多个 GC 线程需要将存活的对象从源区域(如 Eden, Survivor From)复制到目标区域(如 Survivor To, Old Gen)。
2025-04-23 11:23:00
813
原创 JVM-卡表
卡表本质上是一个字节数组(byte[]。它将整个堆内存划分成固定大小的连续区域,每个区域称为一个“卡页(Card Page)”或“卡(Card)”(通常是 2 的幂次方大小,如 512 字节)。卡表中的每一个字节都对应堆内存中的一个卡页。画一个堆内存条,下面对应一个卡表数组,展示其映射关系。卡表中每个字节的值代表其对应卡页的状态。最简单的实现中,有两种状态:通常用 0 表示,意味着对应的卡页“可能没有”需要关心的引用(具体含义看应用场景)。
2025-04-23 09:56:34
1179
原创 深度学习与总结JVM专辑(七):垃圾回收器—CMS(图文+代码)
在Java虚拟机(JVM)的众多垃圾收集器(Garbage Collector, GC)中,CMS(Concurrent Mark Sweep)占有特殊的历史地位。虽然它在较新的JDK版本中已被标记为废弃(Deprecated)并最终移除,但理解CMS的设计理念、工作原理以及优缺点,对于深入掌握JVM内存管理、理解后续更先进的GC(如G1、ZGC)的演进思路,仍然具有非常重要的价值。CMS的核心目标是什么?简单来说,CMS的设计目标是获取尽可能短的回收停顿时间.
2025-04-22 08:21:26
1728
1
原创 阻塞队列-ArrayBlockingQueue
(JUC) 包提供了多种阻塞队列的实现,其中以其有界基于数组和线程安全的特性,在需要精确控制资源和流量的场景中扮演着重要角色。是包提供的一个有界阻塞队列。顾名思义,它的内部实现基于数组结构,并且在创建时必须指定一个固定的容量,这个容量在队列创建后不可改变。这个管道的长度在你创建它的时候就定死了,比如只能同时容纳 10 个物品。不能多也不能少,长度无法动态调整。物品(元素)从管道的一端放入(入队),从另一端取出(出队),遵循先进先出 (FIFO)的原则,就像排队一样。
2025-04-21 17:27:25
921
原创 Fork/Join - ForkJoinTask
高效并行处理:通过分治算法和工作窃取,优化多核处理器资源利用简化并行编程:框架自动处理任务调度、负载均衡和结果合并性能提升:特别适合CPU密集型的递归分解任务,可实现接近线性的加速比自适应调度:通过工作窃取,自动平衡不同工作线程的负载丰富的API:提供了多种子类和工具方法,满足不同场景需求大数据处理:处理大型数组、集合和数据集的并行操作搜索和排序:实现高效的并行排序、查找和过滤图像处理:并行处理图像滤镜、转换和分析科学计算:矩阵运算、模拟和数值分析Java平台核心功能。
2025-04-21 16:43:28
1177
原创 JUC线程池- ForkJoinPool
给定一个,计算其中所有元素的总和。分治思路:如果数组片段足够小(小于某个阈值 THRESHOLD),直接用单线程循环计算这个小片段的和。如果数组片段大于阈值:将其从中间分成两半(左半部分和右半部分)。创建两个新的子任务,分别负责计算左半部分和右半部分的和。并行执行这两个子任务。等待两个子任务都完成后,将其结果相加,得到当前片段的和。回顾 Java 并发框架的演进,基本的Thread。并发编程困难且易错。引入包,提供),LockAtomic*, 并发集合等。
2025-04-21 14:18:00
1263
原创 应用层核心协议详解:HTTP, HTTPS, RPC 与 Nginx
应用层是互联网协议栈的最顶层,直接面向我们日常使用的各种网络应用,例如网页浏览、文件传输、电子邮件等。理解应用层的核心协议对于任何Web开发者来说都至关重要默认读者已具备基础的计算机网络知识(如TCP/IP模型、IP地址、端口等)。HTTP是Web的基础,理解其方法、状态码、版本演进和状态管理机制(Cookie, Session, JWT)至关重要。
2025-04-21 08:56:05
1305
原创 阻塞队列-BlockingQueue
想象一下现实生活中的流水线:上游工序不断生产零件(生产者),下游工序不断取用零件进行组装(消费者)。为了保证流水线顺畅运行,通常会在上下游之间设置一个传送带或缓冲区。这个缓冲区有几个关键作用:在多线程编程的世界里,我们也面临类似的问题:不同的线程可能扮演着生产者和消费者的角色,它们需要一种安全、高效的方式来传递数据或任务。如果直接让它们共享一个普通的集合(如 或 ),就会遇到很多麻烦:为了解决这些痛点,Java 并发包 () 提供了 (阻塞队列)接口及其多种实现。 是 包下的一个接口,它继承自 接口。
2025-04-18 15:53:28
1016
原创 Java 线程中断机制详解
Java 线程中断是一种强大而优雅的线程协作机制,用于请求线程停止其当前任务。它并非强制终止,而是依赖于目标线程的主动响应。
2025-04-16 16:29:37
1244
原创 JUC- CompletableFuture
不带Async后缀的方法 (如thenApplythenAcceptthenRun这类方法的执行线程不是固定的,遵循“谁触发,谁执行(或调用者执行)”的原则。情况一:前置任务已经完成。当你调用thenApply时,如果它依赖的那个已经处于完成状态,那么thenApply里的回调逻辑会立即在当前调用线程中执行。情况二:前置任务尚未完成。当你调用thenApply时,如果前置任务还在运行(比如在某个线程池的线程 T1 中),那么这个回调逻辑会被“挂起”。当线程 T1 完成了前置任务后,
2025-04-16 10:05:05
1249
原创 深入理解Condition接口
在多线程编程中,线程间的协作至关重要。我们经常遇到这样的场景:一个线程需要等待某个条件满足后才能继续执行,而这个条件的改变依赖于其他线程的操作。例如,在经典的“生产者-消费者”模式中,当缓冲区为空时,消费者线程需要暂停等待,直到生产者线程放入数据;当缓冲区满时,生产者线程需要暂停等待,直到消费者线程取出数据。Java 的Object类提供了wait()notify(), 和方法,它们与关键字配合,构成了 Java 内置的线程等待-通知机制。单一等待队列:一个锁对象只能关联一个等待队列。
2025-04-16 08:20:24
870
原创 LockSupport 深度解析
AQS 是 JUC 中大多数同步器(SemaphoreFutureTask等)的基础框架。AQS 内部维护了一个虚拟的 CLH (Craig, Landin, and Hagersten) 双向队列来管理等待获取同步状态(如锁)的线程。在 AQS 中的作用:阻塞获取失败的线程: 当一个线程尝试获取同步状态失败时(例如,调用lock()但锁已被占用),AQS 会将该线程包装成一个节点(Node)加入到等待队列的尾部。然后,在将节点安全地插入队列后,AQS 会调用(这里的this。
2025-04-15 15:32:27
1259
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅