Using @Autowired

可以在本节中包含的示例中使用 JSR 330 的 @Inject 注解替代 Spring 的 @Autowired 注解。参阅 here 了解更多详情。

可以将`@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)

自 Spring Framework 4.3 起,如果目标 Bean 本身仅定义了一个构造函数,就不再需要在该构造函数上使用 "@32" 注解。但是,如果有多个构造函数可用,并且没有主/默认构造函数,那么为了指示容器使用哪个构造函数,必须至少有一个构造函数用 "@33" 注解。请参阅 "@34" 上的讨论内容,了解详细信息。

还可以将`@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

	// ...

}

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

  • 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

	// ...
}

确保目标组件(例如 MovieCatalogCustomerPreferenceDao)是由用于 @Autowired 注解注入点的类型一致声明的。否则,注入可能会在运行时失败,出现“未找到类型匹配项”错误。 对于通过类路径扫描找到的 XML 定义的 Bean 或组件类,容器在前面通常已知具体类型。然而,对于 @Bean 工厂方法,你需要确保已充分明确声明的返回类型。对于实现多个接口的组件或可能被其实现类型引用的组件,考虑在你的工厂方法中声明最具体返回类型(至少像引用 Bean 的注入点所要求的那样具体)。

自 4.3 起,@Autowired 还会考虑注入的自引用(即,引用当前正在注入的 Bean)。请注意,自注入属于备用方案。实际上,你应仅在最后选择时使用自引用(例如,通过 Bean 的事务代理调用同一实例上的其他方法)。在此类场景中,考虑将受影响的方法通过单一委托 Bean 分解出来。

你还可以指示 Spring 从 ApplicationContext 提供特定类型的全部 Bean,方法是将 @Autowired 注解添加到期待该类型数组的字段或方法,如下例所示:

  • Java

  • Kotlin

public class MovieRecommender {

	@Autowired
	private MovieCatalog[] movieCatalogs;

	// ...
}
class MovieRecommender {

	@Autowired
	private lateinit var movieCatalogs: Array<MovieCatalog>

	// ...
}

对于类型化的集合,遵循同样原则,如下例所示:

  • 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 相结合来模拟其语义。

只要期望的键类型为 String,那么即使是类型化的 Map 实例也可以自动注入。地图值包含所有期望类型的 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 可用时,自动注入会失败。如果声明了数组、集合或地图,则至少应有一个匹配元素。

默认行为是将带注释的方法和字段视为指示必需的依赖。你可以更改此行为,如下例所示,允许框架通过将其标记为非必需(即,将 @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 表明相应的属性对于自动注入而言是 可选的,并且如果不能自动注入,该属性将被忽略。这允许属性被分配可通过依赖注入选择性覆盖的默认值。

注入的构造函数和工厂方法参数是一种特殊情况,因为 @Autowired 中的 required 属性具有稍有不同的含义,这是由于 Spring 的可能处理多个构造函数的构造函数解决算法。在单构造函数场景中,构造函数和工厂方法参数实际上默认必需,但有几个特殊规则,例如如果没有可匹配 Bean,那么多元素注入点(数组、集合、地图)解析为空实例。这允许通用实现模式,在该模式中,所有依赖都可以声明在唯一的带多个参数的构造函数中——例如,声明为未带 @Autowired 注解的单个公共构造函数。

只能在一个给定 Bean 类的构造函数中使用 @Autowiredrequired 属性设置为 true,从而指示当用作 Spring Bean 时要自动注入的 the 构造函数。因此,如果将 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) {
		...
	}
}

从 Spring Framework 5.0 起,你还可以使用 @Nullable 注解(任何包中的任何种类的注解——例如 JSR-305 中的 javax.annotation.Nullable)或只是利用 Kotlin 内置的空安全性支持:

  • Java

  • Kotlin

public class SimpleMovieLister {

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

	@Autowired
	var movieFinder: MovieFinder? = null

	// ...
}

你还可以将 @Autowired 用于众所周知并且可以解析的依赖:BeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。这些接口及其扩展接口(例如 ConfigurableApplicationContextResourcePatternResolver)会被自动解析,而不需要任何特殊设置。以下示例自动注入 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 实现处理。这意味着您无法将这些注解应用到您自己的 BeanPostProcessorBeanFactoryPostProcessor 类型(如果有)。这些类型必须通过 XML 或 Spring @Bean 方法显式“连接”。