Spring 核心注解
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的布尔参数,默认值为true。当找不到合适的 bean 进行连接时,它会调整 Spring 的行为。当true时,抛出异常,否则,什么都没有连接。
请注意,如果我们使用构造函数注入,则所有构造函数参数都是必需的。
从 4.3 版开始,除非我们声明至少两个构造函数,否则我们不需要使用*@Autowired*显式注释构造函数。 有关更多详细信息,请访问我们关于@Autowired 和构造函数注入 的文章。
2.2. @Bean
@Bean标记了一个实例化 Spring bean 的工厂方法:
@Bean
Engine engine() {
return new Engine();
}
当需要返回类型的新实例时,Spring 会调用这些方法。
生成的 bean 与工厂方法具有相同的名称。如果我们想给它起不同的名字,我们可以使用这个注解的name或value参数(参数value是参数name的别名):
@Bean("engine")
Engine getEngine() {
return new Engine();
}
请注意,所有使用*@Bean注释的方法都必须在@Configuration*类中。
2.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;
}
使用 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.blogdemo.annotations.Bike">
<property name="color" value="green" />
</bean>
否则,将抛出BeanInitializationException。
2.5. @Value
我们可以使用@Value 将属性值注入到 bean 中。它与构造函数、设置器和字段注入兼容。
构造函数注入:
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*。更多高级示例可以在我们关于*@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)
- 一个*@Configuration类和所有包含的@Bean*方法都会受到影响
- 一个*@Component类,它不是一个@Configuration*类,这个bean将被延迟初始化
- @Autowired构造函数、设置器或字段,用于延迟加载依赖项本身(通过代理)
此注释有一个名为value的参数,默认值为true。覆盖默认行为很有用。
例如,当全局设置为惰性时,将 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 的名称。
然而,大多数时候我们需要一个特定的 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是主要车辆。因此,在Driver类中,Spring 注入了一个Car bean。当然,在Biker bean 中,字段vehicle的值将是Bike对象,因为它是合格的。
2.10. @Scope
我们使用*@Scope来定义@Component类或@Bean定义的范围 。它可以是单例、原型、请求、会话、全局会话*或一些自定义范围。
例如:
@Component
@Scope("prototype")
class Engine {}
3. 上下文配置注解
我们可以使用本节中描述的注释来配置应用程序上下文。
3.1. @Profile
如果我们希望 Spring仅在特定配置文件处于活动状态时使用*@Component类或@Bean*方法,我们可以用*@Profile标记它。我们可以使用注解的value*参数配置配置文件的名称:
@Component
@Profile("sportDay")
class Bike implements Vehicle {}
可以在本文 中阅读有关配置文件的更多信息。
3.2. @Import
我们可以使用特定的*@Configuration*类而无需使用此注解进行组件扫描。我们可以为这些类提供*@Import的value*参数:
@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}
3.3. @ImportResource
我们可以使用此注解**导入 XML 配置。**我们可以使用*locations 参数指定 XML 文件位置,或者使用它的别名value *参数:
@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 开始,我们可以通过上述重复注解功能实现相同的功能。