使用 @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)

从 Spring Framework 4.3 开始,如果目标 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

	// ...

}

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

  • 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 的注入点所要求的具体程度一致)。

自注入

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

然而,请注意,自注入是一种回退机制。对其他组件的常规依赖始终具有优先权。从这个意义上讲,自引用不参与常规的自动装配候选选择,因此尤其永远不会成为主要的。相反,它们始终具有最低的优先级。

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

另一种替代方案是使用 @Resource,它可以通过其唯一名称获取当前 bean 的代理。

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

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

  • 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 级别不可用,因为它不能声明在方法上。其语义可以通过结合使用 @Order 值和每个类型单个 bean 上的 @Primary 来建模。

即使是类型化的 Map 实例也可以自动装配,只要期望的键类型是 String。映射的值包含所有期望类型的 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 表示对应的属性对于自动装配目的来说是可选的,并且如果无法自动装配,则该属性将被忽略。这允许为属性分配可以通过依赖注入可选地覆盖的默认值。

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

任何给定 bean 类中只能有一个构造函数声明 @Autowired 并将 required 属性设置为 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) {
		...
	}
}

您还可以使用参数级别的 @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

	// ...
}

Spring Framework 6.2 尚不支持 JSpecify 等类型级别的 @Nullable 注解。您需要升级到 Spring Framework 7.0,在该版本中,框架可以检测类型级别的注解,并在其自身代码库中一致地声明 JSpecify。

您还可以对众所周知的可解析依赖接口使用 @AutowiredBeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。这些接口及其扩展接口(例如 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 方法显式地“连接”起来。