对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

使用限定符微调基于注释的自动布线

@Primary是按类型使用自动布线的有效方法,当一个 可以确定主要候选人。当您需要对选择过程进行更多控制时, 您可以使用 Spring 的@Qualifier注解。您可以关联限定符值 使用特定参数,缩小类型匹配集的范围,以便特定 bean 为每个参数选择。在最简单的情况下,这可以是一个简单的描述值,因为 如以下示例所示:spring-doc.cadn.net.cn

public class MovieRecommender {

	@Autowired
	@Qualifier("main")
	private MovieCatalog movieCatalog;

	// ...
}
class MovieRecommender {

	@Autowired
	@Qualifier("main")
	private lateinit var movieCatalog: MovieCatalog

	// ...
}

您还可以指定@Qualifier单个构造函数参数的注释或 方法参数,如以下示例所示:spring-doc.cadn.net.cn

public class MovieRecommender {

	private final MovieCatalog movieCatalog;

	private final CustomerPreferenceDao customerPreferenceDao;

	@Autowired
	public void prepare(@Qualifier("main") 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(@Qualifier("main") movieCatalog: MovieCatalog,
				customerPreferenceDao: CustomerPreferenceDao) {
		this.movieCatalog = movieCatalog
		this.customerPreferenceDao = customerPreferenceDao
	}

	// ...
}

以下示例显示了相应的 bean 定义。spring-doc.cadn.net.cn

<?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">
		<qualifier value="main"/> (1)

		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<qualifier value="action"/> (2)

		<!-- inject any dependencies required by this bean -->
	</bean>

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

</beans>
1 带有main限定符值与构造函数参数连接,该参数 以相同的值限定。
2 带有action限定符值与构造函数参数连接,该参数 以相同的值限定。

对于回退匹配,bean 名称被视为默认限定符值。因此,你 可以使用idmain而不是嵌套限定符元素,前导 以相同的匹配结果。但是,虽然您可以使用此约定来引用 按名称划分的特定豆,@Autowired从根本上讲,是关于类型驱动的注入 可选的语义限定符。这意味着限定符值,即使带有 bean 名称 fallback,在类型匹配集中始终具有缩小的语义。他们没有 在语义上表达对唯一 bean 的引用id.好的限定符值是mainEMEApersistent,表示特定组件的特征 独立于 beanid,如果是匿名 bean,则可以自动生成 定义,例如前面示例中的定义。spring-doc.cadn.net.cn

限定符也适用于类型化集合,如前所述,例如Set<MovieCatalog>.在这种情况下,所有匹配的 bean,根据声明的 限定符,作为集合注入。这意味着限定符不必是 独特。相反,它们构成了过滤标准。例如,您可以定义 倍数MovieCatalog具有相同限定符值“action”的 bean,所有这些都是 注入到Set<MovieCatalog>注释为@Qualifier("action").spring-doc.cadn.net.cn

让限定符值根据目标 Bean 名称进行选择,在类型匹配中 候选人,不需要@Qualifier注解。 如果没有其他分辨率指示器(例如限定符或主标记), 对于非唯一依赖关系情况,Spring 匹配注入点名称 (即字段名称或参数名称)与目标 bean 名称并选择 同名候选者(如果有)(按 Bean 名称或关联别名)。spring-doc.cadn.net.cn

从 6.1 版本开始,这需要-parametersJava 编译器标志。spring-doc.cadn.net.cn

作为按名称注入的替代方案,请考虑 JSR-250@Resource注解 在语义上定义为通过其唯一名称标识特定目标组件, 声明的类型与匹配过程无关。@Autowired宁愿 不同的语义:按类型选择候选 Bean 后,指定的String限定符值仅在这些类型选择的候选项中考虑(例如, 匹配account限定符与标有相同限定符标签的 bean)。spring-doc.cadn.net.cn

对于本身被定义为集合的 bean,Map,或数组类型,@Resource是一个很好的解决方案,通过唯一名称引用特定的集合或数组 bean。 也就是说,从 4.3 开始,您可以匹配 collectionMap,以及数组类型通过 Spring 的@Autowired类型匹配算法,只要元素类型信息 保存在@Bean返回类型签名或集合继承层次结构。 在这种情况下,您可以使用限定符值在相同类型的集合中进行选择, 如上一段所述。spring-doc.cadn.net.cn

从 4.3 开始,@Autowired还考虑注入的自引用(即引用返回到当前注入的 bean)。请注意,自注入是一种后备。对其他组件的常规依赖始终具有优先级。从这个意义上说,自引用不参与常规候选选择,因此位于特别是从不主要。相反,它们总是以最低优先级结束。在实践中,您应该仅将自引用作为最后的手段(例如,对于通过 bean 的事务代理在同一实例上调用其他方法)。在这种情况下,考虑将受影响的方法分解为单独的委托 bean。或者,您可以使用@Resource,它可能会获得返回当前 bean 的代理。spring-doc.cadn.net.cn

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

@Autowired适用于字段、构造函数和多参数方法,允许在参数级别通过限定符注释缩小范围。相比之下,@Resource仅支持具有单个参数的字段和 bean 属性 setter 方法。因此,如果您的注入目标是构造函数或多参数方法,则应坚持使用限定符。spring-doc.cadn.net.cn

您可以创建自己的自定义限定符注释。为此,请定义注释并提供@Qualifier注释,如以下示例所示:spring-doc.cadn.net.cn

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

	String value();
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class Genre(val value: String)

然后,您可以在自动连接的字段和参数上提供自定义限定符,如以下示例所示:spring-doc.cadn.net.cn

public class MovieRecommender {

	@Autowired
	@Genre("Action")
	private MovieCatalog actionCatalog;

	private MovieCatalog comedyCatalog;

	@Autowired
	public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
		this.comedyCatalog = comedyCatalog;
	}

	// ...
}
class MovieRecommender {

	@Autowired
	@Genre("Action")
	private lateinit var actionCatalog: MovieCatalog

	private lateinit var comedyCatalog: MovieCatalog

	@Autowired
	fun setComedyCatalog(@Genre("Comedy") comedyCatalog: MovieCatalog) {
		this.comedyCatalog = comedyCatalog
	}

	// ...
}

接下来,您可以提供候选 Bean 定义的信息。您可以添加<qualifier/>标签作为<bean/>标记,然后指定typevalue以匹配您的自定义限定符注释。该类型与 注解的完全限定类名。或者,如果没有风险,作为一种便利 存在冲突的名称,则可以使用短类名。以下示例 演示了这两种方法:spring-doc.cadn.net.cn

<?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">
		<qualifier type="Genre" value="Action"/>
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<qualifier type="example.Genre" value="Comedy"/>
		<!-- inject any dependencies required by this bean -->
	</bean>

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

</beans>

Classpath Scanning 和 Managed Components 中,您可以看到基于注释的替代方法 以 XML 形式提供限定符元数据。具体而言,请参阅提供带有注释的限定符元数据spring-doc.cadn.net.cn

在某些情况下,使用不带值的注释可能就足够了。这可以是 当注释具有更通用的用途并且可以应用于 几种不同类型的依赖项。例如,您可以提供离线 目录,当没有可用的 Internet 连接时可以搜索。首先,定义 简单注解,如以下示例所示:spring-doc.cadn.net.cn

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class Offline

然后将注释添加到要自动连接的字段或属性中,如 以下示例:spring-doc.cadn.net.cn

public class MovieRecommender {

	@Autowired
	@Offline (1)
	private MovieCatalog offlineCatalog;

	// ...
}
1 这一行将@Offline注解。
class MovieRecommender {

	@Autowired
	@Offline (1)
	private lateinit var offlineCatalog: MovieCatalog

	// ...
}
1 这一行将@Offline注解。

现在 bean 定义只需要一个限定符type,如以下示例所示:spring-doc.cadn.net.cn

<bean class="example.SimpleMovieCatalog">
	<qualifier type="Offline"/> (1)
	<!-- inject any dependencies required by this bean -->
</bean>
1 此元素指定限定符。

您还可以定义自定义限定符注释,这些注释接受 添加或代替简单的value属性。如果多个属性值 然后在要自动连接的字段或参数上指定,Bean 定义必须匹配 所有这些属性值都被视为自动配线候选值。例如, 请考虑以下注释定义:spring-doc.cadn.net.cn

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

	String genre();

	Format format();
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class MovieQualifier(val genre: String, val format: Format)

在这种情况下Format是一个枚举,定义如下:spring-doc.cadn.net.cn

public enum Format {
	VHS, DVD, BLURAY
}
enum class Format {
	VHS, DVD, BLURAY
}

要自动连接的字段使用自定义限定符进行注释,并包含值 对于这两个属性:genreformat,如以下示例所示:spring-doc.cadn.net.cn

public class MovieRecommender {

	@Autowired
	@MovieQualifier(format=Format.VHS, genre="Action")
	private MovieCatalog actionVhsCatalog;

	@Autowired
	@MovieQualifier(format=Format.VHS, genre="Comedy")
	private MovieCatalog comedyVhsCatalog;

	@Autowired
	@MovieQualifier(format=Format.DVD, genre="Action")
	private MovieCatalog actionDvdCatalog;

	@Autowired
	@MovieQualifier(format=Format.BLURAY, genre="Comedy")
	private MovieCatalog comedyBluRayCatalog;

	// ...
}
class MovieRecommender {

	@Autowired
	@MovieQualifier(format = Format.VHS, genre = "Action")
	private lateinit var actionVhsCatalog: MovieCatalog

	@Autowired
	@MovieQualifier(format = Format.VHS, genre = "Comedy")
	private lateinit var comedyVhsCatalog: MovieCatalog

	@Autowired
	@MovieQualifier(format = Format.DVD, genre = "Action")
	private lateinit var actionDvdCatalog: MovieCatalog

	@Autowired
	@MovieQualifier(format = Format.BLURAY, genre = "Comedy")
	private lateinit var comedyBluRayCatalog: MovieCatalog

	// ...
}

最后,bean 定义应包含匹配的限定符值。这个例子 还演示了您可以使用 bean 元属性而不是<qualifier/>元素。如果可用,则<qualifier/>元素及其属性 优先级,但自动布线机制会回退到<meta/>标记,如果不存在此类限定符,则在 以下示例:spring-doc.cadn.net.cn

<?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">
		<qualifier type="MovieQualifier">
			<attribute key="format" value="VHS"/>
			<attribute key="genre" value="Action"/>
		</qualifier>
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<qualifier type="MovieQualifier">
			<attribute key="format" value="VHS"/>
			<attribute key="genre" value="Comedy"/>
		</qualifier>
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<meta key="format" value="DVD"/>
		<meta key="genre" value="Action"/>
		<!-- inject any dependencies required by this bean -->
	</bean>

	<bean class="example.SimpleMovieCatalog">
		<meta key="format" value="BLURAY"/>
		<meta key="genre" value="Comedy"/>
		<!-- inject any dependencies required by this bean -->
	</bean>

</beans>