手动获取spring bean的推荐方式有三种:一是实现applicationcontextaware接口,适用于spring管理的bean;二是启动时保存configurableapplicationcontext引用;三是用threadlocal+applicationcontextaware保障多线程安全。

在普通类中手动获取 Spring 的 Bean,核心思路是让该类能访问到 ApplicationContext。Spring 本身不鼓励在非托管类(如工具类、静态方法、new 出来的对象)中硬编码获取 Bean,但实际开发中有时确实需要——比如在 Filter、Utils 工具类、或第三方回调中临时取 Bean。以下是几种**安全、推荐、可落地**的方式:
方式一:实现 ApplicationContextAware 接口(最常用)
适用于你**能控制该类的生命周期**(即该类本身由 Spring 管理,是 Spring Bean),且希望在初始化后拿到上下文。
- 让类实现
org.springframework.context.ApplicationContextAware接口 - 重写
setApplicationContext()方法,将上下文保存为静态或成员变量 - 后续通过该引用调用
getBean()
示例:
@Component
public class BeanUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
public static <t> T getBean(Class<t> clazz) {
return context.getBean(clazz);
}
public static <t> T getBean(String name, Class<t> clazz) {
return context.getBean(name, clazz);
}
}</t></t></t></t>
⚠️ 注意:确保 BeanUtils 本身被 Spring 扫描并注册为 Bean(加 @Component 或配置类注入),否则 setApplicationContext() 不会被回调。
方式二:使用 SpringApplication.run() 后保留上下文引用
适用于主启动类或配置类中,在应用启动完成后显式保存上下文(适合简单场景或测试)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在
main方法中接收ConfigurableApplicationContext返回值 - 将其设为静态变量或通过工具类暴露
- 注意:仅在单例 Spring Boot 应用中安全;多上下文环境(如测试、嵌套容器)慎用
示例:
@SpringBootApplication
public class MyApp {
public static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(MyApp.class, args);
}
}
// 其他地方使用
MyService service = MyApp.context.getBean(MyService.class);
方式三:通过 ThreadLocal + ApplicationContextAware(支持多线程安全)
如果普通类可能被多线程调用(如 WebFilter、AOP 增强方法),且需避免静态上下文被覆盖或并发问题,可用 ThreadLocal 隔离。
- 仍需一个 Spring 管理的 Bean 实现
ApplicationContextAware - 用
ThreadLocal<applicationcontext></applicationcontext>存储当前线程的上下文(通常在请求进入时绑定) - 常见于自定义
OncePerRequestFilter中预设上下文
简化版示例(仅示意逻辑):
@Component
public class ContextHolder implements ApplicationContextAware {
private static final ThreadLocal<applicationcontext> contextHolder =
ThreadLocal.withInitial(() -> null);
@Override
public void setApplicationContext(ApplicationContext ctx) {
contextHolder.set(ctx);
}
public static <t> T getBean(Class<t> clazz) {
return contextHolder.get().getBean(clazz);
}
public static void reset() {
contextHolder.remove();
}
}</t></t></applicationcontext>
⚠️ 实际中更推荐结合 WebMvcConfigurer 或 Filter 自动绑定/清理,避免内存泄漏。
不推荐的做法(避坑提醒)
- 在 new 出来的对象里直接 new ClassPathXmlApplicationContext():会重复加载配置、创建新容器,破坏单例和事务管理
- 用静态 ApplicationContext 却未保证初始化顺序:可能导致空指针(如工具类早于 Spring 容器初始化就被调用)
- 在 @PostConstruct 中调用 getBean() 获取自己或循环依赖 Bean:可能触发提前曝光异常
本质上,Spring 的设计哲学是“依赖由容器注入”,手动获取只是兜底手段。优先考虑重构:把需要 Bean 的逻辑移到 Spring 管理的 Bean 中,用 @Autowired 注入;若真无法改造,再选上述任一可控方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










