使用 @Autowired
@Autowired
在本节包含的示例中,可以使用JSR 330的@Inject注解来替代Spring的@Autowired注解。更多详细信息请参阅此处。
如以下示例所示,您可以将 @Autowired 注解应用于构造函数:
- Java
- Kotlin
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao)
如果目标Bean只定义了一个构造函数,那么在该构造函数上使用@Autowired注解是不必要的。然而,如果存在多个构造函数且没有默认构造函数,那么至少需要有一个构造函数被标注为@Autowired,以便容器知道应该使用哪一个构造函数。详情请参阅构造函数解析的相关讨论。
如以下示例所示,您可以将@Autowired注解应用于传统的setter方法:
- Java
- Kotlin
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
class SimpleMovieLister {
@set:Autowired
lateinit var movieFinder: MovieFinder
// ...
}
如以下示例所示,你可以将@Autowired应用到具有任意名称和多个参数的方法上:
- Java
- Kotlin
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender {
private lateinit var movieCatalog: MovieCatalog
private lateinit var customerPreferenceDao: CustomerPreferenceDao
@Autowired
fun prepare(movieCatalog: MovieCatalog,
customerPreferenceDao: CustomerPreferenceDao) {
this.movieCatalog = movieCatalog
this.customerPreferenceDao = customerPreferenceDao
}
// ...
}
你也可以将@Autowired应用于字段上,甚至可以将其与构造函数结合使用,如以下示例所示:
- Java
- Kotlin
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender @Autowired constructor(
private val customerPreferenceDao: CustomerPreferenceDao) {
@Autowired
private lateinit var movieCatalog: MovieCatalog
// ...
}
请确保你的目标组件(例如 MovieCatalog 或 CustomerPreferenceDao)使用的类型与你在 @Autowired 注解的注入点所指定的类型一致。否则,由于运行时出现“未找到匹配类型”的错误,注入可能会失败。
对于通过类路径扫描找到的 XML 定义的 Bean 或组件类,容器通常可以提前知道具体的类型。但是,对于 @Bean 工厂方法,你需要确保声明的返回类型足够具体。对于实现多个接口的组件,或者可能通过其实现类型来引用的组件,在工厂方法中声明最具体的返回类型(至少要与引用该 Bean 的注入点所要求的类型一样具体)。
你也可以通过向期望该类型数组的字段或方法添加@Autowired注解,来指示Spring从ApplicationContext中提供所有该类型的Bean,如下例所示:
- Java
- Kotlin
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
class MovieRecommender {
@Autowired
private lateinit var movieCatalogs: Array<MovieCatalog>
// ...
}
同样的规则也适用于类型化的集合(typed collections),如下例所示:
- Java
- Kotlin
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Set<MovieCatalog>
// ...
}
如果希望数组或列表中的元素按特定顺序排列,目标 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名称,如下例所示:
- Java
- Kotlin
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Map<String, MovieCatalog>
// ...
}
默认情况下,当给定的注入点没有匹配的候选bean时,自动绑定会失败。对于声明的数组、集合或映射(map),至少需要有一个匹配的元素。
默认行为是将带有注解的方法和字段视为表示必需的依赖项。你可以像下面的例子所示来更改这种行为,通过将某个注入点标记为非必需(即,将@Autowired中的required属性设置为false),使框架能够跳过这个无法满足条件的注入点:
- Java
- Kotlin
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
class SimpleMovieLister {
@Autowired(required = false)
var movieFinder: MovieFinder? = null
// ...
}
如果一个非必需方法的依赖项(或者在有多个参数的情况下,其某个依赖项)不可用,那么该方法将根本不会被调用。在这种情况下,非必需字段也不会被赋值,而是保留其默认值。
换句话说,将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内置的空值安全支持:
- Java
- Kotlin
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
class SimpleMovieLister {
@Autowired
var movieFinder: MovieFinder? = null
// ...
}
对于那些众所周知、可以自动解析的依赖接口,你也可以使用@Autowired:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher和MessageSource。这些接口及其扩展接口(如ConfigurableApplicationContext或ResourcePatternResolver)可以自动被解析,无需任何特殊设置。以下示例会自动注入一个ApplicationContext对象:
- Java
- Kotlin
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var context: ApplicationContext
// ...
}
@Autowired、@Inject、@Value 和 @Resource 这些注解是由 Spring 的 BeanPostProcessor 实现来处理的。这意味着你不能在自己的 BeanPostProcessor 或 BeanFactoryPostProcessor 类(如果有的话)中应用这些注解。
这些类型必须通过使用 XML 或 Spring 的 @Bean 方法来显式地“连接”起来。