Spring 框架
核心技术
IoC 容器
基于注解的容器配置
使用 @Autowired
使用 @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)
如果目标 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
// ...
}
你可以将 @Autowired 应用于具有任意名称和多个参数的方法,如以下示例所示
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
// ...
}
确保你的目标组件(例如,MovieCatalog 或 CustomerPreferenceDao)始终由你用于 @Autowired 注解注入点的类型声明。否则,注入可能会因为运行时出现“未找到类型匹配”错误而失败。
对于通过 XML 定义的 bean 或通过类路径扫描找到的组件类,容器通常会提前知道具体类型。但是,对于 @Bean 工厂方法,你需要确保声明的返回类型具有足够的表达力。对于实现多个接口的组件或可能通过其实现类型引用的组件,请在工厂方法上声明最具体的返回类型(至少与引用你的 bean 的注入点所要求的具体程度相同)。
自注入
@Autowired 也考虑自引用进行注入(即,引用当前正在注入的 bean)。
但请注意,自注入是一种后备机制。对其他组件的常规依赖始终优先。从这个意义上讲,自引用不参与常规的自动装配候选选择,因此尤其永远不是主要的。相反,它们总是以最低优先级结束。
在实践中,你应该只将自引用作为最后手段使用——例如,通过 bean 的事务代理调用同一实例上的其他方法。作为替代方案,在这种情况下,请考虑将受影响的方法分解到单独的委托 bean 中。
另一种替代方案是使用 @Resource,它可以通过其唯一名称获取指向当前 bean 的代理。
尝试在同一 @Configuration 类中注入 @Bean 方法的结果也实际上是一种自引用场景。可以懒惰地在实际需要的方法签名中解析此类引用(而不是配置类中的自动装配字段),或者将受影响的 @Bean 方法声明为 static,从而将它们与包含的配置类实例及其生命周期解耦。否则,此类 bean 只会在回退阶段被考虑,而其他配置类上的匹配 bean 将被选为主要候选(如果可用)。
你还可以通过将 @Autowired 注解添加到期望该类型数组的字段或方法中来指示 Spring 从 ApplicationContext 提供特定类型的所有 bean,如以下示例所示
Java
Kotlin
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
class MovieRecommender {
@Autowired
private lateinit var movieCatalogs: Array
// ...
}
对于类型化集合也适用,如以下示例所示
Java
Kotlin
public class MovieRecommender {
private Set
@Autowired
public void setMovieCatalogs(Set
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Set
// ...
}
如果希望数组或列表中的项目按特定顺序排序,你的目标 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 结合来建模。
即使是类型化的 Map 实例也可以自动装配,只要预期的键类型是 String。映射值都是预期类型的 bean,键是相应的 bean 名称,如以下示例所示
Java
Kotlin
public class MovieRecommender {
private Map
@Autowired
public void setMovieCatalogs(Map
this.movieCatalogs = movieCatalogs;
}
// ...
}
class MovieRecommender {
@Autowired
lateinit var movieCatalogs: Map
// ...
}
默认情况下,当给定注入点没有匹配的候选 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 容器中可以满足最多依赖项的构造函数。如果所有候选者都无法满足,则将使用主/默认构造函数(如果存在)。类似地,如果一个类声明了多个构造函数但没有一个用 @Autowired 注解,则将使用主/默认构造函数(如果存在)。如果一个类一开始只声明一个构造函数,则即使未注解,它也始终会被使用。请注意,注解的构造函数不必是公共的。
或者,你可以通过 Java 的 java.util.Optional 表达特定依赖项的非必需性质,如以下示例所示
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional
...
}
}
你还可以使用参数级别的 @Nullable 注解(任何包中的任何类型——例如,JSpecify 中的 org.jspecify.annotations.Nullable)或仅利用 Kotlin 内置的空安全支持
Java
Kotlin
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
class SimpleMovieLister {
@Autowired
var movieFinder: MovieFinder? = null
// ...
}
你还可以将 @Autowired 用于众所周知的可解析依赖项接口:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher 和 MessageSource。这些接口及其扩展接口,如 ConfigurableApplicationContext 或 ResourcePatternResolver,会自动解析,无需特殊设置。以下示例自动装配一个 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 实现处理。这意味着你不能在自己的 BeanPostProcessor 或 BeanFactoryPostProcessor 类型(如果有)中应用这些注解。
这些类型必须通过使用 XML 或 Spring @Bean 方法明确地“连接”起来。
基于注解的容器配置 使用 @Primary 或 @Fallback 微调基于注解的自动装配
Copyright © 2022 日本世界杯_林高远世界杯 - edenyn.com All Rights Reserved.