下面我将从最佳实践到其他方式,全面地为你介绍如何在 Java 中获取 Spring Bean。

哪种方式最好?
| 场景 | 推荐方式 | 优点 | 缺点 |
|---|---|---|---|
| Spring MVC 控制器、Service、Repository 等组件 | 依赖注入 | 强烈推荐,代码优雅、类型安全、易于测试、符合 IoC 思想。 | 无 |
| 工具类、第三方库、非 Spring 管理的类 | ApplicationContextAware |
非常灵活,可以在任何需要的类中获取 Bean。 | 需要实现接口,增加了与 Spring 的耦合度。 |
| 在静态方法中获取 Bean | @PostConstruct + 实例变量 |
解决了静态方法无法直接注入的问题,保持了类型安全。 | 需要一个额外的非静态实例来持有 Bean。 |
在 main 方法或测试中 |
ApplicationContext |
适合启动时一次性获取,或进行集成测试。 | 手动获取,容易出错,不适合在业务代码中使用。 |
| 旧版 Spring (XML 配置) | BeanFactory / ApplicationContext |
传统方式,兼容性好。 | 代码冗长,类型不安全(需要强制类型转换)。 |
核心结论: 优先使用依赖注入,只有在无法使用依赖注入的特殊情况下,才考虑其他方式。
依赖注入 - 最佳实践
这是最推荐、最优雅的方式,通过在类的字段上使用 @Autowired 或 @Resource 注解,Spring 容器会在初始化时自动为你注入所需的 Bean。
优点:
- 代码简洁:无需手动获取,代码更易读。
- 类型安全:编译器会检查类型,减少运行时错误。
- 易于测试:进行单元测试时,可以轻松地 Mock 依赖的 Bean。
- 低耦合:类本身不需要知道 Bean 是如何创建和管理的。
示例代码:

import org.springframework.stereotype.Service;
import jakarta.annotation.Resource; // 或 org.springframework.beans.factory.annotation.Autowired;
@Service
public class MyService {
// 方式1: @Autowired (按类型注入,如果同类型有多个Bean,再按名称)
@Autowired
private AnotherService anotherService1;
// 方式2: @Resource (按名称注入,默认字段名)
@Resource(name = "anotherService2") // 指定Bean的名称
private AnotherService anotherService2;
public void doSomething() {
anotherService1.performTask();
anotherService2.performTask();
}
}
实现 ApplicationContextAware 接口
当你需要在一个非 Spring 管理的类(例如一个工具类 Utils)中获取 Spring Bean 时,可以实现 ApplicationContextAware 接口,Spring 会在初始化该 Bean 时,将 ApplicationContext 实例注入进来。
优点:
- 非常灵活:可以在任何需要的地方获取任何 Bean。
缺点:
- 增加了耦合度:你的类现在依赖于 Spring 框架的
ApplicationContextAware接口。 - 需要注意线程安全:
ApplicationContext本身是线程安全的,但如果你用它来缓存 Bean,需要自己处理并发问题。
示例代码:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component // 必须被Spring管理才能接收到回调
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 从静态变量ApplicationContext中获取Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量ApplicationContext中获取Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
// ... 其他重载方法
}
使用方式:
public class MyUtilityClass {
public void doWork() {
// 通过工具类获取Bean
MyService myService = SpringContextHolder.getBean(MyService.class);
myService.doSomething();
}
}
在静态方法中获取 Bean
这是一个常见的特殊场景,静态方法属于类级别,而 Spring 的依赖注入是针对实例的,直接在静态方法上使用 @Autowired 是无效的。
解决方案是结合方式二和 @PostConstruct。
示例代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
@Component
public class StaticServiceHolder {
private static MyService myService;
@Autowired
private MyService tempMyService; // 临时实例,用于接收注入
@PostConstruct
public void init() {
// 将注入的实例赋值给静态变量
myService = this.tempMyService;
}
// 提供一个静态方法来获取Bean
public static void performStaticTask() {
if (myService != null) {
myService.doSomething();
}
}
}
使用方式:
public class Main {
public static void main(String[] args) {
// 直接调用静态方法
StaticServiceHolder.performStaticTask();
}
}
在 main 方法或测试中获取
在应用程序入口(如 main 方法)或集成测试中,你可能需要手动获取 ApplicationContext,然后从中获取 Bean。
示例代码 (Spring Boot 应用):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 启动Spring应用,获取ApplicationContext
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
// 手动获取Bean
MyService myService = context.getBean(MyService.class);
myService.doSomething();
// 使用完毕后关闭上下文(可选)
// context.close();
}
}
示例代码 (JUnit 测试):
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
@SpringBootTest
public class MyServiceTest {
// 方式1: 直接在测试类中注入(推荐)
@Autowired
private MyService myService;
@Test
public void testDoSomething() {
myService.doSomething();
}
// 方式2: 从上下文中获取
@Autowired
private ApplicationContext applicationContext;
@Test
public void testGetBeanFromContext() {
MyService anotherService = applicationContext.getBean(MyService.class);
anotherService.doSomething();
}
}
旧版方式 (不推荐)
在 Spring 2.5 之前,或者在使用 XML 配置时,通常会通过 BeanFactory 或 ApplicationContext 的 getBean() 方法来获取。
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
// 旧版XML方式
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
MyService myService = (MyService) factory.getBean("myService"); // 需要强制类型转换,且需要知道Bean名称
这种方式现在基本已被淘汰,因为它冗长、不安全且不易维护。
总结与最佳实践
-
首选依赖注入:在所有 Spring 管理的组件(
@Service,@Controller,@Component,@Repository等)中,始终使用@Autowired或@Resource进行依赖注入,这是最干净、最安全、最符合设计原则的方式。 -
工具类使用
ApplicationContextAware:当你有一个无法使用依赖注入的工具类或辅助类时,实现ApplicationContextAware是一个可行的方案,但请务必谨慎使用,因为它会增加代码与 Spring 的耦合。 -
静态方法使用
@PostConstruct:解决静态方法中获取 Bean 的需求,不要试图在静态字段上直接使用@Autowired。 -
避免在业务代码中手动获取:尽量避免在常规业务逻辑中通过
ApplicationContext手动获取 Bean,这是一种反模式,会使代码变得难以测试和维护,只在启动类、测试或特殊工具类中使用。
