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

从 4.3 开始,@Autowired 还考虑自引用进行注入(即,引用回当前正在注入的 Bean)。请注意,自注入是一种后备方案。在实践中,您应该仅在万不得已时使用自引用(例如,通过 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相结合来建模。

只要预期的键类型为String,即使是类型化的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 表示相应的属性对于自动装配是可选的,如果无法自动装配,则该属性将被忽略。这允许属性分配默认值,这些值可以通过依赖项注入选择性地覆盖。

注入的构造函数和工厂方法参数是一个特殊情况,因为 @Autowired 中的 required 属性具有稍微不同的含义,这是由于 Spring 的构造函数解析算法可能会处理多个构造函数。构造函数和工厂方法参数默认情况下实际上是必需的,但在单构造函数场景中有一些特殊规则,例如多元素注入点(数组、集合、映射)在没有匹配的 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) {
		...
	}
}

从 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

	// ...
}

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