在Spring中,普通类无法直接使用@Autowired注入Bean,核心解决方案是让其访问ApplicationContext实例:方式一实现ApplicationContextAware接口(推荐,需为Spring Bean);方式二静态持有上下文(需确保初始化顺序);方式三显式传参(轻量解耦)。

在 Spring 中,普通类(非 Spring 管理的类,比如工具类、静态方法内部新建的对象、或第三方回调中创建的实例)默认无法直接使用 @Autowired 注入 Bean。要从中获取 Spring 容器中的 Bean,核心思路是:**让该普通类能访问到 ApplicationContext 实例**。
方式一:实现 ApplicationContextAware 接口(推荐,适用于单例普通类)
这是最标准、侵入性小且线程安全的方式。Spring 会自动将容器上下文注入实现该接口的 Bean。
说明:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 你的普通类必须本身是 Spring 管理的 Bean(即被
@Component、@Service等注解标记,或通过 Java Config 注册); - 不能是 new 出来的临时对象,否则 Spring 不会回调
setApplicationContext; - 适合用作工具门面类(如
BeanUtils)、事件监听器、或需要跨模块调用 Bean 的中间服务。
示例:
立即学习“Java免费学习笔记(深入)”;
@Component
public class BeanUtil 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);
}
}
之后在任意地方(包括静态方法、new 出的对象里)调用 BeanUtil.getBean(XXXService.class) 即可。
方式二:通过静态持有 ApplicationContext(需确保初始化顺序)
如果无法将普通类声明为 Spring Bean(例如某个 legacy 工具类不能加注解),可以手动在启动时保存上下文。
说明:
- 通常在主启动类或一个
@Configuration类中,通过SpringApplication.run(...)返回的ConfigurableApplicationContext赋值给静态变量; - 务必保证赋值发生在任何普通类使用前(一般放在
main方法末尾或ApplicationRunner中); - 注意多环境/测试场景下可能重复初始化,建议加 null 判断或使用双重检查。
示例:
立即学习“Java免费学习笔记(深入)”;
@SpringBootApplication
public class MyApp {
public static ApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(MyApp.class, args);
}
}
// 普通工具类(无任何 Spring 注解)
public class HttpHelper {
public static void doRequest() {
RestTemplate restTemplate = MyApp.context.getBean(RestTemplate.class);
// ...
}
}
方式三:传参式获取(最轻量,适合局部、临时场景)
不依赖全局上下文,而是把需要的 Bean 显式传递进普通类的方法或构造函数中。
说明:
- 完全解耦 Spring,利于单元测试和复用;
- 适合逻辑简单、调用链短、Bean 数量少的情况;
- 避免了静态上下文带来的隐藏依赖和生命周期问题。
示例:
立即学习“Java免费学习笔记(深入)”;
public class DataProcessor {
public void process(List<String> data, RestTemplate restTemplate, UserService userService) {
String result = restTemplate.getForObject("...", String.class);
userService.save(result);
}
}
// 在 Spring Bean 中调用:
@Service
public class MyService {
@Autowired private RestTemplate restTemplate;
@Autowired private UserService userService;
public void handle() {
new DataProcessor().process(data, restTemplate, userService); // 显式传入
}
}
不推荐的做法提醒
以下方式存在明显风险,应避免:
-
在非 Spring Bean 中直接 new ApplicationContext(如
new AnnotationConfigApplicationContext(...)):会创建独立容器,与主容器隔离,无法共享单例、AOP、事务等能力; - 滥用 ThreadLocal 存储 ApplicationContext:容易引发内存泄漏,且在异步、线程池场景下不可靠;
- 在工具类中用 static 块 + new ClassPathXmlApplicationContext:硬编码配置路径,破坏 Spring Boot 自动配置机制。
本质上,Spring 的设计哲学是“依赖由容器注入”,强行绕过容器去“取 Bean”,往往意味着架构上可以优化——比如把该普通类改为 Spring Bean,或拆分职责,让真正需要 Spring 特性的部分回归容器管理。

















