使用@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将被选择为主候选者(如果可用)。

您还可以指示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定义的注册顺序。

您可以将@Order注解声明在目标类级别和@Bean方法上,可能用于单个Bean定义(对于使用相同Bean类的多个定义)。@Order值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,这是一个由依赖关系和@DependsOn声明确定的正交问题。

请注意,配置类上的标准@Order注解只会影响启动时整个配置类集合内的评估顺序。这种配置级别的顺序值根本不会影响包含的@Bean方法。对于Bean级别的排序,每个@Bean方法都需要有它自己的@Order注解,该注解适用于特定Bean类型(由工厂方法返回)的多个匹配项集合。

请注意,标准jakarta.annotation.Priority注解在@Bean级别不可用,因为它不能声明在方法上。它的语义可以通过@Order值与每个类型的单个Bean上的@Primary组合来建模。

只要预期的键类型是String,甚至可以自动装配类型化的Map实例。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表示相应的属性对于自动装配而言是可选的,如果无法自动装配该属性,则将忽略该属性。这允许将属性分配默认值,这些值可以通过依赖注入进行可选覆盖。

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

任何给定Bean类的构造函数中,只能声明一个带有required属性设置为true@Autowired,这表示在用作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

	// ...
}

您还可以将@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方法显式“连接”这些类型。