spring 应用中非容器管理类获取 bean 的推荐方式有三种:一是实现 applicationcontextaware 接口,通过静态工具类获取;二是使用 @configurable + aspectj 实现编译期织入;三是通过构造或 setter 方法显式注入。不推荐手动创建新 applicationcontext。

在 Spring 应用中,如果某个类不是由 Spring 容器管理(比如通过 new 手动创建、或由第三方框架实例化),它就无法直接使用 @Autowired 注入 Bean。但仍有几种安全、规范的方式让它获取 Spring 管理的 Bean 实例。
方式一:实现 ApplicationContextAware 接口(推荐)
这是 Spring 官方推荐的非侵入式方式,适用于需要在工具类、静态方法或非托管对象中访问 Bean 的场景。
步骤如下:
- 定义一个全局持有的
ApplicationContext工具类(单例) - 该工具类实现
ApplicationContextAware,Spring 会自动注入上下文 - 提供静态方法如
getBean(Class<t>)</t>或getBean(String)
示例:
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
public static
return context.getBean(clazz);
}
}
方式二:使用 @Configurable + AspectJ(适合实体类)
当需要让普通 new 出来的对象(如 JPA 实体、DTO)也能被 Spring 自动装配时,可启用 Spring 的编译期织入支持。
前提条件:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 添加
spring-aspects依赖 - 开启
@EnableSpringConfigured(Java Config)或配置<spring-configured></spring-configured>(XML) - 类上标注
@Configurable,并确保构建过程启用 AspectJ 编译(如 Maven 的aspectj-maven-plugin)
注意:这种方式对构建流程有要求,适合特定场景(如领域对象需依赖 Service),不建议泛用。
方式三:通过构造/Setter 注入传递 Bean(最简洁)
如果非 Spring 类是由你可控的代码创建(比如工厂方法、监听器初始化逻辑),最佳实践是显式传入所需 Bean,而非绕路查上下文。
例如:
public class MyTask {private final UserService userService;
public MyTask(UserService userService) {
this.userService = userService;
}
public void execute() {
userService.doSomething();
}
}
// 在 Spring 管理的类中创建:
@Service
public class TaskLauncher {
@Autowired private UserService userService;
public void start() {
new MyTask(userService).execute(); // 直接传入
}
}
不推荐的方式:手动 new AnnotationConfigApplicationContext
不要在运行中的 Spring 应用里重新创建一个独立的上下文来“查找” Bean —— 这会导致重复加载、生命周期错乱、事务失效等问题。
常见误区:
- 在工具类里写
new AnnotationConfigApplicationContext(...) - 试图从 ThreadLocal 或静态变量“偷”已存在的上下文(未初始化或线程不安全)
这类做法破坏了 Spring 容器的统一性,极易引发隐性 Bug。










