:::info JSR 330 的 @Inject 注解可以代替 Spring 的 @Autowired 注解在本节包含的例子中使用。更多细节请看这里。 :::
你可以对构造函数应用 @Autowired
注解,如下面的例子所示:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
:::info 从 Spring Framework 4.3 开始,如果目标 Bean 一开始就只定义了一个构造函数,那么在这样的构造函数上就不再需要 @Autowired 注解。然而,如果有几个构造函数,而且没有主要/默认构造函数,那么至少有一个构造函数必须用 @Autowired 注解,以便指示容器使用哪一个。详情请参见关于构造函数解析的讨论。 :::
你也可以对传统的 setter 方法应用 @Autowired
注解,如下面的例子所示:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
您还可以将注解应用于具有任意名称和多个参数的方法,如下面的示例所示:
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;
}
// ...
}
:::tips 确保你的目标组件(例如 MovieCatalog 或 CustomerPreferenceDao)由你用于 @Autowired 注解注入点的类型统一声明。否则,注入可能会在运行时由于 「没有找到类型匹配 」的错误而失败。
对于通过 classpath 扫描找到的 XML 定义的 Bean 或组件类,容器通常预先知道具体类型。然而,对于 @Bean 工厂方法,你需要确保声明的返回类型有足够的表现力。对于实现了多个接口的组件或可能被其实现类型引用的组件,考虑在你的工厂方法上声明最具体的返回类型(至少要与引用你的 bean 的注入点所要求的具体类型一样)。 :::
你也可以指示 Spring 从 ApplicationContext 中提供所有特定类型的 Bean,方法是将 @Autowired
注解添加到期望有该类型数组的字段或方法中,如下例所示:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
有泛型类型的集合也是如此,如下面的示例所示:
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
:::tips
你的目标 Bean 可以实现 org.springframework.core.Ordered 接口,如果你想让数组或列表中的项目以特定的顺序排序,可以使用 @Order
或标准的 @Priority
注解。否则,它们的顺序将遵循容器中相应目标 Bean 定义的注册顺序。
你可以在目标类层面和 @Bean
方法上声明 @Order
注解,可能是针对单个 Bean 定义(在使用相同 Bean 类的多个定义的情况下)。@Order
值可以影响注入点的优先级,但要注意它们不会影响单体的启动顺序,这是一个由依赖关系和 @DependsOn
声明决定的问题。
请注意,标准的 javax.annotation.Priority 注解在 @Bean 级别上是不可用的,因为它不能被声明在方法上。它的语义可以通过 @Order 值与 @Primary 在每个类型的单个 Bean 上的组合来建模。 :::
即使是类型化的 Map 实例也可以被自动连接,只要预期的键类型是 String。Map 的值包含所有预期类型的 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;
}
// ...
}
如果一个非必需的方法的依赖项(或者它的一个依赖项,在多个参数的情况下)不可用,那么它就根本不会被调用。在这种情况下,根本不会填充非必需字段,保留其默认值。
注入的构造函数和工厂方法参数是一种特殊情况,因为由于 Spring 的构造函数解析算法可能会处理多个构造函数,所以 @Autowired
中的 required 属性有一些不同的含义。构造函数和工厂方法参数实际上是默认需要的,但在单构造函数的情况下有一些特殊的规则,比如多元素注入点(数组、集合、Map)如果没有匹配的 Bean,则解析为空实例。这允许一种常见的实现模式,即所有的依赖关系都可以在一个独特的多参数构造函数中声明—例如,声明为一个没有 @Autowired
注解的单一公共构造函数。
:::tips 任何给定的 Bean 类中只有一个构造函数可以声明 @Autowired,并将 required 属性设置为 true,表示该构造函数作为 Spring Bean 使用时要自动连接。因此,如果 required 属性的默认值为 true,那么只有一个构造函数可以用 @Autowired 来注解。如果有多个构造函数声明该注解,它们都必须声明required=false,才能被视为自动连接的候选者(类似于 XML 中的 autowire=constructor)。具有最大数量的依赖关系的构造函数将被选中,这些依赖关系可以通过 Spring 容器中的匹配 Bean 来满足。如果没有一个候选者可以被满足,那么将使用一个主要的/默认的构造函数(如果存在的话)。同样地,如果一个类声明了多个构造函数,但没有一个是用 @Autowired 注解的,那么将使用一个主要/默认构造函数(如果存在的话)。如果一个类一开始只声明了一个构造函数,那么即使没有注释,它也会被使用。请注意,被注解的构造函数不一定是公共的。
建议使用 @Autowired 的 required 属性,而不是 setter 方法上被废弃的 @Required 注解。将 required 属性设置为 false 表示该属性对于自动连接的目的不是必需的,如果该属性不能被自动连接,则会被忽略。另一方面,@Required 更强大,因为它强制要求通过容器支持的任何方式来设置该属性,如果没有定义值,就会引发相应的异常。 :::
另外,你可以通过 Java 8 的 java.util.Optional
来表达特定依赖的非必须性质,正如下面的例子所示。
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
从 Spring Framework 5.0 开始,你也可以使用 @Nullable
注解(任何包中的任何类型—例如 JSR-305中的 javax.annotation.Nullable
)或者直接利用 Kotlin 内置的 null-safety 支持。
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
你也可以对那些众所周知的可解析依赖关系的接口使用 @Autowired
。BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher 和 MessageSource。这些接口和它们的扩展接口,如 ConfigurableApplicationContext 或 ResourcePatternResolver,将被自动解析,不需要特别的设置。下面的例子自动连接了一个 ApplicationContext 对象。
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
:::tips
@Autowired
、@Inject
、@Value
和 @Resource
注解是由 Spring BeanPostProcessor 实现处理的。这意味着你不能在你自己的 BeanPostProcessor 或 BeanFactoryPostProcessor 类型(如果有的话)中应用这些注解。这些类型必须通过使用 XML 或 Spring @Bean 方法明确地 「连接 」 起来。
:::