Spring核心注解解析

目录

1. 概述

2. 依赖注入相关注解

2.1 @Autowired

2.2 @Bean

2.3 @Qualifier

2.4 @Required

2.5 @Value

2.6 @DependsOn

2.7 @Lazy

2.8 @Lookup

2.9 @Primary

2.10 @Scope

3.上下文配置注解

3.1 @Profile

3.2 @Import

3.3 @ImportResource

3.4 @PropertySource

3.5 @PropertySources

4.结论


1. 概述

我们可以使用位于org.springframework.beans.factory.annotation 和 org.springframework.context.annotation packages两个包下的注解来实现spring的依赖注入引擎。

我们通常称之为 “Spring 核心注解” ,我们将在本教程中回顾它们。

2. 依赖注入相关注解

2.1 @Autowired

我们可以使用@Autowired来标记Spring将要解析和注入的依赖项,此注解可以用于构造器方法、setter方法、字段注入等场景。

构造器方法:

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的布尔参数,默认值为true。在使用@Autowired时,首先在容器中查询对应类型的bean,如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据.如果查询的结果不止一个,那么@Autowired会根据名称来查找。如果查询的结果为空,那么会抛出异常。解决方法:使用required=false

注意,如果我们使用构造函数注入,所有构造函数参数都是必需的。

从4.3版开始,我们不需要显式地用@Autowired注释构造函数,除非我们声明了至少两个构造函数。

@Autowired更多细节Guide to Spring @Autowired

关于构造器注入Constructor Dependency Injection in Spring

2.2 @Bean

使用@Bean注解实例化Spring Bean的工厂方法:

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

当需要返回类型为新实例时,Spring会调用这些方法。生成的bean与工厂方法具有相同的名称。如果想要取一个不同的名称,我们可以使用此注释的名称或值参数来实现(参数值是参数名称的别名).

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

注意,所有用@Bean注释的方法都必须在@Configuration类中。

2.3 @Qualifier

我们在不明确bean id或bean名称的情况下使用@Qualifier和@Autowired注解。

例如,以下两个类实现了相同接口

class Bike implements Vehicle {}

class Car implements Vehicle {}

如果spring需要注入Vehicle这个类,会得到多个匹配项。在这种情况下,我们可以使用@Qualifier注解显式地提供bean的名称。

使用构造器注解:

@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
    this.vehicle = vehicle;
}

使用set方法注解:

@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;

更多详情请阅读Guide to Spring @Autowired

2.4 @Required

@Required注解用在setter方法获取XML配置参数的场景:

@Required
void setColor(String color) {
    this.color = color;
}

    

否则,实例话时会抛出BeanInitializationException异常

2.5 @Value

我们可以使用@Value将属性值注入bean。它适用于构造方法、setter方法和字段注入。

构造方法注入:

Engine(@Value("8") int cylinderCount) {
    this.cylinderCount = cylinderCount;
}

set方法注入:

@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注解,更高级的例子可以阅读A Quick Guide to Spring @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在应用程序上下文的启动/引导时立即创建所有单例bean。

但是,有些情况下,我们需要在请求时创建bean,而不是在应用程序启动时创建它。

此注释的行为因具体位置而异。我们可以在以下情况使用

  • 一个@Bean注释的Bean工厂方法,用于延迟方法调用(因此创建Bean)

  • 一个“配置类”和所有包含的“bean”方法将受到影响

  • 一个组件类,它不是一个@Configuration注解类,这个bean会被懒惰地初始化。

  • 使用了@Autowired注解的构造方法、setter方法、或者字段,延迟加载依赖项本身(通过代理)

此批注有一个名为value的参数,默认值为true。可以进行重写

例如,当全局设置为lazy时,想让某个@bean标记的方法为更早加载,或者在使用了@Configuration注解和@Lazy注解的类中指定配置@Bean注解的方法先加载

@Configuration
@Lazy
class VehicleFactoryConfig {
 
    @Bean
    @Lazy(false)
    Engine engine() {
        return new Engine();
    }
}

欲进一步阅读,请访问A Quick Guide to the Spring @Lazy Annotation

2.8 @Lookup

一个用@Lookup注释的方法告诉Spring调用方法时返回该方法的返回类型的实例。

详情访问spring-lookup

2.9 @Primary

有时我们需要定义同一类型的多个bean,在这些情况下,注入将不成功,因为Spring不知道我们需要哪个bean。我们能找到一个处理这个场景的方法:用@Qualifier标记所有的连接点,并指定所需bean的别名。

然而,大多数时候我们需要一个特定的bean,而很少需要其他bean,我们可以使用@Primary来简化这种情况:

如果我们用@Primary标记最常用的bean,它将被选在不合格的注入点上:

@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类实现了vehicle接口并且标注了@primary注解,因此在Driver类中spring注入了一个Car的bean对象。当然在Biker这个类中vehicle对象的名称将会是"bike",因为使用了@qualified注解。

2.10 @Scope

我们使用@Scope来定义@Component类或@Bean定义的范围,它可以是

singleton(全局有且仅有一个实例)、

prototype(每次获取Bean的时候会有一个新的实例)、

request(针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效)、

session(session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效)、

globalSession(global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义)

或某些自定义范围。

例如:

@Component
@Scope("prototype")
class Engine {}

3.上下文配置注解

我们可以使用本节中描述的注释来配置应用程序上下文。

3.1 @Profile

如果我们希望Spring只在特定条件下才才激活使用了@Component注解的类或使用了@Bean注解的方法,我们可以使用@Profile注解。我们可以用注释的value参数配置概要文件的名称

@Component
@Profile("sportDay")
class Bike implements Vehicle {}

了解更多Spring Profiles

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注解利用Java8重复注解特性,这意味着我们可以多次用它标记一个类:

@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 {}

请注意,从Java8开始,我们可以使用上面描述的重复注释特性来实现相同的效果。

4.结论

在本文中,我们看到了最常见的Spring核心注释的概述。我们了解了如何配置bean连接和应用程序上下文,以及如何标记用于组件扫描的类。

示例代码Spring Boot Annotations

你可能感兴趣的:(Java)