Spring 核心注解
1、概览
我们可以通过 org.springframework.beans.factory.annotation
和 org.springframework.context.annotation
包中的注解来使用 Spring DI 引擎的功能。
通常把这些注解称为 “Spring 核心注解”。
2、和 DI 相关的注解
2.1、@Autowired
可以在构造函数、Setter 方法或字段注入中使用 @Autowired
注解,Spring 会解析并注入依赖。
构造函数注入:
class Car {
Engine engine;
@Autowired
Car(Engine engine) {
this.engine = engine;
}
}
Setter 注入:
class Car {
Engine engine;
@Autowired
void setEngine(Engine engine) {
this.engine = engine;
}
}
字段注入:
class Car {
@Autowired
Engine engine;
}
@Autowired
有一个名为 required
的 boolean
参数,默认值为 true
。当 Spring 找不到合适的 Bean 进行注入时,它会控制 Spring 的行为。当值为 true
时,会抛出异常,反之则不会。
注意,如果使用构造函数注入,所有构造函数参数都是 必须的 。
从 Spring 4.3 开始,除非声明了至少两个构造函数,否则不需要用 @Autowired
明确注解构造函数。
2.2、@Bean
@Bean
用于标记工厂方法,用于实例化 Spring Bean:
@Bean
Engine engine() {
return new Engine();
}
生成的 Bean
的名称与工厂方法的名称相同。如果想使用不同的名称,可以使用此注解的 name
或 value
参数(value
是 name
的别名):
@Bean("engine")
Engine getEngine() {
return new Engine();
}
注意,所有注解为 @Bean
的方法必须位于 @Configuration
类中。
2.3、@Qualifier
在模糊情况下,使用 @Qualifier
注解与 @Autowired
注解一起,提供想要使用的 Bean 的 ID 或名称。
例如,以下两个 Bean 实现了相同的接口:
class Bike implements Vehicle {}
class Car implements Vehicle {}
如果 Spring 需要注入一个 Vehicle
Bean,最终会出现多个匹配的定义。在这种情况下,可以使用 @Qualifier
注解显式地提供 Bean 的名称。
构造函数注入:
@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}
Setter 注入:
@Autowired
void setVehicle(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}
或者:
@Autowired
@Qualifier("bike")
void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
字段注入:
@Autowired
@Qualifier("bike")
Vehicle vehicle;
2.4、@Required
@Required
用于 Setter 方法,以标记我们希望通过 XML 填充的依赖:
@Required
void setColor(String color) {
this.color = color;
}
<bean class="com.baeldung.annotations.Bike">
<property name="color" value="green" />
</bean>
否则,将抛出 BeanInitializationException
异常。
2.5、Value
可以使用 @Value
向 Bean 注入属性值。它与构造函数、Setter 和字段注入兼容。
构造函数:
Engine(@Value("8") int cylinderCount) {
this.cylinderCount = cylinderCount;
}
Setter 方法:
@Autowired
void setCylinderCount(@Value("8") int cylinderCount) {
this.cylinderCount = cylinderCount;
}
或者:
@Value("8")
void setCylinderCount(int cylinderCount) {
this.cylinderCount = cylinderCount;
}
字段:
@Value("8")
int cylinderCount;
注入静态值并不实用。因此,可以在 @Value
中使用占位符字符串来注入外部资源中定义的值,例如 .properties
或 .yaml
文件中的值。
假设有以下 .properties
文件:
engine.fuelType=petrol
可以用下面的方法注入 engine.fuelType
的值:
@Value("${engine.fuelType}")
String fuelType;
甚至可以在 SpEL 中使用 @Value
。
2.6、@DependsOn
可以使用此注解让 Spring 在注解的 Bean 之前初始化其他 Bean。通常情况下,这种行为是自动进行的,基于 Bean 之间的显式依赖关系。
只有当依赖关系是隐式的,例如 JDBC 驱动加载或静态变量初始化时,才需要此注解。
可以在依赖类上使用 @DependsOn
来指定依赖 Bean 的名称。注解的 value
参数需要一个包含依赖 Bean 名称的数组:
@DependsOn("engine")
class Car implements Vehicle {}
或者,如果我们使用 @Bean
注解定义 Bean,那么就应该在工厂方法上使用 @DependsOn
注解:
@Bean
@DependsOn("fuel")
Engine engine() {
return new Engine();
}
2.7、@Lazy
当我们希望延迟初始化 Bean 时,可以使用 @Lazy
注解。默认情况下,Spring 在 Application Context 启动时会立即创建所有 Singleton(单例)Bean。
不过,在某些情况下,我们需要在使用时创建 Bean,而不是在应用启动时。
这个注解会根据具体标注位置而有不同的表现,可以用在如下位置:
@Bean
注解的 Bean 工厂方法,可以延迟方法调用(从而延迟 Bean 的创建)。@Configuration
类,包含的@Bean
方法都将受到影响@Component
类,而该组件类不是@Configuration
类,则该 Bean 将被延迟地初始化@Autowired
构造函数、Setter 方法或字段,用于延迟地(通过代理)加载依赖本身
该注解有一个名为 value
的参数,默认值为 true
。它可以覆盖默认行为。
例如,当全局设置为懒加载(lazy)时,可以标记要立即加载的 Bean,或者在使用 @Lazy
标记的 @Configuration
类中,配置特定的 @Bean
方法以进行立即加载:
@Configuration
@Lazy
class VehicleFactoryConfig {
@Bean
@Lazy(false) // 立即加载
Engine engine() {
return new Engine();
}
}
2.8、@Lookup
使用 @Lookup
注解的方法会告诉 Spring,在调用该方法时返回该方法返回类型的实例。
2.9、@Primary
有时,需要定义多个相同类型的 Bean。在这种情况下,注入将不会成功,因为 Spring 不知道需要注入哪个 Bean。
上文已经介绍了处理这种情况的方法:用 @Qualifier
标记所有注入点,并指定所需的 Bean 名称。
可以使用 @Primary
注解来简化这种情况:将最常用的 Bean 标记为 @Primary
,它将在未标记 @Qualifier
的注入点上被选中。
@Component
@Primary
class Car implements Vehicle {}
@Component
class Bike implements Vehicle {}
@Component
class Driver {
@Autowired
Vehicle vehicle;
}
@Component
class Biker {
@Autowired
@Qualifier("bike")
Vehicle vehicle;
}
在前面的示例中,Car
注解了 @Primary
。因此,在 Driver
类中,Spring 注入了一个 Car
Bean。当然,在 Biker
Bean 中,vehicle
字段的值将是 Bike
对象,因为它注解了 @Qualifier
并且指定了 Bean 名称。
2.10、@Scope
使用 @Scope
来定义 @Component
类或 @Bean
的 Scope(作用域),它可以是 singleton
、prototype
、request
、session
、globalSession
或某些自定义作用域。
例如:
@Component
@Scope("prototype")
class Engine {}
3、Context 配置注解
可以使用本节介绍的注解来配置 Application Context。
3.1、@Profile
如果我们希望 Spring 仅在特定 Profile(配置文件)处于活动状态时才启用 @Component
类或 @Bean
方法,可以使用 @Profile
对其进行标记。
使用注解的 value
参数配置 Profile 的名称:
@Component
@Profile("sportDay")
class Bike implements Vehicle {}
3.2、@Import
可以使用该注解来使用特定的 @Configuration
类,而无需进行组件扫描。
通过 @Import
注解的 value
参数来提供这些类:
@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}
3.3、@ImportResource
可以使用该注解导入 XML 配置。用 locations
参数或其别名 value
参数指定 XML 文件的位置:
@Configuration
@ImportResource("classpath:/annotations.xml")
class VehicleFactoryConfig {}
3.4、@PropertySource
通过该注解,可以为应用设置定义属性文件:
@Configuration
@PropertySource("classpath:/annotations.properties")
class VehicleFactoryConfig {}
@PropertySource
利用了 Java 8 的重复注解功能,这意味着可以用它多次标记一个类:
@Configuration
@PropertySource("classpath:/annotations.properties")
@PropertySource("classpath:/vehicle-factory.properties")
class VehicleFactoryConfig {}
3.5、@PropertySources
可以使用此注解指定多个 @PropertySource
配置:
@Configuration
@PropertySources({
@PropertySource("classpath:/annotations.properties"),
@PropertySource("classpath:/vehicle-factory.properties")
})
class VehicleFactoryConfig {}
注意,自 Java 8 以来,可以通过上述重复注解的特性来实现同样的功能。
4、总结
本文介绍了 Spring 中最常用的核心注解,包括依赖注入相关的注解以及用于配置 Application Context 的注解。
Ref:https://www.baeldung.com/spring-core-annotations