尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

SpringBoot(springboot的类加载和传统的双亲委派有什么区别、如何按顺序实例化Bean)

SpringBoot(springboot的类加载和传统的双亲委派有什么区别、如何按顺序实例化Bean)
📅 发布时间:2026/7/1 2:18:53

Java的传统双亲委派模型

Java传统类加载机制,遵循双亲委派模型,核心规则:类加载请求优先由父类加载器处理,只有父加载器无法加载时才由子加载器尝试。
1、JDK 1.8及更早版本采用如下层级结构:

2、从 JDK 9 引入模块系统开始,是这样的层级结构


这样设计的主要目的是为了,避免重复加载核心类(如java.lang.String),确保安全性(防止用户篡改核心类)。

SpringBoot的类加载器改造

改造原因

SpringBoot通过自定义类加载器LaunchedURLClassLoader打破了传统双亲委派的严格层级,主要解决fat jar中嵌套jar的加载问题。

在SpringBoot中,使用打包构建工具时,无论是Maven还是Gradle,在lib/目录中的第三方依赖是以JAR形式打入项目主JAR内的,默认会生成一个包含所有依赖项的fat jar。
目录结构示例如下:

mySpringBootApp.jar ├── BOOT-INF │ ├── classes(用户代码) │ └── lib(依赖的第三方jar) └── org.springframework.boot.loader

传统的Java类加载机制,Application ClassLoader只能从外部classpath加载类,无法直接加载JAR包内嵌的其他JAR(fat jar),因此SpringBoot加入了自定义的类加载器。

主要做了哪些改造

SpringBoot使用LaunchedURLClassLoader(继承自URLClassLoader)替代了ApplicationClassLoader,通过运行时动态生成jar路径的URL来加载嵌套jar。

  • LaunchedURLClassLoader会先加载BOOT-INF/classes目录下的应用类(优先于JDK类)。
  • 再加载BOOT-INF/lib/目录下的依赖JAR,LaunchedURLClassLoader会解析BOOT-INF/lib/下的每个jar,将其URL添加到类路径中。
  • 最后再交给父类加载器(即ApplicationClassLoader)。

总结一下:为了加载嵌套在主JAR内部的fat jar,SpringBoot在类加载流程上做了改造,增加了LaunchedURLClassLoader类加载器,并且会先尝试加载自身的类和依赖JAR,找不到要加载的类时,才交给父类加载器,从而对传统的双亲委派模型进行了改造。

注意,LaunchedURLClassLoader 仅对 BOOT-INF/classes 和 BOOT-INF/lib 下的类采用“子加载器优先”策略,核心类库仍严格遵循双亲委派,因此不会破坏 JDK 的安全模型。

扩展知识

在使用SpringBoot进行开发项目时,SpringBoot官方推荐我们使用热部署的方式是使用spring-boot-devtools模块。

其实SpringBoot的热部署并不是真正意义上的“热替换”,而是通过双类加载器机制实现的“快速重启”。

SpringBoot的“热部署”主要实现原理如下:

  1. 双 ClassLoader 架构:
    • Base ClassLoader:加载第三方 jar 包(不会频繁变动)
    • Restart ClassLoader:加载开发者自己写的类(会频繁变动)
  2. 文件变化监听机制
    • DevTools启动一个后台线程,监听classpath下.class文件的变化
    • 一旦检测到变化,丢弃旧的Restart ClassLoader
    • 重新创建一个新的Restart ClassLoader,加载更新后的类
    • 然后通过反射重新调用main()方法,实现应用重启

由于不需要重新加载第三方类(Base ClassLoader不变),也不需要重新初始化整个Spring容器,重启过程只涉及开发者代码部分,节省大量时间。

虽然叫“热部署”,但本质上是“部分重启”,不是真正的 JVM 热替换(如JRebel那样)

SpringBoot如何指定在其他Bean之前实例化指定的Bean

Bean 实例化/初始化顺序其实就是指“哪个 Bean 先被 new、哪个 @PostConstruct 先跑”。

目前有6种方式可以实现按照一定顺序进行实例化Bean。

1、构造器依赖(最稳,无侵入)

Spring 保证一个 Bean 实例化之前,它依赖的 Bean 必须已实例化。
直接让 BeanA 的构造器里需要 BeanB,或者 BeanA 里有一个非延迟的 BeanB 字段 +@Autowired。

如下代码

@Configuration public class Config { @Bean public B b() { return new B(); } @Bean public A a(B b) { // Spring 保证 b() 先跑 return new A(b); } }

使用这种方式,理解起来简单,并且可靠性高,与具体的应用框架无关,但是也有一定的短板,就是按指定顺序实例化的Bean,必须存在真实的依赖关系。

2、@DependsOn(显式声明,无真正依赖也适用)

虽然两个 Bean 之间没有构造器/字段依赖,但你仍想让 BeanB 先实例化于BeanA。
这个时候就可以使用@DependsOn注解了,但是需要注意一点:@DependsOn只能保证先实例化,不能保证先销毁(销毁顺序用DependentBean.destroyMethod或DisposableBeanAdapter)。

@DependsOn 仅控制 初始化顺序;销毁时 Spring 会按依赖关系的反向顺序执行,因此若 B 依赖 A,则 B 先销毁,A 后销毁。

如下代码:

@Configuration public class Config { @Bean public B b() { return new B(); } @Bean @DependsOn("b") // 容器会先实例化 b,再实例化 a public A a() { return new A(); } }

直接将注解写在类上也可以

@Component @DependsOn("b") public class A { }

3、@Order 或 Ordered(只影响“收集型”顺序)

适用范围:

  • @Bean方法返回的是Collection注入点(如List<X>、Map<String,X>)。
  • CommandLineRunner / ApplicationRunner / Filter / Interceptor等“链式”扩展点。对普通的单例Bean实例化顺序无效。

即使两个单例 Bean 实现了 Ordered 接口,只要它们之间不存在“收集型注入”或“链式扩展点”,Spring 仍然不保证谁先实例化。

使用场景如下代码示例,使用此注解的Bean都是实现了同一个接口的同类型。

@Component @Order(1) public class FirstRunner implements CommandLineRunner { ... } @Component @Order(2) public class SecondRunner implements CommandLineRunner { ... }

4、BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessor 的扩展)

相关新闻

  • 只看光明的一面:当机器学习失去“反面教材“时 | Positive-Only Learning深度解读
  • 2026亚太EMBA QS排名客观测评与科学择校指南
  • 单链表反转:Python/Java/C++三解

最新新闻

  • PrismLauncher-Cracked:终极Minecraft启动器破解版完整使用指南
  • Claude Code项目越写越乱?这套清理流程能救你
  • 2026年AI编程与开发工具盘点:从代码辅助到对话式开发的多条路径
  • AI自动转换PSD为Unity UGUI预制体:原理、实践与避坑指南
  • AI代码助手入门指南:从Cursor到Claude Code,新手如何高效编程
  • 企业级AI Agent实战:从原理到落地的完整指南

日新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号