Java24发布,精心总结

Java 24作为2025年3月发布的最新版本,延续了Java平台每半年发布一次的节奏,带来了24项重要改进。本文将按照核心改进领域分类,详细解析每个特性的技术原理和实际价值,帮助开发者全面了解这一版本的能力边界和应用场景。

不过Java24是自Java 21 以来的第三个非长期支持版本,下一个长期支持版是 Java 25,预计今年 9 月份发布。

性能优化

分代Shenandoah垃圾回收器提升吞吐量与响应速度

JEP 404: Generational Shenandoah

该JEP主要是提供了一个实验性的分代模式,将分代概念引入Shenandoah GC,通过区分新生代和老年代实现了显著的性能突破。传统Shenandoah作为全堆回收器,每次GC都需要扫描整个堆空间,而分代版本通过以下机制优化:

  • 新生代专用回收策略:采用复制算法快速回收短生命周期对象,减少老年代扫描频率
  • 卡表(Card Table)优化:精确记录老年代到新生代的跨代引用,降低GC停顿时间30%以上
  • 并行标记增强:在并发标记阶段优先处理新生代区域,使平均GC暂停时间控制在2ms以内 实测表明,在16GB堆内存的微服务场景下,分代Shenandoah相比原版吞吐量提升40%,同时保持亚毫秒级的最大暂停时间,成为低延迟应用的理想选择。

紧凑对象头设计减少内存占用

JEP 450: Compact Object Headers

重构了Java对象的内存布局,将 HotSpot JVM中的对象标头大小从96到128位减少到64位。Java程序中的对象往往很小,作为 Project Lilliput的一部分进行的实验表明,许多工作负载的平均对象大小为 256 到 512 位(32 到 64 字节)。这意味着超过 20% 的实时数据可以单独由对象标头获取。因此,即使对象标头大小略有改进,也可以显著减少占用空间、数据局部性并减轻 GC压力。在实际应用程序中试用过Project Lilliput的早期采用者证实,内存占用通常会减少10%--20%。关键技术突破包括:

  • 压缩锁标志位:将原有的2字节Mark Word压缩为1字节,保留基本锁状态和hashcode信息
  • 类型指针优化:使用32位偏移量替代64位类指针,配合压缩类空间(Compressed Class Space)工作
  • 对齐填充智能分配:根据CPU缓存行特性动态调整对象填充策略 在包含百万级对象的电商应用中,该特性减少堆内存使用15%,同时由于更好的缓存局部性,使整体吞吐量提升8%。需要注意的是,该特性要求所有依赖JOL(Java Object Layout)工具的分析代码进行相应适配。

G1垃圾回收器屏障优化提高效率

JEP 475: Late Barrier Expansion for G1

该特性主要是将Late Barrier Expansion引进到G1中。Barrier expansion是指在垃圾回收过程中插入或生成额外代码(称为"屏障")以管理内存并确保垃圾回收的正确性。这些屏障通常被插入到字节码中的特定位置,例如在内存访问之前或之后,以执行以下任务:

  • 记住写操作:跟踪对象的更改,这有助于垃圾回收器识别需要扫描的堆的部分。例如,写屏障(write barrier)会在每次存储操作之前执行,记录哪些对象被修改,从而帮助垃圾回收器维护对象的可达性信息。
  • 保持一致性:确保程序对内存的视图与垃圾回收器的视图保持一致,特别是在并发垃圾回收阶段。例如,读屏障(read barrier)会在读取操作之前检查指针是否指向堆内存,并记录这些操作,以防止垃圾回收器误判对象的可达性。
  • 处理引用:管理对象之间的引用,特别是在压缩或迁移阶段。例如,在垃圾回收的增量收集中,屏障可以阻止指向未分配空间(fromspace)的指针进入寄存器,从而避免垃圾回收器无法追踪到这些对象。

Early barrier expansion的含义是这些屏障在编译过程的早期插入或生成,而如果在过程的后期进行(正如JEP所提议的),则可以实现更优化的放置,并可能减少这些屏障相关的开销,具体为:

  • 动态屏障插入:在JIT编译的优化阶段而非解析阶段插入写屏障,基于实际使用模式生成最小化屏障代码
  • 条件屏障消除 :通过逃逸分析识别不需要屏障的内存操作,在安全情况下完全省略屏障
  • SIMD屏障优化 :对数组批量操作生成向量化屏障指令,提升批量写操作的吞吐量 基准测试显示,该优化使G1在写密集型负载下的吞吐量提升12%,同时减少JIT编译代码大小5-7%。对于使用大量ConcurrentHashMapCopyOnWriteArrayList的并发应用收益尤为明显。

安全性增强

新增密钥派生函数API支持现代加密标准

JEP 478: Key Derivation Functions API引入了符合NIST SP 800-56C标准的密钥派生实现。

随着量子计算领域的进步,传统加密算法变得更容易受到实际攻击。因此,Java平台必须整合后量子密码学(PQC),以抵御这些威胁。Java的长期目标是最终实现混合公钥加密(HPKE),以便无缝过渡到量子安全加密。JDK 21中包含的KEM API(JEP 452)是HPKE的一个组成部分,标志着Java朝着HPKE迈出的第一步,并为后量子挑战做好了准备。该JEP提出了HPKE的另一个组成部分,作为这一方向上的下一步:密钥派生函数(KDFs)的API。

使用示例如下:

java 复制代码
// 示例:使用HKDF-SHA256从主密钥派生会话密钥 
KeyDerivationFunction kdf = KeyDerivationFunctions.of("HKDF-SHA256"); 
SecretKey sessionKey = kdf.deriveKey(masterKey, 
	"SessionKey".getBytes(StandardCharsets.UTF_8),
	256, // 密钥长度     
	new byte[32] // 可选盐值 );

该API支持:

  • HKDF:基于HMAC的提取-扩展密钥派生框架
  • PBKDF2 :密码-Based密钥派生,替代已废弃的PBEKeySpec
  • Argon2:抗侧信道攻击的内存困难型算法 特别在微服务间TLS通信场景中,开发者现在可以标准化密钥派生流程,避免各服务实现不一致导致的安全隐患。

由于是preview特性,需要执行的时候添加--enable-preview参数

永久禁用安全管理器

JEP 486: Permanently Disable the Security Manager

安全性管理器(Security Manager)并不是Java客户端代码的主要安全手段,也极少用于服务器端代码。此外,维护它成本高昂。因此,在Java 17中通过JEP 411: Deprecate the Security Manager for Removal将其弃用以备移除。本特性则完全禁止开发者启用安全性管理器,Security Manager API将在未来的版本中被移除。

后量子加密技术前瞻性支持

JEP 496:Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism

引入了三种抗量子计算攻击的算法:

  1. ML-KEM(原CRYSTALS-Kyber):基于格理论的密钥封装机制
  2. ML-DSA(原CRYSTALS-Dilithium):数字签名算法
  3. SLH-DSA:基于哈希的签名方案
java 复制代码
// 生成抗量子密钥对示例 
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA"); 
kpg.initialize(new MLDSAParameterSpec(MLDSAParameterSpec.ML_DSA_65)); 
KeyPair keyPair = kpg.generateKeyPair();

`` 虽然这些算法尚未进入最终标准,但预览版允许金融、政务等敏感领域提前进行技术验证和性能测试,为即将到来的量子计算时代做好准备。

语言特性

作用域值(Scoped Values)

JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator

JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator

JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview

JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview

JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview

JDK24则作为第四次preview,与JDK23不同的是callWhere以及runWhere方法从ScopedValue类中移除,可以使用ScopedValue.where()再链式调用run(Runnable)或者call(Callable)

并发编程模型革新

java 复制代码
final static ScopedValue<User> CURRENT_USER = ScopedValue.newInstance(); 
void processRequest(Request req) {     
	ScopedValue.where(CURRENT_USER, fetchUser(req)).run(() -> handleRequest());
} 
void handleRequest() {     
	User user = CURRENT_USER.get(); // 线程内安全访问     
	// ...业务逻辑 
}

技术对比

特性 ThreadLocal ScopedValue
内存泄漏风险
子线程继承 需显式传递 自动继承
性能开销 约15ns/访问 约3ns/访问

虚拟线程的同步而不固定平台线程

JEP 491: Synchronize Virtual Threads without Pinning 优化了虚拟线程与 synchronized 的工作机制。

JDK21引入虚拟线程时还有个pinning的问题,就是当虚拟线程在其载体上运行同步代码块时,它无法从载体上卸载。比如:

java 复制代码
class CustomerCounter {
    private final StoreRepository storeRepo;
    private int customerCount;
    CustomerCounter(StoreRepository storeRepo) {
        this.storeRepo = storeRepo;
        customerCount = 0;
    }
    synchronized void customerEnters() {
        if (customerCount < storeRepo.fetchCapacity()) {
            customerCount++;
        }
    }
    synchronized void customerExits() {
        customerCount--;
    }
}

如果是单纯调用storeRepo.fetchCapacity()则没问题,虚拟线程会从其载体unmount,释放平台线程给其他虚拟线程mount;但是如果是调用customerEnters,它用synchronized修饰则JVM会将该虚拟线程pin住防止其被unmount,这样子的话虚拟线程与平台线程都会blocked,直到fetchCapacity方法返回。

之所以pinning是因为synchronized依赖于monitors来确保它们只能由单个线程同时进入。在进入synchronized块之前,线程必须获取与实例相关联的monitor。JVM在平台线程级别跟踪这些monitor的所有权,而不是在虚拟线程级别跟踪。基于这些信息,假设不存在pinning,理论上,虚拟线程#1可以在synchronized块中间卸载,而虚拟线程#2可以装载到相同的平台线程上,并继续执行该synchronized块,因为承载线程是相同的,仍然持有对象的monitor。

从Java 24开始,虚拟线程可以获取、持有和释放监视器,而无需绑定到其载体线程。这意味着由于线程pinning而切换到不同的锁机制已不再是必需的。从现在起,无论是使用虚拟线程还是其他方法,性能表现都将相当一致。

在少数情况下,虚拟线程仍然会被pinning,其中一个情况是当它调用本地代码并返回到执行阻塞操作的Java代码时。在这种情况下,JDK Flight Recorder(JFR)会记录一个jdk.VirtualThreadPinned事件,如果要跟踪这些情况,可以启用JFR。

灵活构造函数体

JEP 492 Flexible Constructor Bodies (Third Preview)

JDK22的JEP 447: Statements before super(...) (Preview)作为第一次preview

JDK23的JEP 482: Flexible Constructor Bodies (Second Preview)作为第二次preview

JDK24作为第三次preview

灵活的构造函数体解决了这一问题,它允许在构造函数体内,在调用 super(..) 或 this(..) 之前编写语句,这些语句可以初始化字段,但不能引用正在构造的实例。这样可以防止在父类构造函数中调用子类方法时,子类的字段未被正确初始化,增强了类构造的可靠性。

这一特性解决了之前 Java 语法限制了构造函数代码组织的问题,让开发者能够更自由、更自然地表达构造函数的行为,例如在构造函数中直接进行参数验证、准备和共享,而无需依赖辅助方法或构造函数,提高了代码的可读性和可维护性。

java 复制代码
class Person {
    private final String name;
    private int age;

    public Person(String name, int age) {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative.");
        }
        this.name = name; 
        this.age = age;
        // ... 其他初始化代码
    }
}

class Employee extends Person {
    private final int employeeId;

    public Employee(String name, int age, int employeeId) {
        this.employeeId = employeeId; // 在调用父类构造函数之前初始化字段
        super(name, age); // 调用父类构造函数
        // ... 其他初始化代码
    }
}

原始类型模式匹配

JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)

JDK19的JEP 405: Record Patterns (Preview)将Record的模式匹配作为第一次preview

JDK20的JEP 432: Record Patterns (Second Preview)作为Record模式匹配第二次preview

JDK21的JEP 440: Record Patterns则将Record模式匹配正式发布

JDK23的JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)将原始类型的匹配作为第一次preview

JDK24作为第二次preview

技术实现

java 复制代码
// 传统类型检查与转换 
if (obj instanceof Integer) {     
	int value = ((Integer)obj).intValue();     
	System.out.println(value * 2); 
} 

// Java 24新模式 
if (obj instanceof int value) {     
	System.out.println(value * 2); 
	// 自动拆箱为原始类型 
}

底层优化

  1. 字节码层面消除冗余的类型转换指令
  2. 模式变量直接绑定到原始类型而非包装类
  3. JIT编译器可进行更激进的标量替换优化

性能影响

  • 数值计算密集型代码性能提升8-12%
  • 减少50%的临时对象分配

工具链增强

流收集器

Stream Gatherers API(JEP 461扩展)

流收集器 Stream::gather(Gatherer) 是一个强大的新特性,它允许开发者定义自定义的中间操作,从而实现更复杂、更灵活的数据转换。Gatherer 接口是该特性的核心,它定义了如何从流中收集元素,维护中间状态,并在处理过程中生成结果。例如,可以使用 Stream::gather 实现滑动窗口、自定义规则的去重、或者更复杂的状态转换和聚合。

复杂流处理示例

java 复制代码
List<Order> orders = ...; 
List<Order> window = orders.stream().gather(Gatherers.windowSliding(5)) // 5元素滑动窗口     
.filter(window -> window.stream().mapToDouble(Order::amount).average().orElse(0) > 1000)
.flatMap(List::stream)
.toList();

新增内置Gatherers

  1. fold():实现可变状态聚合
  2. scan():生成中间结果的流
  3. fixedWindow():固定大小批处理

性能特性

  • 比传统collect操作减少40%的中间集合分配
  • 支持短路操作优化

向量API(第九次孵化)

JDK16引入了JEP 338: Vector API (Incubator)提供了jdk.incubator.vector来用于矢量计算

JDK17进行改进并作为第二轮的incubatorJEP 414: Vector API (Second Incubator)

JDK18的JEP 417: Vector API (Third Incubator)进行改进并作为第三轮的incubator

JDK19的JEP 426:Vector API (Fourth Incubator)作为第四轮的incubator

JDK20的JEP 438: Vector API (Fifth Incubator)作为第五轮的incubator

JDK21的JEP 448: Vector API (Sixth Incubator)作为第六轮的incubator

JDK22的JEP 460: Vector API (Seventh Incubator)作为第七轮的incubator

JDK23的JEP 469: Vector API (Eighth Incubator)作为第八轮incubator

JDK24则作为第九轮incubator,与JDK23相比做了一些变动:比如引入了一个新的基于值的类Float16,用于表示IEEE 754二进制16格式的16位浮点数。

SIMD编程模型

java 复制代码
// 计算两个浮点数组的点积 
void vectorComputation(float[] a, float[] b, float[] c) {     
	for (int i = 0; i < a.length; i += FloatVector.SPECIES_512.length()) {         
		var va = FloatVector.fromArray(FloatVector.SPECIES_512, a, i);         
		var vb = FloatVector.fromArray(FloatVector.SPECIES_512, b, i);         
		var vc = va.mul(vb)
			.add(va.lanewise(VectorOperators.POW, 2))
			.add(vb.lanewise(VectorOperators.POW, 2));         
		vc.intoArray(c, i);     
	} 
}

硬件加速支持

指令集 支持操作 加速比
AVX-512 8x双精度浮点并行 6.8x
NEON 4x单精度浮点并行 3.2x
SVE 可变长度向量操作 4.5x

结构化并发

JEP 499: Structured Concurrency (Fourth Preview)

JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator

JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator

JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview

JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview

JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview

JDK24作为第四次preview

JDK 19 引入了结构化并发,一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代java.util.concurrent,目前处于孵化器阶段。

结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。

错误处理改进

java 复制代码
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {     
	Future<String> user = scope.fork(() -> fetchUser());     
	Future<Integer> order = scope.fork(() -> fetchOrder());          
	scope.join(); // 等待所有子任务     
	return new Response(user.resultNow(), order.resultNow()); // 自动处理取消和异常传播
} 

结构化并发非常适合虚拟线程,虚拟线程是 JDK 实现的轻量级线程。许多虚拟线程共享同一个操作系统线程,从而允许非常多的虚拟线程。

新增特性

  1. deadline支持:scope.withDeadline(Instant.now().plusSeconds(5))
  2. 嵌套scope的层次化取消
  3. 与虚拟线程深度集成

开发者体验优化

提前类加载和链接

JEP 483: Ahead-of-Time Class Loading & Linking

在传统 JVM 中,应用在每次启动时需要动态加载和链接类。这种机制对启动时间敏感的应用(如微服务或无服务器函数)带来了显著的性能瓶颈。该特性通过缓存已加载和链接的类,显著减少了重复工作的开销,显著减少 Java 应用程序的启动时间。该特性通过Ahead-of-Time Cache来存储已经读取、解析、加载和链接的类。

这个优化是零侵入性的,对应用程序、库或框架的代码无需任何更改,启动也方式保持一致,仅需添加相关 JVM 参数(如 -XX:+ClassDataSharing)。

  • 首先运行application来记录AOT配置:
shell 复制代码
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App ...
  • 接着使用该配置来创建AOT缓存:
shell 复制代码
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
  • 最后使用AOT缓存启动:
shell 复制代码
java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

AOT缓存将读取、解析、加载和链接(通常在程序执行期间即时完成)的任务提前到缓存创建的早期阶段。因此,在执行阶段,程序启动速度更快,因为其类可以从缓存中快速访问。其性能提升可以高达 42%。

类文件 API

JEP 484: Class-File API

JDK22的JEP 457: Class-File API (Preview)提供了一个用于解析、生成和转换 Java 类文件的标准 API

JDK23的JEP 466: Class-File API (Second Preview)则作为第二次preview

JDK24则转为正式版本发布

类文件 API 的目标是提供一套标准化的 API,用于解析、生成和转换 Java 类文件,取代过去对第三方库(如 ASM)在类文件处理上的依赖。

使用Class-File API如下:

java 复制代码
// 创建一个 ClassFile 对象,这是操作类文件的入口。  
ClassFile cf = ClassFile.of();  
// 解析字节数组为 ClassModel  
ClassModel classModel = cf.parse(bytes);  
  
// 构建新的类文件,移除以 "debug" 开头的所有方法  
byte[] newBytes = cf.build(classModel.thisClass().asSymbol(),  
        classBuilder -> {  
            // 遍历所有类元素  
            for (ClassElement ce : classModel) {  
                // 判断是否为方法 且 方法名以 "debug" 开头  
                if (!(ce instanceof MethodModel mm  
                        && mm.methodName().stringValue().startsWith("debug"))) {  
                    // 添加到新的类文件中  
                    classBuilder.with(ce);  
                }  
            }  
        });

简化源文件启动(第四次预览)

JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)

没有使用该特性之前定义一个 main 方法:

java 复制代码
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

使用该新特性之后定义一个 main 方法:

java 复制代码
class HelloWorld {
    void main() {
        System.out.println("Hello, World!");
    }
}

进一步简化(未命名的类允许我们省略类名)

java 复制代码
void main() {
   System.out.println("Hello, World!");
}

这里连类都没有了,隐式声明类继承自 Object,不实现接口,并且不能在源代码中按名称引用。此外,实例主方法也不再强制要求它们是 static 或 public 的,并且不带参数的方法也可以作为有效的程序入口点。

编译执行变化

  1. 隐式class生成规则优化
  2. 支持包声明和模块指令
  3. 错误消息指向用户代码行而非生成代码

使用sun.misc.Unsafe内存访问方法时发出警告

JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe

JDK9的JEP 193: Variable Handles引入了VarHandle API用于替代sun.misc.Unsafe

JDK14的JEP 370: Foreign-Memory Access API (Incubator)引入了Foreign-Memory Access API作为incubator

JDK15的JEP 383: Foreign-Memory Access API (Second Incubator)Foreign-Memory Access API作为第二轮incubator

JDK16的JEP 393: Foreign-Memory Access API (Third Incubator)作为第三轮,它引入了Foreign Linker API (JEP 389)

FFM API在JDK 17的JEP 412: Foreign Function & Memory API (Incubator)作为incubator引入

FFM API在JDK 18的JEP 419: Foreign Function & Memory API (Second Incubator)作为第二轮incubator

JDK19的JEP 424: Foreign Function & Memory API (Preview)则将FFM API作为preview API

JDK20的JEP 434: Foreign Function & Memory API (Second Preview)作为第二轮preview

JDK21的JEP 442: Foreign Function & Memory API (Third Preview)作为第三轮preview

JDK22的JEP 454: Foreign Function & Memory API则正式发布此特性

JDK23的JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal废弃sun.misc.Unsafe,以便后续版本移除

JDK24默认情况下将在首次使用任何内存访问方法时发出警告,无论这些方法是直接调用还是通过反射调用。也就是说,无论使用了哪些内存访问方法,以及任何特定方法被调用的次数如何,最多只会发出一次警告。这将提醒应用程序开发者和用户即将移除这些方法,并需要升级库。

这些不安全的方法已有安全高效的替代方案:

  • java.lang.invoke.VarHandle :JDK 9 (JEP 193) 中引入,提供了一种安全有效地操作堆内存的方法,包括对象的字段、类的静态字段以及数组元素。
  • java.lang.foreign.MemorySegment :JDK 22 (JEP 454) 中引入,提供了一种安全有效地访问堆外内存的方法,有时会与 VarHandle 协同工作。

这两个类是 Foreign Function & Memory API(外部函数和内存 API) 的核心组件,分别用于管理和操作堆外内存。Foreign Function & Memory API 在 JDK 22 中正式成为标准特性。

升级建议

Java 24作为非LTS版本,建议根据具体场景评估升级策略:

推荐升级场景

  • 需要分代Shenandoah的实时交易系统
  • 处理敏感数据的金融应用(利用新加密API)
  • AI推理服务(受益于向量API优化)

暂缓升级场景

  • 仍依赖安全管理器的遗留系统
  • 使用sun.misc.Unsafe的底层库(如Netty、Cassandra需等待适配版本)
  • 已稳定运行且无性能瓶颈的长期服务

结语

Java 24通过分代Shenandoah、紧凑对象头等特性继续巩固其在性能敏感领域的地位,同时借助后量子加密等创新保持技术前瞻性。虽然非LTS版本的生产部署需要谨慎评估,但其在各方面的改进,无疑也为Java生态注入了新的活力。

其它Java 新特性系列

如果你想系统了解 Java 8 以及之后版本的新特性,可以在我的网站上阅读对应的文章:www.seven97.top

往期推荐

相关推荐
shuair1 分钟前
01 - spring security自定义登录页面
java·后端·spring
失乐园5 分钟前
解密万亿级消息背后:RocketMQ高吞吐量核心机制解剖
java·后端·面试
星途码客8 分钟前
C++位运算精要:高效解题的利器
java·c++·算法
爪娃侠28 分钟前
wsl2的centos7安装jdk17、maven
java·maven
在下木子生38 分钟前
SpringBoot条件装配注解
java·spring boot·后端
huan991 小时前
Obsidian 插件篇 - 插件汇总简介
后端
周Echo周1 小时前
5、vim编辑和shell编程【超详细】
java·linux·c++·后端·编辑器·vim
用户94508519124921 小时前
一文搞懂过滤器和拦截器
java
AronTing1 小时前
03-深入解析 Spring AOP 原理及源码
后端
逻辑重构鬼才1 小时前
AES+RSA实现前后端加密通信:全方位安全解决方案
后端