Spring 核心注解

1、概览

我们可以通过 org.springframework.beans.factory.annotationorg.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 有一个名为 requiredboolean 参数,默认值为 true。当 Spring 找不到合适的 Bean 进行注入时,它会控制 Spring 的行为。当值为 true 时,会抛出异常,反之则不会。

注意,如果使用构造函数注入,所有构造函数参数都是 必须的

从 Spring 4.3 开始,除非声明了至少两个构造函数,否则不需要用 @Autowired 明确注解构造函数。

2.2、@Bean

@Bean 用于标记工厂方法,用于实例化 Spring Bean:

@Bean
Engine engine() {
    return new Engine();
}

生成的 Bean 的名称与工厂方法的名称相同。如果想使用不同的名称,可以使用此注解的 namevalue 参数(valuename 的别名):

@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 类或 @BeanScope(作用域),它可以是 singletonprototyperequestsessionglobalSession 或某些自定义作用域。

例如:

@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