Fine-tuning Annotation-based Autowiring with @Primary or @Fallback

由于按类型自动装配可能导致出现多个候选对象,因此通常需要对选择过程进行更多控制。一种实现此目的的方法是使用 Spring 的 @Primary 注解。@Primary 指示当多个 Bean 是要自动装配到单值依赖项的候选对象时,应优先考虑特定的 Bean。如果候选对象中恰好只有一个主要 Bean,则它将成为自动装配的值。

Because autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring’s @Primary annotation. @Primary indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one primary bean exists among the candidates, it becomes the autowired value.

考虑将 firstMovieCatalog 定义为主要 MovieCatalog 的以下配置:

Consider the following configuration that defines firstMovieCatalog as the primary MovieCatalog:

  • Java

  • Kotlin

@Configuration
public class MovieConfiguration {

	@Bean
	@Primary
	public MovieCatalog firstMovieCatalog() { ... }

	@Bean
	public MovieCatalog secondMovieCatalog() { ... }

	// ...
}
@Configuration
class MovieConfiguration {

	@Bean
	@Primary
	fun firstMovieCatalog(): MovieCatalog { ... }

	@Bean
	fun secondMovieCatalog(): MovieCatalog { ... }

	// ...
}

或者,从 6.2 开始,有一个 @Fallback 注解,用于划分要注入的除常规 Bean 之外的任何 Bean。如果只保留了一个常规 Bean,则它实际上也是主要 Bean:

Alternatively, as of 6.2, there is a @Fallback annotation for demarcating any beans other than the regular ones to be injected. If only one regular bean is left, it is effectively primary as well:

  • Java

  • Kotlin

@Configuration
public class MovieConfiguration {

	@Bean
	public MovieCatalog firstMovieCatalog() { ... }

	@Bean
	@Fallback
	public MovieCatalog secondMovieCatalog() { ... }

	// ...
}
@Configuration
class MovieConfiguration {

	@Bean
	fun firstMovieCatalog(): MovieCatalog { ... }

	@Bean
	@Fallback
	fun secondMovieCatalog(): MovieCatalog { ... }

	// ...
}

使用前述配置的两个变体,以下 MovieRecommender 将使用 firstMovieCatalog 自动装配:

With both variants of the preceding configuration, the following MovieRecommender is autowired with the firstMovieCatalog:

  • Java

  • Kotlin

public class MovieRecommender {

	@Autowired
	private MovieCatalog movieCatalog;

	// ...
}
class MovieRecommender {

	@Autowired
	private lateinit var movieCatalog: MovieCatalog

	// ...
}

相应的 Bean 定义如下:

The corresponding bean definitions follow:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		https://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config/>

	<bean class="example.SimpleMovieCatalog" primary="true">
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>