跳到主要内容
版本:7.0.3

使用 @Autowired

Hunyuan 7b 中英对照 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;
}

// ...
}
提示

如果目标Bean只定义了一个构造函数,那么在该构造函数上使用@Autowired注解是不必要的。然而,如果存在多个构造函数且没有默认构造函数,那么至少需要有一个构造函数被标注为@Autowired,以便容器知道应该使用哪一个构造函数。详情请参阅构造函数解析的相关讨论。

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

public class SimpleMovieLister {

private MovieFinder movieFinder;

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

// ...
}

如以下示例所示,你可以将@Autowired应用到具有任意名称和多个参数的方法上:

public class MovieRecommender {

private MovieCatalog movieCatalog;

private CustomerPreferenceDao customerPreferenceDao;

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

// ...
}

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

public class MovieRecommender {

private final CustomerPreferenceDao customerPreferenceDao;

@Autowired
private MovieCatalog movieCatalog;

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

// ...
}
提示

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

对于通过类路径扫描找到的 XML 定义的 Bean 或组件类,容器通常可以提前知道具体的类型。但是,对于 @Bean 工厂方法,你需要确保声明的返回类型足够具体。对于实现多个接口的组件,或者可能通过其实现类型来引用的组件,在工厂方法中声明最具体的返回类型(至少要与引用该 Bean 的注入点所要求的类型一样具体)。

自注入

@Autowired 也会考虑自引用进行注入(即,引用当前被注入的 Bean 本身)。

然而,请注意,自注入是一种后备机制。对其他组件的常规依赖总是具有优先级。从这个意义上说,自引用不会参与常规自动注入候选者的选择,因此它们从来都不是首选。相反,它们的优先级总是最低的。

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

另一种选择是使用 @Resource,它可以通过当前 Bean 的唯一名称获取一个返回到该 Bean 的代理。

备注

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

你也可以通过向期望该类型数组的字段或方法添加@Autowired注解,来指示Spring从ApplicationContext中提供所有该类型的Bean,如下例所示:

public class MovieRecommender {

@Autowired
private MovieCatalog[] movieCatalogs;

// ...
}

同样的规则也适用于类型化的集合(typed collections),如下例所示:

public class MovieRecommender {

private Set<MovieCatalog> movieCatalogs;

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

// ...
}
提示

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

你可以在目标类级别以及 @Bean 方法上声明 @Order 注解,甚至可以针对单个 Bean 定义进行设置(当存在多个使用相同 Bean 类的定义时)。@Order 的值可能会影响注入点的优先级,但请注意,它们不会影响单例的启动顺序,后者的确定因素是依赖关系和 @DependsOn 声明。

需要注意的是,配置类上的 @Order 注解仅会影响启动时所有配置类之间的评估顺序。这种配置级别的顺序值对其中的 @Bean 方法毫无影响。对于 Bean 级别的排序,每个 @Bean 方法都需要有自己的 @Order 注解,该注解将在工厂方法返回的多个匹配结果中针对特定 Bean 类型起作用。

需要注意的是,标准的 jakarta.annotation.Priority 注解不能在 @Bean 级别使用,因为它不能用于方法上。其语义可以通过在单个 Bean 上结合使用 @Order@Primary 来实现。

即使类型为Map的实例,只要其键的预期类型是String,也可以实现自动连线(autowiring)。映射的值都是预期类型的bean,而键则是对应的bean名称,如下例所示:

public class MovieRecommender {

private Map<String, MovieCatalog> movieCatalogs;

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

// ...
}

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

默认行为是将带有注解的方法和字段视为表示必需的依赖项。你可以像下面的例子所示来更改这种行为,通过将某个注入点标记为非必需(即,将@Autowired中的required属性设置为false),使框架能够跳过这个无法满足条件的注入点:

public class SimpleMovieLister {

private MovieFinder movieFinder;

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

// ...
}
备注

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

换句话说,将required属性设置为false表示该属性在自动配置(autowiring)过程中是可选的;如果无法进行自动配置,该属性将会被忽略。这样就可以为属性设置默认值,并且这些默认值可以通过依赖注入(dependency injection)进行选择性覆盖。

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

备注

在任何给定的bean类中,只能有一个构造函数声明@Autowired注解,并且将required属性设置为true,这表示当该构造函数被用作Spring bean时,将会进行自动注入。因此,如果required属性保持其默认值true,则只能有一个构造函数被标注为@Autowired。如果有多个构造函数都标注了该注解,那么它们都必须声明required=false才能被视为自动注入的候选者(类似于XML中的autowire=constructor)。将选择依赖关系能够通过Spring容器中的bean来满足的构造函数数量最多的那个。如果没有任何候选者能够满足依赖关系,则会使用主构造函数/默认构造函数(如果存在的话)。同样地,如果一个类声明了多个构造函数,但其中没有一个标注了@Autowired,那么也会使用主构造函数/默认构造函数(如果存在的话)。如果一个类一开始就只声明了一个构造函数,那么即使该构造函数没有标注@Autowired,也会始终使用它。需要注意的是,被标注的构造函数不一定是public类型的。

或者,你可以通过Java的java.util.Optional来表达某个依赖关系的非必要性,如下例所示:

public class SimpleMovieLister {

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

您还可以使用参数级别的@Nullable注解(任何包中的任何类型的注解——例如,来自JSpecify的org.jspecify.annotations Nullable),或者直接利用Kotlin内置的空值安全支持:

public class SimpleMovieLister {

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

对于那些众所周知、可以自动解析的依赖接口,你也可以使用@AutowiredBeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。这些接口及其扩展接口(如ConfigurableApplicationContextResourcePatternResolver)可以自动被解析,无需任何特殊设置。以下示例会自动注入一个ApplicationContext对象:

public class MovieRecommender {

@Autowired
private ApplicationContext context;

public MovieRecommender() {
}

// ...
}
备注

@Autowired@Inject@Value@Resource 这些注解是由 Spring 的 BeanPostProcessor 实现来处理的。这意味着你不能在自己的 BeanPostProcessorBeanFactoryPostProcessor 类(如果有的话)中应用这些注解。

这些类型必须通过使用 XML 或 Spring 的 @Bean 方法来显式地“连接”起来。