Spring @Autowired解析
一、@Autowired 是什么?
- @Autowired(自动注入)是 Spring Framework 用来完成 Dependency Injection(依赖注入,缩写 DI)的一种注解方式。
- 它可以标注在 构造器(constructor)、字段(field)、Setter 方法(setter method)以及普通 方法(method)上,让 Spring 容器自动把合适的 Bean “wire up”(连线/装配)到你的目标组件中。
英文小贴士
- Dependency Injection (DI):依赖注入
- Autowiring:自动装配
- Bean:Spring 管理的对象
二、@Autowired 的装配时机
-
扫描组件(Component Scan)
- Spring 启动时根据
@Component
、@Service
、@Controller
、@Repository
等注解,或你在@Configuration
中声明的@Bean
方法,扫描并实例化所有 BeanDefinition。
- Spring 启动时根据
-
实例化 Bean
- 根据 BeanDefinition 调用构造器
new
出 Bean 对象。
- 根据 BeanDefinition 调用构造器
-
依赖注入阶段(Dependency Injection Phase)
- Spring 会扫描 Bean 类中标记了
@Autowired
的点,然后按照一定的 解析算法(resolution algorithm)查找容器中匹配的 Bean,完成赋值或调用。
- Spring 会扫描 Bean 类中标记了
-
初始化后处理
- 在
@PostConstruct
、InitializingBean.afterPropertiesSet()
、自定义init-method
之前与之后,还有BeanPostProcessor
拦截点,但与@Autowired
无关。
- 在
三、@Autowired 的应用场景
3.1 构造器注入(Constructor Injection)
@Service
public class OrderService {private final PaymentService paymentService;// Spring 容器会识别这个构造器,并把 PaymentService Bean 注入进来@Autowired public OrderService(PaymentService paymentService) {this.paymentService = paymentService;}// ...
}
-
优点
- 强制依赖:如果没有对应的 Bean,容器启动失败,fail fast(快速失败)。
- 适合与
final
字段配合,使依赖不可变。 - 有助于编写单元测试(可通过构造器手动传入 mock 对象)。
-
注意
- 从 Spring 4.3+ 开始,如果只有一个构造器,可以省略
@Autowired
,容器也会自动注入。
- 从 Spring 4.3+ 开始,如果只有一个构造器,可以省略
3.2 字段注入(Field Injection)
@Component
public class NotificationService {@Autowiredprivate EmailSender emailSender;// ...
}
-
优点:写法简洁,代码量少。
-
缺点:
- 不利于单元测试(无法通过构造器、setter 方式注入 mock)。
- 违反 Inversion of Control 原则(测试时不易替换依赖)。
一般建议开发中 尽量少用,学习和快速原型可以用。
3.3 Setter 注入(Setter Injection)
@Component
public class ReportService {private ReportGenerator generator;@Autowiredpublic void setReportGenerator(ReportGenerator generator) {this.generator = generator;}// ...
}
-
优点
- 依赖可选:可以不必在构造时提供,通过
required=false
实现可选注入(见下节)。 - 适合有多个可选依赖的场景。
- 依赖可选:可以不必在构造时提供,通过
-
注意
- Setter 方法不能是
private
,需要至少public
或protected
。
- Setter 方法不能是
3.4 任意方法注入
Spring 也允许把 @Autowired
标注在任意普通方法上,参数会自动注入:
@Component
public class StartupRunner {private final List<Initializer> initializers;@Autowiredpublic void configure(List<Initializer> initializers, Environment env) {this.initializers = initializers;// ... 使用 env}
}
四、@Autowired 的高级属性
4.1 required:控制是否必须注入
默认情况下,@Autowired(required = true)
,表示 必须 找到匹配 Bean,否则容器启动失败。
@Autowired(required = false)
private AuditService auditService;
- 当
required=false
,如果容器中没有对应的 Bean,则注入null
,不报错。适合可选依赖场景。
4.2 @Qualifier:细化装配
当容器中有多个类型相同的 Bean,Spring 无法决定注入哪一个,就会报 NoUniqueBeanDefinitionException。这时可以配合 @Qualifier
:
@Service
public class PaymentService {@Autowired@Qualifier("creditCardProcessor")private PaymentProcessor processor;// ...
}@Component("creditCardProcessor")
public class CreditCardProcessor implements PaymentProcessor { … }@Component("paypalProcessor")
public class PayPalProcessor implements PaymentProcessor { … }
@Qualifier("beanName")
指定注入的具体 Bean 名称。
4.3 @Primary:优先 Bean
也可以在某个 Bean 的定义上标记 @Primary
,让它在类型匹配冲突时具有更高优先级:
@Component
@Primary
public class DefaultPaymentProcessor implements PaymentProcessor { … }
如果同时存在 @Primary
与 @Qualifier
,Spring 会先根据 @Qualifier
精确匹配,再退而求其次使用 @Primary
。
五、集合与可空注入
5.1 注入集合(List/Set/Map)
当某个类型有多个 Bean 时,可以注入一个集合:
@Component
public class TaskRunner {@Autowiredprivate List<Task> tasks; // 注入所有实现了 Task 接口的 Bean,按注册顺序@Autowiredprivate Map<String, Task> taskMap; // key = beanName, value = 对应 Task Bean
}
- Spring 会自动收集同类型 Bean 并注入集合,方便批量处理。
5.2 使用 Optional
在 Spring 5 及以上,你也可以用 Java 8 的 Optional<T>
做可选注入:
@Autowired
private Optional<NotificationService> notificationService;
- 如果容器中存在,就
Optional.of(bean)
;否则Optional.empty()
。
六、解析顺序与原理
- 按类型(byType) 匹配:先在容器中查找与依赖类型完全一致的 Bean。
- 按名称(byName) 匹配:当有多个类型相同的 Bean 时,会尝试根据属性名(或
@Qualifier
指定的名称)匹配 Bean 名称。 - @Primary:如果有
@Primary
标记,优先注入该 Bean。 - @Priority(Java 标准):也可用 JSR-250 的
@Priority
,需配合@Priority
注解一起使用。
上述过程由 AutowiredAnnotationBeanPostProcessor
(实现了 BeanPostProcessor
)完成,它在 postProcessProperties 阶段拦截,每个标有 @Autowired
的注入点都会调用反射来设置属性或调用构造器/方法。
七、常见误区与调试
-
在非 Spring 管理的类上使用 @Autowired 不生效
- 只有 Spring 容器管理的 Bean(通过
@Component
、@Service
、@Configuration
、@Bean
等方式注册)才能自动装配。
- 只有 Spring 容器管理的 Bean(通过
-
混用 XML 和 注解
- 如果同时在 XML 中声明了同一 Bean,可能导致覆盖或冲突,要注意 BeanDefinition 的加载顺序。
-
循环依赖
- 对于 单例 Bean,Spring 支持构造器循环依赖,但只在 setter/field 注入场景下;构造器注入的循环依赖会抛出异常。
-
调试技巧
-
在
application.properties
中开启调试日志:logging.level.org.springframework.beans=DEBUG
-
观察
AutowiredAnnotationBeanPostProcessor
输出的信息,快速定位注入失败或重复。
-
八、小结
- @Autowired 是 Spring 中最常用的依赖注入注解,支持构造器、字段、setter 及任意方法注入。
- 可以通过
required=false
、@Qualifier
、@Primary
、Optional<T>
、集合注入等手段实现更灵活的装配策略。 - 背后由 AutowiredAnnotationBeanPostProcessor 驱动,遵循 byType→byName→@Primary 的解析规则。
- 合理选择注入方式(推荐构造器注入),结合 单元测试、可选依赖 和 集合注入,能让你的 Spring 应用更健壮、可维护。