使用 @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的注入点所需的一样具体)。

您还可以指示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声明确定的正交关注点。

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

即使是带有类型的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时,自动装配会失败。对于声明的数组、集合或映射,至少需要一个匹配元素。

默认行为是将带注解的方法和字段视为指示所需依赖关系。您可以通过以下示例中演示的方式更改此行为,使框架能够跳过一个不可满足的注入点(即,通过将@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使用时要自动装配的构造函数。因此,如果将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

	// ...
}

您还可以为已知可解析依赖项的接口使用@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方法显式地进行“连接”。