跳到主要内容

使用 @Autowired

ChatGPT-4o 中英对照 Using @Autowired Using @Autowired

备注

JSR 330 的 @Inject 注解可以在本节包含的示例中替代 Spring 的 @Autowired 注解。更多详情请参见此处

您可以将 @Autowired 注解应用于构造函数,如以下示例所示:

public class MovieRecommender {

private final CustomerPreferenceDao customerPreferenceDao;

@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}

// ...
}
java
备注

从 Spring Framework 4.3 开始,如果目标 bean 一开始只定义了一个构造函数,那么在这样的构造函数上不再需要 @Autowired 注解。然而,如果有多个构造函数可用且没有主要/默认构造函数,则至少必须在其中一个构造函数上标注 @Autowired,以指示容器使用哪个构造函数。详情请参见关于构造函数解析的讨论。

您也可以将 @Autowired 注解应用于传统的 setter 方法,如下例所示:

public class SimpleMovieLister {

private MovieFinder movieFinder;

@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}

// ...
}
java

您还可以将注解应用于具有任意名称和多个参数的方法,如以下示例所示:

public class MovieRecommender {

private MovieCatalog movieCatalog;

private CustomerPreferenceDao customerPreferenceDao;

@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}

// ...
}
java

你可以将 @Autowired 应用于字段,甚至可以与构造函数混合使用,如下例所示:

public class MovieRecommender {

private final CustomerPreferenceDao customerPreferenceDao;

@Autowired
private MovieCatalog movieCatalog;

@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}

// ...
}
java
提示

确保你的目标组件(例如,MovieCatalogCustomerPreferenceDao)在 @Autowired 注解的注入点中使用的类型声明一致。否则,注入可能会在运行时由于“未找到类型匹配”错误而失败。

对于通过类路径扫描找到的 XML 定义的 bean 或组件类,容器通常会提前知道具体类型。然而,对于 @Bean 工厂方法,你需要确保声明的返回类型足够具有表现力。对于实现多个接口的组件或可能通过其实现类型引用的组件,考虑在你的工厂方法上声明最具体的返回类型(至少要与引用你的 bean 的注入点所需的类型一样具体)。

自引用注入

@Autowired 也会考虑自引用进行注入(即,引用回当前注入的 bean)。

但是请注意,自引用注入是一种后备机制。对其他组件的常规依赖总是优先的。从这个意义上说,自引用不参与常规自动装配候选项的选择,因此特别是从来不是主要的。相反,它们总是以最低优先级结束。

实际上,您应该仅在最后手段时使用自引用——例如,通过 bean 的事务代理调用同一实例上的其他方法。作为替代方案,在这种情况下,可以考虑将受影响的方法提取到一个单独的委托 bean 中。

另一个替代方法是使用 @Resource,它可以通过其唯一名称获得返回到当前 bean 的代理。

备注

尝试在同一个 @Configuration 类中注入 @Bean 方法的结果实际上也是一个自引用场景。要么在实际需要的地方在方法签名中延迟解析此类引用(而不是在配置类中的自动装配字段),要么将受影响的 @Bean 方法声明为 static,将它们与包含的配置类实例及其生命周期解耦。否则,此类 bean 仅在后备阶段被考虑,而其他配置类上的匹配 bean 则被选为主要候选项(如果可用)。

您还可以通过将 @Autowired 注解添加到期望该类型数组的字段或方法上,指示 Spring 从 ApplicationContext 提供特定类型的所有 bean,如以下示例所示:

public class MovieRecommender {

@Autowired
private MovieCatalog[] movieCatalogs;

// ...
}
java

同样的道理也适用于类型化集合,如以下示例所示:

public class MovieRecommender {

private Set<MovieCatalog> movieCatalogs;

@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}

// ...
}
java
提示

你的目标 bean 可以实现 org.springframework.core.Ordered 接口,或者使用 @Order 或标准的 @Priority 注解,如果你希望数组或列表中的项目按特定顺序排序。否则,它们的顺序将遵循容器中相应目标 bean 定义的注册顺序。

你可以在目标类级别和 @Bean 方法上声明 @Order 注解,可能用于单个 bean 定义(在使用相同 bean 类的多个定义的情况下)。@Order 值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,这是由依赖关系和 @DependsOn 声明决定的一个独立问题。

请注意,配置类上的 @Order 注解仅影响启动时整个配置类集合中的评估顺序。这样的配置级别顺序值完全不影响所包含的 @Bean 方法。对于 bean 级别的排序,每个 @Bean 方法需要有自己的 @Order 注解,该注解适用于特定 bean 类型的一组多个匹配项(由工厂方法返回)。

请注意,标准的 jakarta.annotation.Priority 注解在 @Bean 级别不可用,因为它不能在方法上声明。它的语义可以通过 @Order 值与 @Primary 结合在每种类型的单个 bean 上进行建模。

即使是类型化的 Map 实例也可以自动装配,只要预期的键类型是 String。映射值包含所有预期类型的 bean,而键包含相应的 bean 名称,如以下示例所示:

public class MovieRecommender {

private Map<String, MovieCatalog> movieCatalogs;

@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}

// ...
}
java

默认情况下,当没有可用的候选 bean 匹配给定的注入点时,自动装配会失败。在声明的数组、集合或映射的情况下,至少需要一个匹配的元素。

默认行为是将带注解的方法和字段视为必需的依赖项。您可以更改此行为,如以下示例所示,通过将其标记为非必需(即,通过将 @Autowired 中的 required 属性设置为 false),使框架能够跳过一个无法满足的注入点:

public class SimpleMovieLister {

private MovieFinder movieFinder;

@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}

// ...
}
java
备注

如果某个非必需的方法的依赖项(或者在有多个参数的情况下,其某个依赖项)不可用,该方法将根本不会被调用。在这种情况下,非必需字段将根本不会被填充,保持其默认值。

换句话说,将 required 属性设置为 false 表示对应的属性在自动装配时是可选的,如果无法自动装配,该属性将被忽略。这允许属性被分配默认值,并可以通过依赖注入可选地覆盖这些默认值。

注入的构造函数和工厂方法参数是一个特殊情况,因为 @Autowired 中的 required 属性由于 Spring 的构造函数解析算法可能会处理多个构造函数,因此具有稍微不同的含义。构造函数和工厂方法参数默认情况下实际上是必需的,但在单一构造函数场景中有一些特殊规则,例如多元素注入点(数组、集合、映射)在没有匹配的 bean 可用时解析为空实例。这允许一种常见的实现模式,其中所有依赖项都可以在一个独特的多参数构造函数中声明——例如,声明为一个没有 @Autowired 注解的公共构造函数。

备注

任何给定 bean 类的构造函数中只能有一个声明 @Autowiredrequired 属性设置为 true,这表示当用作 Spring bean 时需要自动装配的构造函数。因此,如果 required 属性保持其默认值 true,则只能有一个构造函数可以用 @Autowired 注解。如果多个构造函数声明了该注解,则它们都必须声明 required=false 才能被视为自动装配的候选者(类似于 XML 中的 autowire=constructor)。将选择依赖项数量最多且可以通过 Spring 容器中的匹配 bean 满足的构造函数。如果没有候选者可以满足,则将使用主要/默认构造函数(如果存在)。同样,如果一个类声明了多个构造函数,但没有一个用 @Autowired 注解,则将使用主要/默认构造函数(如果存在)。如果一个类一开始只声明了一个构造函数,它将始终被使用,即使没有注解。请注意,带注解的构造函数不一定是公共的。

或者,您可以通过 Java 8 的 java.util.Optional 来表示特定依赖项的非必需性质,如以下示例所示:

public class SimpleMovieLister {

@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
java

你也可以使用 @Nullable 注解(任何包中的任何类型,例如,JSR-305 中的 javax.annotation.Nullable)或直接利用 Kotlin 内置的空安全支持:

public class SimpleMovieLister {

@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
java

您还可以对众所周知的可解析依赖项接口使用 @AutowiredBeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。这些接口及其扩展接口,例如 ConfigurableApplicationContextResourcePatternResolver,会自动解析,无需特殊设置。以下示例自动装配一个 ApplicationContext 对象:

public class MovieRecommender {

@Autowired
private ApplicationContext context;

public MovieRecommender() {
}

// ...
}
java
备注

@Autowired@Inject@Value@Resource 注解由 Spring 的 BeanPostProcessor 实现处理。这意味着你不能在你自己的 BeanPostProcessorBeanFactoryPostProcessor 类型中应用这些注解(如果有的话)。这些类型必须通过使用 XML 或 Spring 的 @Bean 方法显式地进行“装配”。