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

news/2025/11/4 16:33:29/文章来源:https://www.cnblogs.com/jimoer/p/19190686

前言

SpringBoot中,类加载机制与Java的传统双亲委派类加载机制是有一定区别。主要体现在自定义类加载器fat jar(可执行jar)的加载方式上。

Java的传统双亲委派模型

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

2、从 JDK 9 引入模块系统开始,是这样的层级结构
image
这样设计的主要目的是为了,避免重复加载核心类(如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 {@Beanpublic B b() { return new B(); }@Beanpublic A a(B b) {      // Spring 保证 b() 先跑return new A(b);}
}

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

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

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

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

如下代码:

@Configuration
public class Config {@Beanpublic B b() { return new B(); }@Bean@DependsOn("b")   // 容器会先实例化 b,再实例化 apublic 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 的扩展)

在容器刷新早期(所有 BeanDefinition 加载完、实例化之前)把定义顺序调到自己想要的顺序。

@Component
public class OrderBeanProcessor implements BeanFactoryPostProcessor {// 让某个 Bean 在普通 Bean 实例化之前提前实例化@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {PrimaryOrderBean bean = beanFactory.getBean(PrimaryOrderBean.class);System.out.println(bean);}
}
@Component
public class PrimaryOrderBean {public PrimaryOrderBean() {System.out.println("init primary order bean");}@Overridepublic String toString() {return "PrimaryOrderBean{toString}";}
}

此方式的风险:可读性差,容易踩坑,除非写框架,否则不建议

5、 @AutoConfigureBefore / @AutoConfigureAfter(仅对 spring.factories 里的自动配置生效)

当在写自己的 starter时,想让 MyAutoConfigurationDataSourceAutoConfiguration 之前/之后运行。
对普通 @Configuration 无效,也不会影响 Bean 实例化顺序,只影响配置类解析顺序。

@Configuration
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
public class MyAutoConfiguration { }

这两个注解只对 META-INF/spring.factories 中注册的 EnableAutoConfiguration 类生效;写在普通 @Configuration 类上会被忽略。

6、实现 PriorityOrdered / Ordered(只影响“后处理”顺序)

对普通 Bean 的“实例化顺序”没有任何影响,仅当 Spring 内部收集 BeanPostProcessorFactoryPostProcessor 等扩展点时使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/955825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年采沙船优质厂家权威推荐榜单:挖沙船/射吸式抽沙船/抽沙船设备源头厂家精选

在河道治理与基建需求持续增长的背景下,一艘高效可靠的采沙船已成为提升河道疏浚与沙矿开采效率的关键装备。 采沙船作为河道疏浚、沙矿开采的核心设备,其技术水平与作业效率直接影响着工程进度与资源开发效益。为帮…

PG小版本升级步骤参考指导

点击查看代码 小版本升级步骤:(例如12.2升级到12.3) 安装pg12.2到/usr/local/pg12.2里面,然后创建/usr/local/pg目录,ln -s /usr/local/pg /usr/local/pg12.2。 这样升级的时候安装pg12.3到/usr/local/pg12.3,然…

SQL Server 并发控制:Fabric Warehouse只支持快照隔离

Fabric Warehouse只支持快照隔离,这是强制执行的,且不能修改隔离级别,还是默认省略SET ISOLATION SNAPSHOT 语句。 一,Fabric Warehouse 只支持快照隔离级别 不同于传统的数据仓库,Fabric Warehouse对所有事务强制…

2025 年 11 月插入式密度计,音叉密度计,直管密度计,在线密度计厂家最新推荐,聚焦高性能与可靠性兼具的优质品牌

引言 近期,行业权威协会针对 2025 年 11 月插入式密度计、音叉密度计、直管密度计、在线密度计厂家开展专项测评,测评覆盖全球范围内百余家主流企业。测评采用 “资质审核 + 性能测试 + 案例验证 + 售后调研” 四维评…

国标GB28181算法算力平台EasyGBS助力公交/客运搭建全场景实时监控安全管理新体系

国标GB28181算法算力平台EasyGBS助力公交/客运搭建全场景实时监控安全管理新体系随着城市发展与出行需求增长,公交/客运行业安全与管理问题日益突出。车辆内治安事件频发,超速、违规驾驶等行为威胁乘客安全,传统管理…

2025塑胶/汽车/精密/五金/冲压/模具配件/司筒/顶针/镶件/优选榜:锦鸿深耕二十载领跑,四大实力企业筑牢精密制造根基​

2025 年,被誉为 “工业之母” 的模具产业加速升级,模具配件司筒作为核心组件,市场需求向高精度、耐损耗方向集中。在 “全球模具产业之都” 东莞引领下,一批企业凭借技术积淀脱颖而出,以下推荐榜聚焦真实实力,为…

PG升级步骤参考指导

点击查看代码 16版本升级到17版本时: 安装pg16到/usr/local/pg16里面,然后创建/usr/local/pg目录,ln -s /usr/local/pg /usr/local/pg16。 这样升级的时候安装pg17到/usr/local/pg17,然后修改/usr/local/pg指向/us…

2025年樱桃木木皮生产厂家权威推荐榜单:银橡木皮/榆木皮/天然木皮源头厂家精选

在高端家具制造与室内装饰行业,樱桃木木皮以其独特的纹理和色泽,正成为设计师青睐的表面装饰材料。 随着市场对绿色、环保材料的需求持续增长,樱桃木木皮因其可再生性和良好的装饰性能,应用范围从传统家具制造扩展…

MES表结构示例

活到老,学到老。

20232410 2025-2026-1 《网络与系统攻防技术》实验四实验报告

1.实验内容 一、恶意代码文件类型标识、脱壳与字符串提取 对提供的rada恶意代码样本,进行文件类型识别,脱壳与字符串提取,以获得rada恶意代码的编写作者,具体操作如下: (1)使用文件格式和类型识别工具,给出rad…

springboot xml json doc等选择

-------------------------------------------------------------------------------------------------------- XML 和 JSON,是程序员几乎每天都会打交道的数据、特别是配置数据的承载格式。我想你心里应该有一个大致…

2025 年 11 月科氏力质量流量计,热式气体质量流量计,质量流量计厂家最新推荐,聚焦资质、案例、售后的五家机构深度解读

引言 近期,行业权威协会针对科氏力质量流量计、热式气体质量流量计及质量流量计厂家开展专项测评,测评覆盖全球范围内百余家主流企业,从资质认证、实际应用案例、售后服务三大核心维度出发,采用数据量化分析与实地…

面向对象思考

面向对象思考 面向对象思考:核心理念 面向对象编程(OOP)的核心是将数据与操作数据的方法耦合为对象,以“对象”为基本单元构建程序,更贴合现实世界的问题建模方式。相比面向过程编程(以“方法”为核心,数据与方…

2025年工业用防爆除湿机生产厂家权威推荐榜单:防爆恒温恒湿机/防爆工业除湿机/防爆调温除湿机源头厂家精选

在石油化工、航空航天、电力能源等高风险行业,防爆除湿设备已成为保障生产安全、提升产品质量的关键环节。 随着国家对工业安全生产要求的不断提高,防爆除湿机市场需求呈现稳定增长。2024年,该品类产品国内市场询盘…

救命

感觉自从昨天秒了 T2 之后精神就不正常了。 现在怎么说呢,处于一种极其抽象的混沌状态,无法干任何有意义工作,大脑已经崩溃了。 今天模拟赛就能看出来我完全开摆了,丝毫不想写。 不知道该咋办,感觉在学校短时间内…

超越简单的回放:深度解析国标GB28181算法算力平台EasyGBS的录像检索与回放技术

超越简单的回放:深度解析国标GB28181算法算力平台EasyGBS的录像检索与回放技术在安防监控领域,国标GB28181国家标准如同“通用语言”,实现了不同安防设备与平台之间的互联互通。然而,仅仅实现设备的接入和实时预览…

2025年聚四氟乙烯膜生产厂家权威推荐榜单:特氟隆膜/铁氟龙膜/特氟龙膜源头厂家精选

在新能源与环保产业快速发展的推动下,聚四氟乙烯(PTFE)膜材料市场需求持续增长。据2025年行业统计数据显示,中国PTFE膜材料市场规模已达286亿元,年均增长率稳定在18%以上。 随着过滤材料、建筑材料和电子工业的升…

详细介绍:⸢ 柒-Ⅱ⸥ ⤳ 可信纵深防御建设方案:应用可信网络可信

详细介绍:⸢ 柒-Ⅱ⸥ ⤳ 可信纵深防御建设方案:应用可信&网络可信pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: …

一个BFS的trick

前言 感觉这个一个典中典典做法,但是我还是不会() 今天第二次遇到这个问题(上一次的找不到了),所以记录一下做法 CF2041D Drunken Maze 思路 对于在走迷宫的基础上加入“不能连续往一个方向走 \(k\) 步”限制的问…

2025 年 11 月股权设计财税合规公司推荐排行榜,股权架构设计,财税合规方案,企业股权激励,税务筹划公司推荐

2025年11月股权设计财税合规公司推荐排行榜:股权架构设计与财税合规方案深度解析 一、行业背景与发展趋势 随着我国市场经济体制的不断完善和企业治理结构的持续优化,股权设计与财税合规已成为企业健康发展的关键支撑…