普通工具类需通过 ApplicationContext 获取 Spring Bean,推荐实现 ApplicationContextAware 接口并用静态变量持有容器;替代方式是在启动类中手动注入 ApplicationContext;避免在非 Web 环境使用 Web 相关工具类。

普通工具类(比如 DateUtils、JsonUtils)本身不是 Spring 管理的 Bean,不能直接用 @Autowired 注入其他 Bean。要让它能调用 Service、Mapper 或其他 Spring 组件,核心思路只有一个:**让工具类能访问到 Spring 的 ApplicationContext 容器,再通过 getBean() 拿对象**。
推荐方式:实现 ApplicationContextAware 接口
这是最常用、最稳妥、Spring 官方支持的方式。工具类自己“主动申请”容器引用,并存为静态变量供全局使用。
- 写一个工具类(如
SpringContextUtil),加上@Component注解,确保它被 Spring 扫描到 - 实现
ApplicationContextAware接口,重写setApplicationContext方法,把传入的上下文赋值给静态字段 - 提供静态方法,如
getBean(Class<t> clazz)</t>或getBean(String name),内部调用applicationContext.getBean(...) - 在工具方法里直接调用
SpringContextUtil.getBean(YourService.class)即可
替代方式:启动类中手动注入 ApplicationContext
适合不想让工具类成为 Spring Bean 的场景(比如已有遗留工具包,不便加注解)。
- 定义一个普通工具类(无注解),含静态
ApplicationContext字段和setApplicationContext方法 - 在 Spring Boot 启动类的
main方法中,拿到ConfigurableApplicationContext后,立即调用该工具类的 set 方法传入 - 后续任何地方调用工具类的 getBean 方法,都能拿到容器里的对象
- 注意:必须在
SpringApplication.run()之后执行 set,否则容器还没初始化完成
不推荐但存在的做法:@Autowired 注入 ApplicationContext 到工具类
前提是这个工具类本身是 Spring Bean(比如加了 @Component)。这种方式看似简单,但有隐患:
- 如果工具类被多个线程频繁调用,而你又把它设计成单例(默认),
@Autowired的 ApplicationContext 是线程安全的,没问题;但若误用原型模式或手动 new 实例,就可能拿不到上下文 - 静态方法无法直接使用
@Autowired字段,仍需配合静态持有逻辑,本质上又回到第一种方式 - 不如直接实现
ApplicationContextAware清晰、可控、符合 Spring 生命周期契约
关键提醒:别在非 Web 环境里硬套 Web 工具类
像 WebApplicationContextUtils 这类工具,依赖 Servlet 上下文,在纯 Spring Boot 非 Web 项目(如定时任务、批处理)中会报空指针。务必确认你的项目类型,优先用通用的 ApplicationContext 方式。


















