Spring 的这些核心注解你了解吗?
我们可以使用org.springframework.beans.factory.annotation
和org.springframework.context.annotation
包中的注释来利用Spring DI引擎的功能。我们经常将这些称为“Spring核心注释”。
>>DI相关注释
1. @Autowired
我们可以使用@Autowired
来标记Spring将要解析和注入的依赖项。我们可以将这个注释与构造函数,setter或字段注入一起使用。构造函数注入:
class Car {
Engine engine;
@Autowired
Car(Engine engine) {
this.engine = engine;
}
}
设值注入:
class Car {
Engine engine;
@Autowired
void setEngine(Engine engine) {
this.engine = engine;
}
}
字段注入:
class Car {
@Autowired
Engine engine;
}
@Autowired
有一个名为required
的布尔参数,默认值为true
。当它没有找到合适的bean来连接时,它会调整Spring的行为。如果为true,则抛出异常,否则没有任何连线。注意,如果我们使用构造函数注入,则所有构造函数参数都是必需的。从版本4.3开始,除非我们声明至少两个构造函数,否则我们不需要显式地使用@Autowired
注释构造函数。
2. @Bean
当需要返回类型的新实例时,Spring会调用这些方法。生成的bean与工厂方法具有相同的名称。如果我们想以不同的方式命名,我们可以使用此批注的名称或值参数(参数值是参数名称的别名):
@Bean("engine")
Engine getEngine() {
return new Engine();
}
请注意,所有使用@Bean
注释的方法都必须在@Configuration
类中。
3. @Qualifier
我们使用@Qualifier
和@Autowired
来提供我们想要在不明确的情况下使用的bean id或bean名称。例如,以下两个bean实现相同的接口:
class Bike implements Vehicle {}
class Car implements Vehicle {}
如果Spring需要注入一个Vehicle bean,它最终会有多个匹配的定义。在这种情况下,我们可以使用@Qualifier注释显式提供bean的名称。使用构造函数注入:
@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}
设值注入:
@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;
4. @Required
@Required
用于标记我们想要通过XML填充的依赖项的setter方法:
@Required
void setColor(String color) {
this.color = color;
}
<bean class="com.baeldung.annotations.Bike">
<property name="color" value="green" />
</bean>
否则,将抛出BeanInitializationException
。
5. @Value
我们可以使用@Value
将属性值注入bean。它与构造函数,setter和字段注入兼容。
构造函数注入:
Engine(@Value("8") int cylinderCount) {
this.cylinderCount = cylinderCount;
}
设值注入:
@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;
6. @DependsOn
我们可以使用这个注释使Spring在注释之前初始化其他bean。通常,此行为是自动的,基于bean之间的显式依赖关系。当依赖项是隐式时,我们只需要这个注释,例如,JDBC驱动程序加载或静态变量初始化。
我们可以在依赖类上使用@DependsOn
来指定依赖关系bean的名称。注释的value参数需要一个包含依赖项bean名称的数组:
@DependsOn("engine")
class Car implements Vehicle {}
或者,如果我们使用@Bean
批注定义bean,则应使用@DependsOn
注释工厂方法:
@Bean
@DependsOn("fuel")
Engine engine() {
return new Engine();
}
7. @Lazy
当我们想要懒惰地初始化我们的bean时,我们使用@Lazy
。默认情况下,Spring会在应用程序上下文的启动/引导时急切地创建所有单例bean。
但是,有些情况下我们需要在请求时创建bean,而不是在应用程序启动时。
此注释的行为会有所不同,具体取决于我们准确放置它的位置。我们可以说:
一个@Bean
带注释的bean工厂方法,用于延迟方法调用(因此创建bean) 一个@Configuration
类,所有包含的@Bean
方法都会受到影响 一个@Component
类,它不是@Configuration
类,这个bean将被懒惰地初始化 @Autowired
构造函数,setter或字段,懒惰地加载依赖项(通过代理)此批注具有名为value的参数,其默认值为true。
覆盖默认行为很有用。例如,在全局设置为惰性时标记要急切加载的bean,或者在@Lazy
标记的@Configuration
类中将特定的@Bean
方法配置为急切加载:
@Configuration
@Lazy
class VehicleFactoryConfig {
@Bean
@Lazy(false)
Engine engine() {
return new Engine();
}
}
8. @Lookup
使用@Lookup
注释的方法告诉Spring在调用它时返回方法返回类型的实例。
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;
}
在前面的例子中,汽车是主要的载体。因此,在Driver类中,Spring注入了一个Car bean。当然,在Biker bean中,现场车辆的价值将是一个Bike对象,因为它是合格的。
10. @Scope
我们使用@Scope
来定义@Component
类的范围或@Bean定义。它可以是单例,原型,请求,会话,globalSession或某些自定义范围。例如:
@Component
@Scope("prototype")
class Engine {}
>>上下文配置注释
我们可以使用本节中描述的注释配置应用程序上下文。
1. @Profile
如果我们希望Spring仅在特定配置文件处于活动状态时使用@Component
类或@Bean
方法,我们可以使用@Profile
标记它。我们可以使用注释的value参数配置配置文件的名称:
@Component
@Profile("sportDay")
class Bike implements Vehicle {}
2. @Import
我们可以使用特定的@Configuration
类,而不使用此批注进行组件扫描。我们可以为这些类提供@Import
的value参数:
@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}
3. @ImportResource
我们可以使用此批注导入XML配置。我们可以使用locations参数或其别名value参数指定XML文件位置:
@Configuration
@ImportResource("classpath:/annotations.xml")
class VehicleFactoryConfig {}
4. @PropertySource
使用此注释,我们可以为应用程序设置定义属性文件:
@Configuration
@PropertySource("classpath:/annotations.properties")
class VehicleFactoryConfig {}
@PropertySource
利用Java 8重复注释功能,这意味着我们可以多次使用它标记一个类:
@Configuration
@PropertySource("classpath:/annotations.properties")
@PropertySource("classpath:/vehicle-factory.properties")
class VehicleFactoryConfig {}
5. @PropertySources
我们可以使用此批注指定多个@PropertySource
配置:
@Configuration
@PropertySources({
@PropertySource("classpath:/annotations.properties"),
@PropertySource("classpath:/vehicle-factory.properties")
})
class VehicleFactoryConfig {}
注意,自Java 8以来,我们可以通过如上所述的重复注释功能实现相同的功能。
- END -
往期精彩
◆
◆
◆
关注下方二维码
每天推送优质文章
你会有意想不到的收获