1.概述
我们可以通过org.springframework.beans.factory.annotation 和org.springframework.context.annotation 包中的注解利用Spring DI引擎的能力。我们将这些包中的注解称为Spring核心注解,在本教程中将会复习它们。
2.DI有关的注解
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的boolean参数,默认值为true。当此注解没有找到合适的bean进行注入时可以通过此参数调整Spring的注入行为。当required为true时,将会抛出异常,否则将不会执行注入。
注意,如果我们使用构造器进行注入,所有构造器参数是强制性的。
从4.3版本开始,如果只有一个构造器,那么我们不需要明确的在构造器上标注@Autowired注解。
2.2 @Bean
@Bean注解标记一个实例化Spring bean的工厂方法:
@Bean
Engine engine() {
return new Engine();
}
当需要一个返回类型的新实例时,被@Bean标注的方法将被调用。
返回的bean和该方法具有相同的名字。如果我们想给它起不同的名字,我们可以通过该注解中的name或value参数指定(其中value参数是name参数的别名):
@Bean("engine")
Engine getEngine() {
return new Engine();
}
注意,所有被@Bean标注的方法必须在被@Configuration注解标注的类中。
2.3 @Qualifier
当出现不确定注入哪个bean时,我们可以同时使用@Qualifier和@Autowired注解提供这个bean的id或名称唯一指定。
例如,下面两个bean实现相同的接口:
class Bike implements Vehicle {}
class Car implements Vehicle {}
如果Spring需要注入一个Vehicle bean,它会匹配到多个符合条件的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文件中。
假设有下面的文件:
engine.fuelType=petrol
我们可以通过下面的方式注入engine.fuelType的值:
@Value("${engine.fuelType}")
String fuelType;
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工厂方法,用于延迟方法调用
- @Configuration类,所有包含的@Bean方法都将受到影响
- 一个@Component类,它不是一个@Configuration类,这个bean将被惰性初始化
- @Autowired构造函数、setter或字段,用于惰性地(通过代理)加载依赖项本身
这个注解有个value参数,默认值为true,它通常被用来覆盖默认行为。
例如,当全局设置为懒加载时让某个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的名称。
然而,大多数情况下我们需要一个指定的bean而不是其他的。我们可以使用@Primary简化这种场景:我们将频繁使用的bean标注为@Primary,它将会被优先注入:
@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被标记为主要的交通工具,因此,在Driver类中Spring将注入Car,当然,在Biker类中将被注入Bike,因为它已经被指定了。
2.10 @Scope
我们使用@Scope定义@Component类或@Bean实例的作用域。它可以被指定为singleton、prototype、request、session、globalSession或其他自定义作用域中的一个。
例如:
@Component
@Scope("prototype")
class Engine {}
3. 上下文配置注解
我们可以通过本节描述的注解配置应用上下文信息。
3.1 @Profile
如果我们想使用@Compant或@Bean方法仅当一个指定的profile被激活时,我们可以将其标记为@Profile。
我们可以通过该注解的参数value来配置profile的名字:
@Component
@Profile("sportDay")
class Bike implements Vehicle {}
3.2 @Import
通过此注解我们可以使用没有进行组件扫描的被@Configuration标记的指定类,通过该注解的参数value指定这些类:
@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}
3.3 @ImportResource
通过这个注解我们可以导入xml配置。我们可以通过value参数指定xml文件的路径:
@Configuration
@ImportResource("classpath:/annotations.xml")
class VehicleFactoryConfig {}
3.4 @PropertySource
通过此注解可以定义应用配置的属性文件:
@Configuration
@PropertySource("classpath:/annotations.properties")
class VehicleFactoryConfig {}
此注解利用了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和配置环境上下文,如何标记类使其可以被组件扫描发现。