news 2026/4/16 14:41:50

Spring Boot 钩子全集实战(五):ApplicationContextInitializer详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 钩子全集实战(五):ApplicationContextInitializer详解

Spring Boot 钩子全集实战(五):ApplicationContextInitializer详解

在上一篇中,我们深入剖析了SpringApplicationRunListener.environmentPrepared()这一关键扩展点,实现了环境合法性校验、启动上下文传递、多环境隔离兜底与配置动态增强等高阶能力。今天,我们将进入 Spring Boot 启动生命周期的下一个重要阶段——容器初始化前的关键扩展点ApplicationContextInitializer

一、什么是ApplicationContextInitializer

ApplicationContextInitializer是 Spring 框架原生提供的接口,在 Spring Boot 中被广泛用于ApplicationContext初始化完成前、刷新前(refresh 前)对容器进行定制化配置。其触发时机具有如下特征:

  • 触发时机ApplicationContext已创建但尚未调用refresh()
  • 核心状态Environment已完全准备就绪,所有配置已生效;
  • 执行顺序:晚于environmentPrepared(),早于BeanFactoryPostProcessor
  • 核心能力:可注册 Bean、修改 Bean 定义、设置容器属性、注入自定义逻辑。

核心价值:在容器刷新前对ApplicationContext做最后的“预热”和“定制”,是实现容器级扩展、安全加固、AOP 注入、监控埋点等场景的核心入口。

二、场景 :容器安全加固(禁止危险 Bean 注入)

业务痛点

微服务架构下,部分第三方库或内部组件可能通过自动配置注入高危 Bean(如RuntimeScriptEngineJndiTemplate),存在远程代码执行(RCE)风险。即使通过配置禁用,仍可能因依赖传递或版本升级被意外激活。

解决方案

利用ApplicationContextInitializer在容器刷新前扫描并移除/替换高危 Bean 定义,从源头阻断安全隐患。

实现代码
package com.example.demo.initializer; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.jndi.JndiTemplate; import org.springframework.util.StringUtils; import javax.naming.InitialContext; import javax.script.ScriptEngine; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * 容器安全加固初始化器 */ public class SecurityHardeningInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { // 高危类黑名单(可根据安全策略动态加载) private static final Set<String> DANGEROUS_BEAN_TYPES = new HashSet<>(Arrays.asList( "javax.script.ScriptEngine", "javax.naming.InitialContext", "org.springframework.jndi.JndiTemplate", "java.lang.Runtime" )); @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("[安全加固] 开始扫描并清理高危 Bean 定义"); //构造高危类黑名单的类 if (applicationContext instanceof BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(ScriptEngine.class); BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(InitialContext.class); BeanDefinitionBuilder builder3 = BeanDefinitionBuilder.genericBeanDefinition(JndiTemplate.class); BeanDefinitionBuilder builder4 = BeanDefinitionBuilder.genericBeanDefinition(Runtime.class); // 注册BeanDefinition registry.registerBeanDefinition("scriptEngine", builder1.getBeanDefinition()); registry.registerBeanDefinition("initialContext", builder2.getBeanDefinition()); registry.registerBeanDefinition("jndiTemplate", builder3.getBeanDefinition()); registry.registerBeanDefinition("runtime", builder4.getBeanDefinition()); } DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); String[] beanNames = beanFactory.getBeanDefinitionNames(); for (String beanName : beanNames) { var beanDefinition = beanFactory.getBeanDefinition(beanName); String beanClassName = beanDefinition.getBeanClassName(); if (StringUtils.hasText(beanClassName) && DANGEROUS_BEAN_TYPES.contains(beanClassName)) { System.err.printf("[安全加固] 检测到高危 Bean:%s(类型:%s),已移除!%n", beanName, beanClassName); beanFactory.removeBeanDefinition(beanName); } } // 禁止通过 @Import 或 ComponentScan 自动注册高危类 disableDangerousScanning(applicationContext); System.out.println("[安全加固] 容器安全加固完成"); } /** * 禁用高危类的组件扫描(防止后续自动注册) */ private void disableDangerousScanning(ConfigurableApplicationContext context) { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AssignableTypeFilter(Runtime.class)); // 实际生产中可结合 AspectJ 或字节码工具拦截,此处仅作示意 System.out.println("[安全加固] 已禁用高危类自动扫描(需配合编译期检查)"); } }
配置方式(任选其一)

方式 1:通过spring.factories

# resources/META-INF/spring.factories org.springframework.context.ApplicationContextInitializer=\ com.example.demo.initializer.SecurityHardeningInitializer

方式 2:通过主类显式注册

@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(DemoApplication.class); app.addInitializers(new SecurityHardeningInitializer()); app.run(args); } }
输出结果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.5.8) [安全加固] 开始扫描并清理高危 Bean 定义 [安全加固] 已禁用高危类自动扫描(需配合编译期检查) [安全加固] 容器安全加固完成 2025-12-17T23:58:06.580+08:00 INFO 11158 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 21.0.9 with PID 11158 (/Users/wangmingfei/Documents/个人/05 java天梯之路/01 源码/03 每日打卡系列/daily-check-in/springboot钩子/demo/target/classes started by wangmingfei in /Users/wangmingfei/Documents/个人/05 java天梯之路/01 源码/03 每日打卡系列/daily-check-in/springboot钩子/demo) 2025-12-17T23:58:06.581+08:00 INFO 11158 --- [ main] com.example.demo.DemoApplication : The following 1 profile is active: "prod" [安全加固] 检测到高危 Bean:scriptEngine(类型:javax.script.ScriptEngine),已移除! [安全加固] 检测到高危 Bean:initialContext(类型:javax.naming.InitialContext),已移除! [安全加固] 检测到高危 Bean:jndiTemplate(类型:org.springframework.jndi.JndiTemplate),已移除! [安全加固] 检测到高危 Bean:runtime(类型:java.lang.Runtime),已移除! 2025-12-17T23:58:06.876+08:00 INFO 11158 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2025-12-17T23:58:06.882+08:00 INFO 11158 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-12-17T23:58:06.883+08:00 INFO 11158 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.49] 2025-12-17T23:58:06.901+08:00 INFO 11158 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2025-12-17T23:58:06.901+08:00 INFO 11158 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 303 ms 2025-12-17T23:58:07.038+08:00 INFO 11158 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' 2025-12-17T23:58:07.042+08:00 INFO 11158 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 0.645 seconds (process running for 0.792)
生产价值
  • 从容器层面拦截高危 Bean,比运行时检测更早、更彻底;
  • 防止因依赖升级或配置错误引入安全漏洞;

三、总结

ApplicationContextInitializer是 Spring Boot 启动流程中连接环境准备与容器刷新的关键桥梁,它与environmentPrepared()形成“环境 → 容器”的完整扩展链路,是构建企业级高可靠、高安全、高可观测性应用不可或缺的一环。

📌关注我,每天 5 分钟,带你从 Java 小白变身编程高手!

👉 点赞 + 关注 + 转发,让更多小伙伴一起进步!

👉 私信 “SpringBoot 钩子源码” 获取完整源码!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 21:09:11

操作mysql常用python脚本,强到爆炸

1.导出数据库指定表的所有字段(含有字段注释)和数据导出结果如下#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ MySQL数据导出工具 - 修复元组索引问题 """import pandas as pd import pymysql import openpyxl from openpyxl.utils impo…

作者头像 李华
网站建设 2026/4/3 5:45:56

前后端分离学科竞赛管理系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

摘要 随着信息技术的快速发展&#xff0c;学科竞赛管理系统的信息化和智能化需求日益增长。传统的学科竞赛管理模式依赖人工操作&#xff0c;效率低下且容易出错&#xff0c;难以满足大规模竞赛活动的需求。为了解决这一问题&#xff0c;设计并实现一个基于前后端分离架构的学科…

作者头像 李华
网站建设 2026/4/14 2:12:22

DSP算法学习

都是以QPSK为例针对不同的qam信号&#xff0c;一些算法可能不同&#xff0c;还需读者再去学习从IQ时延对准-IQ不平衡-粗色散补偿-自适应均衡解复用-频偏估计与补偿-载波相位恢复

作者头像 李华
网站建设 2026/4/1 12:39:17

ai-agent 一个强大的辅助工具

随着ai的大热&#xff0c;如何更好的利用ai&#xff0c;而不单单作为知识的查询。如果它能帮我们设计测试用例&#xff0c;执行用例&#xff0c;并给出结果&#xff0c;甚至可以帮我们开发&#xff0c;是不是一个梦中情tool。 这不单单是幻想&#xff0c;目前不少大厂已经实现&…

作者头像 李华
网站建设 2026/4/16 13:00:41

[特殊字符]_微服务架构下的性能调优实战[20260108162541]

作为一名经历过多个微服务架构项目的工程师&#xff0c;我深知在分布式环境下进行性能调优的复杂性。微服务架构虽然提供了良好的可扩展性和灵活性&#xff0c;但也带来了新的性能挑战。今天我要分享的是在微服务架构下进行性能调优的实战经验。 &#x1f4a1; 微服务架构的性…

作者头像 李华
网站建设 2026/4/11 22:01:24

Gerber文件解析利器gerbv:PCB制造验证的专业解决方案

Gerber文件解析利器gerbv&#xff1a;PCB制造验证的专业解决方案 【免费下载链接】gerbv Maintained fork of gerbv, carrying mostly bugfixes 项目地址: https://gitcode.com/gh_mirrors/ge/gerbv 在电子设计自动化流程中&#xff0c;Gerber文件作为PCB制造的核心数据…

作者头像 李华