2026/3/6 13:55:30
网站建设
项目流程
建网站张掖哪家强?,信息型网站有哪些,新公司怎么做网络推广,凡客诚品官网旗舰店Spring Boot 钩子全集实战#xff08;六#xff09;#xff1a;SpringApplicationRunListener.contextPrepared() 详解
在上一篇中#xff0c;我们深入剖析了 ApplicationContextInitializer 这一容器初始化前的核心扩展点#xff0c;实现了容器安全加固、Bean 定义预处理…Spring Boot 钩子全集实战六SpringApplicationRunListener.contextPrepared()详解在上一篇中我们深入剖析了ApplicationContextInitializer这一容器初始化前的核心扩展点实现了容器安全加固、Bean 定义预处理等高阶能力。今天我们将继续跟进 Spring Boot 启动生命周期解析SpringApplicationRunListener接口的又一关键方法contextPrepared()。一、什么是SpringApplicationRunListener.contextPrepared()SpringApplicationRunListener.contextPrepared()是 Spring Boot 启动流程中衔接ApplicationContextInitializer与ApplicationContext刷新前的关键回调方法其触发时机和核心特征如下触发时机ApplicationContext已创建完成、ApplicationContextInitializer已全部执行完毕但容器尚未调用refresh()方法核心状态容器骨架已搭建Bean 定义尚未加载环境Environment已完全就绪执行顺序晚于ApplicationContextInitializer.initialize()早于SpringApplicationRunListener.contextLoaded()和容器refresh()核心能力可对ApplicationContext进行最终定制、添加容器级监听器、提前绑定资源、拦截 Bean 加载前置流程。✅核心价值作为容器刷新前的 “最后一道关卡”它弥补了ApplicationContextInitializer与容器加载之间的扩展空白可实现容器行为的最终校准、监听器动态注册等场景。二、场景容器启动权限校验防止非授权环境 / 用户启动应用业务痛点生产环境应用包可能被误拷贝到测试环境以外的非授权服务器如员工本地机器、第三方服务器启动导致敏感配置泄露部分核心应用如支付系统、用户中心仅允许指定运维用户启动普通用户启动可能引发操作风险传统权限校验多在 Bean 初始化后执行此时容器已加载部分资源校验失败后需额外清理效率低下。解决方案利用contextPrepared()方法在容器加载 Bean 前执行「服务器 IP 白名单校验」「启动用户白名单校验」校验失败直接终止应用启动从源头阻断非授权访问。步骤 1实现权限校验逻辑在contextPrepared()中修改CustomContextPreparedRunListener添加权限校验逻辑packagecom.example.demo.listener;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.SpringApplicationRunListener;importorg.springframework.context.ConfigurableApplicationContext;importorg.springframework.core.env.ConfigurableEnvironment;importjava.net.InetAddress;importjava.net.UnknownHostException;importjava.util.Arrays;importjava.util.HashSet;importjava.util.Set;/** * 自定义 SpringApplicationRunListener实现容器启动权限校验 */publicclassCustomContextPreparedRunListenerimplementsSpringApplicationRunListener{// 必须提供的构造方法publicCustomContextPreparedRunListener(SpringApplicationapplication,String[]args){}// 服务器 IP 白名单生产环境可从配置中心动态拉取privatestaticfinalSetStringSERVER_IP_WHITELISTnewHashSet(Arrays.asList(192.168.1.100,192.168.1.101,172.16.0.50// 生产授权服务器 IP));// 启动用户白名单生产环境可从配置中心动态拉取privatestaticfinalSetStringUSER_WHITELISTnewHashSet(Arrays.asList(prod_ops,admin,payment_admin// 授权运维用户));/** * 核心方法contextPrepared 实现启动权限校验 */OverridepublicvoidcontextPrepared(ConfigurableApplicationContextcontext){System.out.println([ContextPrepared] 开始执行容器启动权限校验...);ConfigurableEnvironmentenvironmentcontext.getEnvironment();StringcurrentEnvenvironment.getActiveProfiles().length0?environment.getActiveProfiles()[0]:prod;// 仅对生产环境执行严格权限校验开发/测试环境跳过if(prod.equals(currentEnv)){try{// 1. 服务器 IP 白名单校验validateServerIp();// 2. 启动用户白名单校验validateStartupUser();System.out.println([ContextPrepared] 权限校验通过允许启动应用);}catch(SecurityExceptione){System.err.println([ContextPrepared] 权限校验失败e.getMessage());// 校验失败直接终止 JVM 进程避免容器继续加载资源System.exit(1);}}else{System.out.println([ContextPrepared] 当前为非生产环境currentEnv跳过严格权限校验);}}/** * 服务器 IP 白名单校验 */privatevoidvalidateServerIp(){try{// 获取当前服务器本机 IPInetAddresslocalHostInetAddress.getLocalHost();StringserverIplocalHost.getHostAddress();System.out.println([ContextPrepared] 当前服务器 IPserverIp);if(!SERVER_IP_WHITELIST.contains(serverIp)){thrownewSecurityException(当前服务器 IPserverIp不在授权白名单内禁止启动);}}catch(UnknownHostExceptione){thrownewSecurityException(获取服务器 IP 失败e.getMessage());}}/** * 启动用户白名单校验 */privatevoidvalidateStartupUser(){// 获取当前启动应用的操作系统用户StringcurrentUserSystem.getProperty(user.name);System.out.println([ContextPrepared] 当前启动用户currentUser);if(!USER_WHITELIST.contains(currentUser)){thrownewSecurityException(当前用户currentUser不在授权白名单内禁止启动);}}// 其他生命周期方法省略OverridepublicvoidcontextLoaded(ConfigurableApplicationContextcontext){}Overridepublicvoidfailed(ConfigurableApplicationContextcontext,Throwableexception){}}步骤 2注册 RunListenerorg.springframework.boot.SpringApplicationRunListener\ com.example.demo.listener.CustomContextPreparedRunListener步骤3: 输出结果非授权 IP 启动生产环境[ContextPrepared] 开始执行容器启动权限校验... [ContextPrepared] 当前服务器 IP127.0.0.1 [ContextPrepared] 权限校验失败当前服务器 IP127.0.0.1不在授权白名单内禁止启动生产价值校验时机早容器加载 Bean 前避免非授权启动后清理资源的额外开销提升安全校验效率双重校验IP 用户形成完整的启动权限管控体系有效防止敏感应用被误启动或恶意启动支持环境差异化校验仅生产环境严格校验不影响开发 / 测试效率兼顾安全性与易用性白名单可扩展为从配置中心动态拉取无需修改代码即可更新授权列表提升维护灵活性。三、总结SpringApplicationRunListener.contextPrepared()是 Spring Boot 启动流程中容器刷新前的最终定制入口它承接ApplicationContextInitializer的执行结果为容器加载 Bean 定义做好最后的准备。其与ApplicationContextInitializer配合形成了 “容器创建 → 初始化 → 最终定制 → 加载 Bean” 的完整扩展链路是构建高可用、高灵活度企业级应用的重要支撑。关注我每天 5 分钟带你从 Java 小白变身编程高手 点赞 关注 转发让更多小伙伴一起进步 私信 “SpringBoot 钩子源码” 获取完整源码