📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)、(进阶篇)、(架构篇)清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、阿里云专家博主、51CTO专家博主、产品软文专业写手、技术文章评审老师、技术类问卷调查设计师、幕后大佬社区创始人、开源项目贡献者。
📘拥有多年一线研发和团队管理经验,研究过主流框架的底层源码(Spring、SpringBoot、SpringMVC、SpringCloud、Mybatis、Dubbo、Zookeeper),消息中间件底层架构原理(RabbitMQ、RocketMQ、Kafka)、Redis缓存、MySQL关系型数据库、 ElasticSearch全文搜索、MongoDB非关系型数据库、Apache ShardingSphere分库分表读写分离、设计模式、领域驱动DDD、Kubernetes容器编排等。不定期分享高并发、高可用、高性能、微服务、分布式、海量数据、性能调优、云原生、项目管理、产品思维、技术选型、架构设计、求职面试、副业思维、个人成长等内容。

🌾阅读前,快速浏览目录和章节概览可帮助了解文章结构、内容和作者的重点。了解自己希望从中获得什么样的知识或经验是非常重要的。建议在阅读时做笔记、思考问题、自我提问,以加深理解和吸收知识。阅读结束后,反思和总结所学内容,并尝试应用到现实中,有助于深化理解和应用知识。与朋友或同事分享所读内容,讨论细节并获得反馈,也有助于加深对知识的理解和吸收。💡在这个美好的时刻,笔者不再啰嗦废话,现在毫不拖延地进入文章所要讨论的主题。接下来,我将为大家呈现正文内容。

JVM知识体系详解
类加载机制
Java虚拟机(JVM)的类加载机制是Java运行时的核心之一,它确保了Java代码的安全性、稳定性和效率。在类加载过程中,JVM通过类加载器负责将.class
文件从文件系统或网络加载到JVM中,并生成相应的java.lang.Class
对象。类加载机制主要分为以下几个阶段:
-
加载:类加载器负责查找和加载指定的
.class
文件。这个过程涉及到类加载器的加载策略和搜索路径。在Java中,主要有四种类型的类加载器:Bootstrap ClassLoader、Extension ClassLoader、System ClassLoader和用户自定义类加载器。Bootstrap ClassLoader负责加载核心库,如rt.jar
;Extension ClassLoader负责加载扩展库;System ClassLoader负责加载应用程序类路径(classpath)中的类;用户自定义类加载器可以按需定义,实现特定的加载逻辑。 -
验证:验证阶段确保加载的类信息符合JVM规范,防止恶意代码对JVM造成破坏。验证过程包括:文件格式验证、元数据验证、字节码验证和符号引用验证。
-
准备:准备阶段为类变量分配内存并设置默认初始值。对于基本数据类型,如
int
、float
等,其初始值为0;对于引用类型,如Object
,其初始值为null
。 -
解析:解析阶段将符号引用转换为直接引用。符号引用是指类、接口、字段和方法的符号名称和字面量,而直接引用是指直接指向对象的指针、偏移量或方法句柄。
-
初始化:初始化阶段是类加载过程的最后一个阶段,它执行类定义中指定的构造器方法(
<clinit>()
),给类变量赋予正确的初始值。初始化过程包括:执行静态代码块、执行静态初始化器方法、设置类变量的初始值。
双亲委派模型
双亲委派模型是Java类加载机制的核心设计之一,它要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。在加载类时,类加载器首先委托父类加载器进行加载,只有当父类加载器无法完成加载任务时,才自己尝试加载。这种设计可以避免类的重复加载,保证类型的全局唯一性,同时简化类加载过程。
自定义类加载器
自定义类加载器可以让我们控制类的加载过程,实现特定的功能,如模块化系统。自定义类加载器需要继承java.lang.ClassLoader
类,并重写findClass()
方法,实现类的查找和加载逻辑。在自定义类加载器中,我们可以根据需要修改类加载过程,例如:实现热部署、实现代码混淆、实现代码加密等。
模块化系统(JPMS)
Java Platform Module System(JPMS)是Java 9引入的一种模块化系统,旨在解决之前版本中JVM的依赖性和性能问题。它通过将代码划分为独立的模块来提高系统性能和安全性。JPMS的核心特性包括:
-
模块定义:模块定义文件(
module-info.java
)用于声明模块的依赖关系、模块的公开API和模块的私有API。 -
模块版本:模块版本采用语义版本控制,包括主版本号、次版本号和修订号。
-
模块依赖:模块之间的依赖关系通过模块定义文件中的
requires
、uses
、provides
和exports
关键字进行声明。 -
模块解析:模块解析器根据模块依赖关系,确定模块的加载顺序和依赖关系。
-
模块加载:模块加载器根据模块定义文件和模块依赖关系,将模块加载到JVM中。
内存模型
JVM的内存模型由多个运行时数据区组成,这些数据区分别负责存储不同的数据类型和对象。
-
堆:堆是JVM中最大的内存区域,用于存储几乎所有的Java对象实例和数组。堆被所有线程共享,垃圾回收器主要在堆上工作。
-
栈:每个线程有一个栈,用于存储局部变量和方法调用等。栈是线程私有的,栈空间相对较小,但访问速度较快。
-
方法区:方法区存储已经被虚拟机加载的类信息、常量、静态变量等。方法区被所有线程共享,其空间相对较小。
-
PC寄存器:每条线程有一个PC寄存器,指向当前执行的方法指令。PC寄存器是线程私有的,用于控制线程的执行流程。
内存溢出场景分析
内存溢出通常发生在堆空间不足时,常见场景包括:
-
创建大量对象:例如,创建大量小对象或大对象,导致堆空间耗尽。
-
长期存在内存泄漏:例如,对象生命周期过长,导致无法被垃圾回收器回收。
-
方法区或栈溢出:例如,加载大量类信息或方法信息,导致方法区空间不足;或递归调用深度过大,导致栈空间不足。
垃圾回收
垃圾回收(GC)是JVM自动内存管理的关键,它通过标记-清除、复制、整理等算法回收不再使用的对象占用的内存。垃圾回收的主要目标是减少内存占用,提高系统性能。
-
标记-清除:标记-清除算法首先标记所有可达对象,然后清除未被标记的对象。这种算法的缺点是会产生内存碎片。
-
复制:复制算法将对象在堆中分成两半,每次只使用一半,当这一半快满时,将存活的对象复制到另一半,然后清空原一半。这种算法的缺点是空间利用率较低。
-
整理:整理算法类似于复制算法,但在移动对象时会整理内存,减少内存碎片。
GC Roots可达性分析
GC Roots是一组特殊的对象,用于标记那些可达的对象。垃圾回收器通过遍历这些对象来确定哪些对象是不可达的。常见的GC Roots包括:
- 栈中的引用变量
- 方法区中的静态变量
- 方法区中的常量池
- 本地方法栈中的JNI引用
分代收集理论
分代收集理论将对象分为几代,通常是新生代(Young)和老年代(Old)。新生代对象存活时间短,回收频率高;老年代对象存活时间长,回收频率低。分代收集的主要目的是提高垃圾回收效率。
-
新生代:新生代主要存放新创建的对象,其回收频率较高。新生代采用复制算法进行垃圾回收,分为Eden区和两个Survivor区。
-
老年代:老年代存放存活时间较长的对象,其回收频率较低。老年代采用标记-清除或标记-整理算法进行垃圾回收。
引用类型
引用类型包括强(Strong)、软(Soft)、弱(Weak)和虚(Phantom)引用。不同类型的引用对垃圾回收的影响不同。
-
强引用:强引用是默认的引用类型,只要存在强引用,对象就不会被垃圾回收器回收。
-
软引用:软引用用于缓存,当内存不足时,垃圾回收器会回收软引用指向的对象。
-
弱引用:弱引用用于实现缓存淘汰策略,当内存不足时,垃圾回收器会回收弱引用指向的对象。
-
虚引用:虚引用是弱引用的加强版,它没有任何实际意义,只能通过引用队列来获取。
垃圾回收算法
-
标记-清除:标记-清除算法首先标记所有可达对象,然后清除未被标记的对象。这种算法的缺点是会产生内存碎片。
-
复制:复制算法将对象在堆中分成两半,每次只使用一半,当这一半快满时,将存活的对象复制到另一半,然后清空原一半。这种算法的缺点是空间利用率较低。
-
整理:整理算法类似于复制算法,但在移动对象时会整理内存,减少内存碎片。
并发收集器
并发收集器允许垃圾回收与应用程序线程并发执行,常见的有CMS(Concurrent Mark Sweep)和G1(Garbage-First)收集器。
-
CMS(Concurrent Mark Sweep):CMS收集器是一种以降低停顿时间为目标的并发收集器,适用于对停顿时间要求较高的场景。
-
G1(Garbage-First):G1收集器是一种面向服务端应用的垃圾回收器,适用于多核处理器和大型堆的场景。
停顿时间控制策略
JVM提供了多种策略来控制垃圾回收时的停顿时间,如G1的Garbage-First和CMS的并发标记和清除。
-
Garbage-First(G1):G1收集器通过将堆内存划分为多个区域,优先回收垃圾回收价值最高的区域,从而降低停顿时间。
-
并发标记和清除(CMS):CMS收集器通过并发标记和清除来降低停顿时间,但可能会产生内存碎片。
性能调优
性能调优涉及JVM参数配置(如Xms、Xmx等)、内存泄漏诊断和JIT编译优化。
-
JVM参数配置:通过调整JVM参数,如堆大小、栈大小、垃圾回收策略等,来优化JVM性能。
-
内存泄漏诊断:通过内存分析工具,如MAT(Memory Analyzer Tool)和VisualVM,来诊断和修复内存泄漏问题。
-
JIT编译优化:JIT编译器可以将Java字节码编译成机器码,从而提高程序执行效率。通过调整JIT编译器参数,可以优化JIT编译过程。
Spring Boot知识体系详解
自动配置
Spring Boot的自动配置是基于条件化配置实现的。当Spring Boot启动时,它会自动配置应用所需的所有Bean。自动配置的核心是@EnableAutoConfiguration
注解。
-
@EnableAutoConfiguration
原理:@EnableAutoConfiguration
通过扫描类路径下的jar包,找到所有配置类,并利用条件化配置来选择合适的配置。条件化配置主要基于以下条件:- 条件注解:例如
@SpringBootApplication
、@ConditionalOnClass
、@ConditionalOnMissingBean
等。 - 条件属性:例如
spring.datasource.url
、spring.datasource.username
等。
- 条件注解:例如
-
条件化配置(
@Conditional
):条件化配置允许我们根据特定条件选择性地启用或禁用某些配置。例如,当存在某个类时,才启用相应的配置。
自定义Starter开发
自定义Starter可以帮助我们快速集成第三方库到Spring Boot应用中。自定义Starter需要创建一个Maven或Gradle项目,并添加相应的依赖和配置。
-
创建自定义Starter:创建一个Maven或Gradle项目,并添加Spring Boot依赖和自定义配置。
-
添加依赖:将第三方库添加到自定义Starter的依赖中。
-
配置文件:在自定义Starter中添加配置文件,例如
application.properties
或application.yml
。 -
自动配置:在自定义Starter中添加自动配置类,实现自动配置逻辑。
起步依赖
起步依赖(Starter Dependencies)是Spring Boot项目的一部分,它们包含了创建独立运行项目所需的全部依赖。起步依赖简化了项目依赖管理,提高了开发效率。
-
起步依赖的组成:起步依赖通常包含以下组件:
- 核心依赖:例如Spring Boot核心库、Spring Web等。
- 依赖关系:例如数据库连接池、ORM框架等。
- 依赖版本:起步依赖中包含了所有依赖的版本信息。
-
依赖管理机制:Maven或Gradle等构建工具使用BOM(Bill of Materials)文件来管理项目依赖的版本。BOM文件定义了所有依赖的版本信息,确保项目中的依赖版本一致。
版本冲突解决
版本冲突通常发生在多个依赖项引入了同一库的不同版本时。Spring Boot通过选择合适的版本号来解决这个问题。
-
依赖树分析:分析项目依赖树,找出版本冲突的依赖项。
-
选择合适的版本号:根据依赖关系和版本兼容性,选择合适的版本号。
-
依赖排除:使用
<exclusions>
标签排除冲突的依赖项。
第三方库集成模式
Spring Boot提供了多种集成第三方库的模式,包括自动化配置、依赖注入和事件驱动等。
-
自动化配置:通过添加相应的起步依赖和自动配置类,实现第三方库的自动化配置。
-
依赖注入:使用Spring框架的依赖注入功能,将第三方库的实例注入到Spring容器中。
-
事件驱动:使用Spring框架的事件驱动机制,实现第三方库的事件监听和响应。
Actuator
Spring Boot Actuator是一个提供生产级应用监控和管理功能的模块。它允许我们通过HTTP端点获取应用的运行时信息。
-
Actuator端点:Actuator提供了多种端点,例如:
/health
:获取应用的运行状态。/metrics
:获取应用的性能指标。/info
:获取应用的元数据信息。/logs
:获取应用的日志信息。
-
自定义Endpoint开发:我们可以自定义Endpoint来提供特定于应用的监控和管理功能。
配置文件管理
Spring Boot支持多环境配置,允许我们根据不同的环境加载不同的配置文件(如application-{profile}.yml
)。
-
多环境配置:Spring Boot支持通过
application-{profile}.yml
文件实现多环境配置,例如:application-dev.yml
:开发环境配置。application-test.yml
:测试环境配置。application-prod.yml
:生产环境配置。
-
配置加载优先级:配置加载的优先级遵循“先配置,后覆盖”的原则。例如,如果同时存在
application.yml
和application-dev.yml
,则application-dev.yml
中的配置会覆盖application.yml
中的配置。
动态配置刷新
Spring Boot允许我们动态刷新配置,以便在运行时修改配置而不需要重启应用。
-
配置刷新机制:Spring Boot使用
@RefreshScope
注解来实现配置刷新。当配置发生变化时,Spring容器会自动刷新具有@RefreshScope
注解的Bean。 -
配置刷新方式:配置刷新可以通过以下方式实现:
- HTTP请求:通过HTTP请求触发配置刷新。
- 命令行:通过命令行参数触发配置刷新。
- 消息队列:通过消息队列触发配置刷新。
监控与日志
Spring Boot与Micrometer集成,提供了多种监控工具。同时,它支持Logback/SLF4J等日志框架。
-
监控工具:Spring Boot支持的监控工具包括:
- Micrometer:用于收集和导出应用性能指标。
- Prometheus:用于监控和告警。
- Grafana:用于可视化监控数据。
-
日志框架:Spring Boot支持的日志框架包括:
- Logback:用于日志记录和日志管理。
- SLF4J:用于日志门面。
分布式链路追踪扩展机制
Spring Boot支持分布式链路追踪,可以通过自定义配置来扩展链路追踪功能。
-
分布式链路追踪:分布式链路追踪是一种用于追踪分布式系统中请求路径的技术。Spring Boot支持以下分布式链路追踪框架:
- Zipkin
- Jaeger
-
自定义配置:通过自定义配置,我们可以选择合适的分布式链路追踪框架,并配置相关参数。
自定义AutoConfigurationBean生命周期扩展点
我们可以通过实现@Conditional
注解来扩展AutoConfigurationBean的生命周期。
-
AutoConfigurationBean生命周期:AutoConfigurationBean的生命周期包括:
- 初始化:创建AutoConfigurationBean实例。
- 销毁:销毁AutoConfigurationBean实例。
-
扩展生命周期:通过实现
@Conditional
注解,我们可以控制AutoConfigurationBean的生命周期,例如:- 在初始化阶段添加自定义逻辑。
- 在销毁阶段添加自定义逻辑。
响应式编程支持
Spring Boot支持响应式编程,通过Reactor、Project Reactor等库实现。
-
响应式编程:响应式编程是一种异步编程范式,它允许程序以非阻塞的方式处理事件。
-
响应式编程库:Spring Boot支持的响应式编程库包括:
- Reactor:用于构建响应式应用程序。
- Project Reactor:用于构建响应式流应用程序。
通过以上对JVM和Spring Boot知识体系的详细解析,我们可以更深入地理解Java虚拟机的工作原理和Spring Boot框架的核心特性。这些知识对于Java开发者和架构师来说至关重要,有助于提高代码质量、优化系统性能和解决实际问题。
📥博主的人生感悟和目标

- 💂 博客主页: Java程序员廖志伟希望各位读者大大多多支持用心写文章的博主,现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!
- 👉 开源项目: Java程序员廖志伟
- 🌥 哔哩哔哩: Java程序员廖志伟
- 🎏 个人社区: Java程序员廖志伟
- 🔖 个人微信号:
SeniorRD

📙经过多年在CSDN创作上千篇文章的经验积累,我已经拥有了不错的写作技巧。同时,我还与清华大学出版社签下了四本书籍的合约,并将陆续出版。这些书籍包括了基础篇、进阶篇、架构篇的📌《Java项目实战—深入理解大型互联网企业通用技术》📌,以及📚《解密程序员的思维密码--沟通、演讲、思考的实践》📚。具体出版计划会根据实际情况进行调整,希望各位读者朋友能够多多支持!
🔔如果您需要转载或者搬运这篇文章的话,非常欢迎您私信我哦~