优惠券分发系统-学习笔记-第三章

第三章学习旅程记录-springboot 相关内容

SpringBoot 应用入口

Springboot 的三种启动方式

  • SpringApplication 静态方法 run
  • 通过 api 调整应用行为,并启动
  • SprinigApplicationBuilder 的 fluent api 实现链式调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
// 1. 通过静态 run 方法
SpringApplication.run(SpringBootStudyApplication.class, args);

// 2. 通过 api 调整应用行为
SpringApplication application =
new SpringApplication(SpringBootStudyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);

// 3. SpringApplicationBuilder Fluent Api, 链式调用
new SpringApplicationBuilder(SpringBootStudyApplication.class)
.bannerMode(Banner.Mode.OFF)
.web(WebApplicationType.NONE)
.run(args);
}

@SpringBootApplication

springboot注解

@SpringBootApplication 由三个重要注解组成

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

@SpringBootConfiguration 等价于 @Configuration ,说明该项目通过 java configuration 的方式进行配置。

@ComponentScan 扫描 classpath 下的包和子包用户自定义的一些需要注入的 bean。

@EnableAutoConfiguration 是开启自动配置的功能。

@EnableAutoConfiguration 帮助我们自动载入应用程序所需要的默认配置。也就是我们加入的各种 spring-boot-starter 的配置信息,从而达到了自动配置的功能。

它是由 @AutoConfigurationPackage 和 @Import(AutoConfigurationImportSelector.class) 组成的。
@AutoConfigurationPackage 是由核心注解 @Import(AutoConfigurationPackages.Registrar.class) 组成。

所以我们要关注 AutoConfigurationPackages.Registrar.class 和 AutoConfigurationImportSelector.class 这两个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}

@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}

}

可以看到,AutoConfigurationPackages.Registrar.class 事实上是将一些 bean 注入到 IOC 容器中。这里和之前的 ComponentScan 不同,它是注入一些 spring-boot-starter 的注解,例如 spring-data-jpa 标注的 @entity 等。

它是将应用程序的主配置类所在包和子包 的一些 bean 导入的 IOC 容器,主配置类就是我们应用 springBootApplication 所在的位置 。

查看 AutoConfigurationImportSelector 可以发现,它是通过 getCandidateConfigurations 方法来获取需要进行配置的信息,getCandidateConfigurations 中通过 SpringFactoriesLoader.loadFactoryNames 来加载需要配置的信息。
而这些加载的信息,保存在下面的路径中

1
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

SpringBoot 配置文件

同一目录下的 application 和 bootstrap

  • bootstrap 优先级高于 application,优先被加载
  • bootstrap 用于应用程序上下文的引导阶段,由父 ApplicationContext 加载
  • bootstrap 是系统级别的配置 (不变的参数), application 是应用级别的参数。

不同位置的配置文件加载顺序 (优先级)

  • file: ./config/ - 优先级最高 (项目根路径下的 config)
  • file ./ - 优先级第二 (项目根路径)
  • classpath: /config/ - 优先级第三 (项目 resources/config 下)
  • classpath: / - 优先级第四 (项目 resources 目录下)

高优先级的配置覆盖低优先级相同配置,多个配置文件互补。

SpringBoot 配置文件属性注入方式

  1. @value 注入
  2. @ConfigurationProperties 注入

@ConfigurationProperties 需要引入下列包。

1
2
3
4
5
6
<!-- 专门用于数据绑定的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

ConfigurationProperties 注入实例

1
2
3
4
5
6
7
8
9
10
11
/**
* <h1>SpringBoot 的配置</h1>
* Created by Qinyi.
*/
@Data
@Component
@ConfigurationProperties(prefix = "imooc.springboot")
public class SpringBootConfig {
private String version;
private String name;
}

SpringBoot 定时任务

  • 应用入口加入 @EnableScheduling 注解
  • 编写schedule 类,该类是一个 spring bean,所以需要 @Component 注解
  • 编写对应的方法,加入 @schedule 注解来声明这是一个定时任务

常用定时任务调度配置

  • fixedRate 上一次开始执行时间点之后 X ms 再执行
  • fixedDelay 上一次执行完毕时间点之后X ms 再执行
  • initialDelay 第一次延迟 X ms 后再执行
  • cron crontab 表达式

SpringBoot 异步任务

启用异步任务需要引入 web starter 相关依赖。

通过 @EnableAsync 开启异步任务支持,随后编写 async 相关类,填写 @Service 注解,标注是一个 spring bean。

编写异步方法,可以有返回值,和无返回值,填写 @Async 注解,标识是一个异步服务。
因为 springboot 自己实现的异步线程池比较低效,每次都会新建一个线程池,所以我们需要自行实现一个异步线程池。

同时,还要处理异步任务的异常,要注意的是,有返回值的异常可以交给客户端进行处理。无返回值的异常,我们需要在配置中进行编写对应方法。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Slf4j
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {

@Bean
@Override
public Executor getAsyncExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(20);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("ImoocAsync_");

// 等待所有任务完成后才关闭,默认 false
executor.setWaitForTasksToCompleteOnShutdown(true);
// 最大等待时间 60s
executor.setAwaitTerminationSeconds(60);

// 拒绝策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy()
);

executor.initialize();

return executor;
}

/**
* <h2>定义异步任务异常处理类</h2>
* */
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}

class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

@Override
public void handleUncaughtException(Throwable throwable,
Method method, Object... objects) {
log.info("AsyncError: {}, Method: {}, Param: {}",
throwable.getMessage(),
method.getName(),
JSON.toJSONString(objects));
throwable.printStackTrace();

// TODO 发送邮件或者短信
}
}
}

SpringBoot 开机启动

有两种方式

  • ApplicationRunner
  • CommandLineRunner

默认 ApplicationRunner 优先级高于 CommandLineRunner ,可以通过再类上加入 @Order() 注解来更改顺序。

SpringBoot jackson 使用技巧

springboot 内置 jackson ,同时 controller 也是通过内置 jackson 来完成序列化和反序列化。

四个常用的 jacksono 注解

  • @JsonProperty(“rt”) 可以起别名
  • @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”) 设置格式
  • @JsonIgnore 设置忽略该字段,不序列化
  • @JsonIgnoreProperties 类级别

因为每个都设置 JsonFormat 非常麻烦,所以我们可以配置 jackson的 objectmapper 来通用设置。

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

@Bean
public ObjectMapper getObjectMapper() {

ObjectMapper mapper = new ObjectMapper();
// 不序列化空值
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 设置默认的日期格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

return mapper;
}
}

Spring Boot Actuator

springboot 提供的对应用系统的自省和监控的集成功能,它可以查看应用(配置)信息,环境信息以及对应用进行操控。

Actuator 监控点分类

  • 原生端点
    • 应用配置类
    • 度量指标类
    • 操作控制类
  • 自定义端点

应用配置类常用监控

  • /actuator/info 自己配置的 info 信息
  • /actuator/beans 应用中 bean 的信息
  • /actuator/mappings 应用中 URI 的路径信息。

度量指标常用监控

  • /actuator/health 检查应用的运行状态
  • /actuator/threaddump 当前线程活动快照

操作控制类常用监控

  • /actuator/shutdown 关闭应用 (POST)

自定义端点实例

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Endpoint(id = "datetime")
public class DateTimeEndPoint {

private String format = "yyyy-MM-dd HH:mm:ss";

/**
* <h2>用来显示监控指标</h2>
* /imooc/actuator/datetime
* */
@ReadOperation
public Map<String, Object> info() {

Map<String, Object> info = new HashMap<>();
info.put("name", "qinyi");
info.put("age", "19");
info.put("datetime", new SimpleDateFormat(format).format(new Date()));

return info;
}

/**
* <h2>动态更改监控指标</h2>
* */
@WriteOperation
public void setFormat(String format) {
this.format = format;
}
}

@Configuration
public class DateTimeEndpointConfig {

@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public DateTimeEndPoint dateTimeEndPoint() {
return new DateTimeEndPoint();
}
}

自定义 Spring Boot Starter

加入相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-autoconfigure -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
</dependencies>

编写对应的类和配置类,并在 resources 下新建 META-INF目录,在该目录下新建 spring.factoies 文件。在其中配置需要自动配置的类

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.imooc.springboot.configuration.SplitAutoConfiguration