当前位置: 首页 > news >正文

Spring——Spring相关类原理与实战

摘要

本文深入探讨了 Spring 框架中 InitializingBean 接口的原理与实战应用,该接口是 Spring 提供的一个生命周期接口,用于在 Bean 属性注入完成后执行初始化逻辑。文章详细介绍了接口定义、作用、典型使用场景,并与其他相关概念如 @PostConstruct 和 DisposableBean 进行了对比。

1. InitializingBean原理与实战

InitializingBean 是 Spring 提供的一个生命周期接口,其核心作用是让 Bean 在所有属性注入完成后执行一些初始化逻辑。

1.1. 🧩 接口定义

public interface InitializingBean {void afterPropertiesSet() throws Exception;
}

如果你的类实现了这个接口,Spring 会在完成依赖注入后自动调用 afterPropertiesSet() 方法。

1.2. ✅ InitializingBean作用

功能

说明

生命周期钩子

在 Bean 初始化(注入属性)后执行自定义逻辑

替代 @PostConstruct

是一种“接口驱动”的初始化方式

适用于框架开发

明确初始化点,便于统一管理

1.3. ✅ 典型使用场景(实战)

1.3.1. 初始化资源、连接等

@Component
public class RedisClient implements InitializingBean {private JedisPool jedisPool;@Value("${redis.host}")private String host;@Value("${redis.port}")private int port;@Overridepublic void afterPropertiesSet() throws Exception {jedisPool = new JedisPool(host, port);System.out.println("Redis 连接池初始化完成");}public Jedis getConnection() {return jedisPool.getResource();}
}

📌 实战说明:配置注入完成后,通过 afterPropertiesSet() 初始化 Redis 连接池。

1.3.2. 校验依赖是否注入完整

@Component
public class SomeService implements InitializingBean {@Autowiredprivate SomeDependency dependency;@Overridepublic void afterPropertiesSet() {if (dependency == null) {throw new IllegalStateException("SomeDependency 没有被注入!");}}
}

1.3.3. 在框架中设置静态访问点(如 XXL-Job 中)

@Override
public void afterPropertiesSet() throws Exception {adminConfig = this; // 设置静态访问入口xxlJobScheduler = new XxlJobScheduler();xxlJobScheduler.init(); // 初始化调度器
}

📌 实战说明:用于启动调度器、加载配置等初始化逻辑,适合中间件开发。

1.4. ✅ InitializingBean总结

  • InitializingBean 提供了一种 标准化的 Bean 初始化入口
  • 推荐用于:底层框架、组件、工具类初始化中,如连接池、调度器、配置校验。
  • 对于业务逻辑,更推荐用 @PostConstruct 注解,简洁易读。

2. @PostConstruct注解原理与实战

@PostConstruct 是 Java 提供的标准注解(来自 javax.annotationjakarta.annotation),在 Spring 中用于定义 Bean 的初始化方法,当 Bean 完成依赖注入之后自动执行。

2.1. ✅ @PostConstruct 是什么?

@PostConstruct
public void init() {// 初始化逻辑
}
  • 当 Spring 完成对 Bean 的创建与依赖注入后,会自动调用标注了 @PostConstruct 的方法。
  • 方法 只能有一个、无参数、返回值为 void

2.2. ✅ @PostConstruct与Spring生命周期的关系

Spring 创建一个 Bean 的完整流程如下:

构造函数 -> 依赖注入 -> @PostConstruct -> InitializingBean.afterPropertiesSet() -> Bean 初始化完成

因此,@PostConstruct 执行在 Bean 初始化的早期阶段,非常适合做以下操作:

用途

说明

资源初始化

建立连接池、定时器、缓存等

参数检查

校验注入的配置是否符合要求

注册操作

向注册中心、事件总线等注册自己

静态赋值

注入静态成员变量或构造辅助工具

2.3. ✅ 实战使用示例

2.3.1. 缓存初始化

@Component
public class DictCache {private final DictService dictService;private Map<String, String> dictCache = new HashMap<>();public DictCache(DictService dictService) {this.dictService = dictService;}@PostConstructpublic void loadCache() {dictCache = dictService.loadAllDict();System.out.println("字典缓存加载完毕!");}public String get(String key) {return dictCache.get(key);}
}

2.3.2. 参数校验或默认值设置

@Component
public class SmsSender {@Value("${sms.gateway.url}")private String gatewayUrl;@PostConstructpublic void validate() {if (gatewayUrl == null || gatewayUrl.isEmpty()) {throw new IllegalArgumentException("短信网关地址不能为空!");}}
}

2.3.3. 设置静态工具类

@Component
public class SpringContextUtil {@Autowiredprivate ApplicationContext applicationContext;public static ApplicationContext context;@PostConstructpublic void init() {SpringContextUtil.context = this.applicationContext;}public static <T> T getBean(Class<T> clazz) {return context.getBean(clazz);}
}

2.4. ✅ @PostConstruct与InitializingBean 的对比

特性

@PostConstruct

InitializingBean

来源

Java 标准注解

Spring 接口

侵入性

低(无需实现接口)

高(必须实现接口)

可读性

更清晰、简洁

稍显繁琐

推荐

✅ 推荐

❌ 一般不推荐用于业务代码

场景

普通业务初始化

框架、组件级初始化

3. @PostConstructInitializingBean区别?

缓存初始化 场景中,@PostConstructInitializingBean 都能完成初始化逻辑,但两者有以下核心区别

  • @PostConstruct 是注解驱动的初始化方式,简洁、解耦、推荐用于业务代码
  • InitializingBean 是接口驱动的初始化方式,侵入性强,推荐用于框架/中间件级别代码

3.1. ✅ 功能与使用上的对比

对比项

@PostConstruct

InitializingBean

本质

Java 标准注解(JSR-250)

Spring 生命周期接口

编码方式

在方法上加注解

实现接口、重写方法

方法名

任意(如 init()

固定:afterPropertiesSet()

方法个数

可以多个类中各定义一个

一个类只能有一个 afterPropertiesSet()

侵入性

✅ 低:无须继承或实现接口

❌ 高:必须实现接口

可读性

✅ 强:一看注解就知道是初始化

❌ 差:容易被忽视

可测试性

✅ 好(不会影响类结构)

❌ 接口实现影响结构

场景适用

业务代码、工具类、缓存加载

框架设计、底层组件、可复用模块

推荐程度

✅ 更推荐使用

⚠️ 更适合框架代码

3.2. ✅ 实际缓存初始化场景对比

3.2.1. 用@PostConstruct 初始化缓存

@Component
public class DictCache {@Autowiredprivate DictService dictService;private Map<String, String> cache = new HashMap<>();@PostConstructpublic void initCache() {cache = dictService.loadAllDict();}
}

优点

  • 简洁明了
  • 不影响类结构
  • 易于测试和维护

3.2.2. 用InitializingBean 初始化缓存

@Component
public class DictCache implements InitializingBean {@Autowiredprivate DictService dictService;private Map<String, String> cache = new HashMap<>();@Overridepublic void afterPropertiesSet() throws Exception {cache = dictService.loadAllDict();}
}

⚠️ 缺点

  • 需要实现接口,影响类设计
  • 方法名固定,不够语义化
  • 可读性差:不能一眼看出这是初始化方法

3.3. ✅ 实际开发推荐

场景

推荐方式

普通业务初始化(如缓存、参数)

@PostConstruct

框架开发 / 高通用组件(如连接池、调度器)

InitializingBean

初始化逻辑中涉及多个阶段、多个顺序

❌都不推荐,建议用 @Bean(initMethod = "...") 或配置类

4. DisposableBean原理与实战

DisposableBean 是 Spring 提供的一个生命周期接口,用于在 Bean 被销毁时执行清理逻辑,常用于释放资源、关闭连接、销毁线程池等操作。DisposableBean 接口的 destroy() 方法会在 Spring 容器销毁该 Bean 之前被调用,用于完成资源释放或清理工作。

4.1. 🧩 接口定义

public interface DisposableBean {void destroy() throws Exception;
}

Spring 会在 容器关闭前 调用实现类的 destroy() 方法。

4.2. ✅ 释放线程池

@Component
public class TaskManager implements DisposableBean {private ExecutorService threadPool = Executors.newFixedThreadPool(10);public void submit(Runnable task) {threadPool.submit(task);}@Overridepublic void destroy() throws Exception {System.out.println("正在关闭线程池...");threadPool.shutdown();}
}

📝 当 Spring 容器关闭时,destroy() 方法被自动调用,安全关闭线程池。

4.3. ✅ 关闭数据库连接或 Redis 客户端

java复制编辑
@Component
public class RedisClientWrapper implements DisposableBean {private JedisPool jedisPool = new JedisPool("localhost");public Jedis getClient() {return jedisPool.getResource();}@Overridepublic void destroy() throws Exception {System.out.println("关闭 Redis 连接池");jedisPool.close();}
}

4.4. ✅ 结合 InitializingBean

有时你会在一个类中同时使用初始化和销毁逻辑:

@Component
public class MyService implements InitializingBean, DisposableBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("初始化资源");}@Overridepublic void destroy() throws Exception {System.out.println("清理资源");}
}

4.5. 🛠️ 替代方案:@PreDestroy

Spring 也支持使用 @PreDestroy 注解实现销毁逻辑:

@PreDestroy
public void cleanup() {System.out.println("释放资源 @PreDestroy");
}

4.5.1. 🔍 区别总结:

对比项

DisposableBean

@PreDestroy

来源

Spring 接口

Java 标准注解(JSR-250)

入侵性

高(实现接口)

低(注解)

推荐程度

❌ 较低

✅ 更推荐

方法限制

固定 destroy()

方法名可自定义

结构清晰

❌ 不利于多继承

✅ 解耦、灵活

4.6. ✅ 总结

项目

说明

接口名

DisposableBean

方法

destroy()

调用时机

Bean 被销毁前(如容器关闭)

常见用途

释放线程池、关闭连接池、清理缓存等

推荐替代

使用 @PreDestroy更灵活、非侵入式

使用场景

资源管理类、任务调度类、连接池等生命周期敏感组件

如果你在业务中需要在 Spring 应用关闭时清理资源,推荐使用 @PreDestroy;如果你正在写一个框架、组件,或者需要精确控制 Bean 生命周期,则可以使用 DisposableBean

博文参考

相关文章:

  • 桑荫不徙 · 时之沙 | 在筛选与共生之间,向轻盈之境远航
  • 11.无重复字符的最长子串
  • 电路图识图基础知识-电动机制动控制电路(十八)
  • Java 8 Stream API 入门到实践详解
  • 人工智能赋能高中学科教学的应用与前景研究
  • 【Qt】背景知识 + 环境搭建
  • Xilinx FPGA MIPI DSI TX Subsystem 仿真笔记
  • 【Langchain】构建RAG基本流程
  • QT使用AES加解密,openssl及QCA问题记录
  • 综合笔试知识点
  • 文字转语音
  • 关于汉语普通话元音音位最好归纳为几个的问题
  • 能上Nature封面的idea!强化学习+卡尔曼滤波
  • 【Electron】应用打包教程(包含 C++ 后端 + 前端)
  • Spring AI与Spring Modulith核心技术解析
  • springboot的test模块使用Autowired注入失败
  • 【Linux】Linux进程间通讯-共享内存
  • FSMC扩展外部SRAM
  • Linux Gnome壁纸
  • 言思集交流社区(SpringBoot)
  • 网站访客qq统计 原理/短视频营销策略
  • 成都网站建设公司排名/东莞最新消息 今天
  • html5 css3网站实例设计报告/seo优化专家
  • 网易那个自己做游戏的网站是什么原因/网络服务商在哪咨询
  • 电子商务网站建设的必要性/厦门seo排名
  • 浦城县规划建设旅游局网站/淘数据