Spring Boot 最核心的27个干货注解,你了解多少?

Posted by 彭超 on 2019-11-30
Estimated Reading Time 8 Minutes
Words 2.1k In Total
Viewed Times

Spring 相关的 6 个注解

Spring Boot 的有些注解有时候也需要和 Spring 的注解搭配使用,例如以下于 Spring Boot 配合最紧密的 6 个 Spring 基础框架的注解:

@Configuration

从 Spring 3.0 开始,@Configuration 用于定义配置类,可替换 xml 配置文件,被注解的类内部含有一个或多个被 @Bean 注解的方法,这些方法将被 AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext 类进行扫描,并用于构建 Bean 定义,初始化 Spring 容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class TaskAutoConfiguration {

@Bean
@Profile("biz-electrfence-controller")
public BizElectrfenceControllerJob bizElectrfenceControllerJob() {
return new BizElectrfenceControllerJob();
}

@Bean
@Profile("biz-consume-1-datasync")
public BizBikeElectrFenceTradeSyncJob bizBikeElectrFenceTradeSyncJob() {
return new BizBikeElectrFenceTradeSyncJob();
}
}

@ComponentScan

做过 Web 开发的同学一定用过 @Controller,@Service,@Repository 注解,查看源码你会发现,它们当中都会有一个共同的注解 @Component,而 @ComponentScan 注解默认就会将标识了 @Controller,@Service,@Repository,@Component 注解的类装配到 Spring 容器中。

1
2
3
4
5
6
@ComponentScan(value = "com.abacus.check.api")
public class CheckApiApplication {
public static void main(String[] args) {
SpringApplication.run(CheckApiApplication.class, args);
}
}

@SpringBootApplication 注解也包含了 @ComponentScan 注解,所以在使用中也可以也可以通过 @SpringBootApplication 的 baseScanPackages 属性进行配置。

1
2
3
4
5
6
@SpringBootApplication(scanBasePackages = {"com.abacus.check.api", "com.abacus.check.service"})
public class CheckApiApplication {
public static void main(String[] args) {
SpringApplication.run(CheckApiApplication.class, args);
}
}

@Conditional

@Conditional 是 Spring 4 新提供的注解,通过 @Conditional 注解可以根据代码中设置的条件装载不同的 Bean,在设置条件注解之前,先要把装载 Bean 的类去实现 Conditional 接口,然后对实现接口的类设置是否装配的条件。Spring Boot 注解中的 @ConditionalOnProperty,@ConditionalOnBean 等以 @Conditional 开头的注解,都是通过集成了 @Conditional 来实现相应功能。

@Import

通过导入的方式把实例加入到 Spring IOC 容器中。可以在需要时将没有被 Spring 容器管理的类导入至 Spring 容器中。

1
2
3
4
5
6
7
8
9
10
//类定义
public class Square {}

//类定义
public class Circular {}

//导入
@Import({Square.class,Circular.class})
@Configuration
public class MainConfig{}

@ImportResource

和 @Import 类似,区别在于 @ImportResource 导入的是配置文件。

1
2
3
4
5
6
7
@ImportResource("classpath:spring-redis.xml")  //导入xml配置

public class CheckApiApplication {
public static void main(String[] args) {
SpringApplication.run(CheckApiApplication.class, args);
}
}

@Component

@Component 是一个元注解,意思是可以注解其它类注解,如 @Controller,@Service,@Repository。带此注解的类被看作组件,当使用基于此注解的配置和类的路径被扫描到的时候,这些类会被实例化。@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注,作用就相当于 XML 配置。

Spring Boot 最核心的 20 个注解

说完与 Spring Boot 密切相关的几个 Spring 基础注解后,下面我们就再一起看看 Spring Boot 提供的核心注解的内容吧。

@SpringBootApplication

这个注解是 Spring Boot 最核心的注解,用在 Spring Boot 的主类上,标识这个一个 Spring Boot 应用,用来开启 Spring Boot 的各项能力。实际上这个注解是 @Configuration,@EnableAutoConfiguration,@ComponentScan 三个注解的组合。由于这些注解是一起使用,所以 Spring Boot 提供了一个统一的注解 @SpringBootApplication。

@EnableAutoConfiguration

允许 Spring Boot 自动配置注解,开启这个注解后 Spring Boot 就能根据当前类路径下的包或者类来配置 Spring Bean。

如:当前类路径下有 MyBatis 这个 Jar 包,MuBatisAutoConfiguration 注解就能根据相关参数来配置 MyBatis 的各个 Bean。

@EnableAutoConfiguration 实现的关键在于引入了 AutoConfigurationImportSelector,其核心逻辑为 selectImports 方法,逻辑大致如下:

  • 从配置文件 META-INF/spring.factories 加载所有可能用到的配置类
  • 去重,并将 exclude 和 excludeName 属性携带的类排除
  • 过滤,将满足条件(@Conditional)的自动配置类返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//导入AutoConfigurationImportSelector的子类
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

@SpringBootConfiguration

这个注解是 @Configuration 注解的变体,只是用来修饰 Spring Boot 的配置而已,或者可利于 Spring Boot 后续的扩展。

@ConditionalOnBean

@ConditionalOnBean(A.class),仅仅在当前上下文中存在 A 对象时,才会实例化一个 Bean,也就是说只有当 A.class 在 Spring 的 ApplicationContext 中存在是,这个当前的 Bean 才能够创建。

1
2
3
4
5
6
@Bean
//当前环境上下文存在DefaultMQProducer实例时,才能创建RocketMQProducerLifecycle这个Bean
@ConditionalOnBean(DefaultMQProducer.class)
public RocketMQProducerLifecycle rocketMQLifecycle() {
return new RocketMQProducerLifecycle();
}

@ConditionalOnMissingBean

组合 @Conditional 注解,和 @ConditionalMissingBean 注解相反,仅仅在当前上下文中不存在 A 对象时,才会实例化当前 Bean。

1
2
3
4
5
6
@Bean
//仅当当前环境上下文缺失RocketMQProducer对象时,才允许创建RocketMQProducer Bean对象
@ConditionalOnMissingBean(RocketMQProducer.class)
public RocketMQProducer mqProducer() {
return new RocketMQProducer();
}

@ConditionalOnClass

组合 @Conditional 注解,仅当某些类存在于 classpath 上的时候才创建当前 Bean。

1
2
3
4
5
6
7
8
@Bean
//当classpath中存在类HealthIndicator时,才创建HealthIndicator Bean对象
@ConditionalOnClass(HealthIndicator.class)
public HealthIndicator rocketMQProducerHealthIndicator(Map<String, DefaultMQProducer> producers) {
if (producers.size() == 1) {
return new RocketMQProducerHealthIndicator(producers.values().iterator().next());
}
}

@ConditionalOnMissingClass

组合 @Conditional 注解,和 @ConditionalOnClass 注解相反,当 classpath 中没有指定的 Class 才开启配置。

@ConditionalOnWebApplication

组合 @Conditional 注解,当前项目类型是 Web 项目才开启配置,当前项目类型有以下三种

  • ANY:任何 Web 项目都匹配
  • SERVLET:仅基础的 Servlet 项目才会匹配
  • REACTIVE:只有基于响应的 Web 项目才匹配

@ConditionalOnMissingWebApplication

组合 @Conditional 注解,和 @ConditionalOnWebApplication 注解相反,当前项目类型不是 Web 项目才开启配置。

@ConditionalOnProperty

组合 @Conditional 注解,当指定的属性有指定的值才开启配置。

具体操作是通过两个属性 name 以及 havingValue 来实现的,其中 name 是用来从 application.properties 中读取某个属性值,如果该值为空则直接返回 false;如果值不为空,则将该值与 havingValue 指定的值进行比较,如果一样返回 true,否则返回 false;如果返回值为 false,则该 configuration 不生效;为 true 则生效。

1
2
3
4
5
6
@Bean
//匹配属性rocketmq.producer.enabled值是否为true
@ConditionalOnProperty(value = "rocketmq.producer.enabled", havingValue = "true", matchIfMissing = true)
public RocketMQProducer mqProducer() {
return new RocketMQProducer();
}

@ConditionalOnExpression

组合 @Conditional 注解,当 SpEL 表达式为 true 时才开启配置。

1
2
3
4
5
6
7
8
@Configuration
@ConditionalOnExpression("${enabled:false}")
public class BigpipeConfiguration {
@Bean
public OrderMessageMonitor orderMessageMonitor(ConfigContext configContext) {
return new OrderMessageMonitor(configContext);
}
}

@ConditionalOnJava

组合 @Conditional 注解,当运行的 Java JVM 在指定的版本范围时才开启配置。

@ConditionalOnResource

组合 Conditional 注解,当类路径下有指定的资源才开启配置

1
2
3
4
5
@Bean
@ConditionalOnResource(resources="classpath:shiro.ini")
protected Realm iniClasspathRealm(){
return new Realm();
}

@ConditionalOnJndi

组合 @Conditional 注解,当指定的 JNDI 存在时才开启配置。

@ConditionalOnCloudPlatform

组合 @Conditional 注解,当指定的云平台激活时才开启配置。

@ConditionalOnSingleCandidate

组合 @Conditional 注解,当指定的 class 在容器中只有一个 Bean,或者同时有多个但为首选时才开启配置。

@ConfigurationProperties

Spring Boot 可以使用注解的方式将自定义的 .properties 文件映射到 实体 Bean 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Data
@ConfigurationProperties("rocketmq.consumer")
public class RocketMQConsumerProperties extends RocketMQProperties {
private boolean enabled = true;

private String consumerGroup;

private MessageModel messageModel = MessageModel.CLUSTERING;

private ConsumeFromWhere consumeFromWhere = ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET;

private int consumeThreadMin = 20;

private int consumeThreadMax = 64;

private int consumeConcurrentlyMaxSpan = 2000;

private int pullThresholdForQueue = 1000;

private int pullInterval = 0;

private int consumeMessageBatchMaxSize = 1;

private int pullBatchSize = 32;
}

@EnableConfigurationProperties

当 @EnableConfigurationProperties 注解应用到你的 @Configuration 时,任何被 @ConfigurationProperties 注解的 Beans 将自动被 Environment 属性配置。这种风格特别适合与 SpringApplication 的外部 YAML 配置进行配合使用。

1
2
3
4
5
6
7
8
9
10
@Configuration
@EnableConfigurationProperties({
RocketMQProducerProperties.class,
RocketMQConsumerProperties.class,
})
@AutoConfigureOrder
public class RocketMQAutoConfiguration {
@Value("${spring.application.name}")
private String applicationName;
}

@AutoConfigureAfter

用在自动配置类上面。表示该自动配置类需要在另外指定的自动配置类配置完之后。

如 MyBatis 的自动配置类,需要在数据源自动配置类之后。

1
2
3
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
}

@AutoConfigureBefore

这个和 @AutoConfigureAfter 注解相反,表示该自动配置类需要在另外指定的自动配置类配置完之前。

@AutoConfigureOrder

Spring Boot 1.3.0 中有一个新注解 @AutoConfigureOrder,用于确定配置加载的优先级顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 自动配置里面的最高优先级
@Configuration
@ConditionalOnWebApplication // 仅限于web应用
@Import(BeanPostProcessorsRegistrar.class) // 导入内置容器的设置
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
// ...
}

@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
// ...
}
}

本文为转载文章,转载请标明原文出处。

原文链接:https://www.fangzhipeng.com/javainterview/2019/09/06/boot-27-ann.html


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !