properties

依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
  • spring-boot-configuration-processor说白了就是给自定义的配置类生成元数据信息的,因为spring也不知道你有哪些配置类,所以搞了这个方便大家自定义
  • 元数据, 这些数据并不是在项目运行中有什么作用. 而是在开发期间能够通过ide的处理给我们更多的便捷提示.

SpringBoot之spring-boot-configuration-processor

配置文件

  • application.yml:
1
2
3
4
5
6
7
server:
port: 8080
servlet:
context-path: /demo
spring:
profiles:
active: dev

配置分区

  • dev:
1
2
3
4
5
6
7
8
application:
name: dev环境 @artifactId@
version: dev环境 @version@
developer:
name: dev环境 xkcoding
website: dev环境 http://xkcoding.com
qq: dev环境 237497819
phone-number: dev环境 17326075631
  • proc
1
2
3
4
5
6
7
8
application:
name: prod环境 @artifactId@
version: prod环境 @version@
developer:
name: prod环境 xkcoding
website: prod环境 http://xkcoding.com
qq: prod环境 237497819
phone-number: prod环境 17326075631

spring.profiles.active来区分配置

spring boot允许你通过命名约定按照一定的格式

(application-{profile}.properties)来定义多个配置文件根据springboot的配置文件命名约定,结合active可在不同环境引用不同的properties外部配置

  • 如:spring.profiles.active=dev ,dev正好匹配下面配置中的application-dev.properties 配置文件,所以app启动时,项目会先从application-dev.properties加载配置。再从application.properties配置文件加载配置,如果有重复的配置,则以application.properties的配置为准。

如此,我们就不用为了不同的运行环境而去更改大量的环境配置了(此处,dev、pro、test分别为:开发、生产、测试环境配置)

  • @value可以从配置文件中获取值并注入
1
2
3
4
5
6
public class ApplicationProperty {
@Value("${application.name}")
private String name;
@Value("${application.version}")
private String version;
}
  • @ConfigurationProperties

在此种场景下,当Bean被实例化时,@ConfigurationProperties会将对应前缀的后面的属性与Bean对象的属性匹配。符合条件则进行赋值。

1
2
3
4
5
6
7
8
@ConfigurationProperties(prefix = "developer")
@Component
public class DeveloperProperty {
private String name;
private String website;
private String qq;
private String phoneNumber;
}

@ConfigurationProperties使用详解

actuator

actuator是spring boot提供的对应用系统的自省和监控的集成功能,可以对应用系统进行配置查看、相关功能统计等。

三步为你的Springboot集成Actuator监控功能

依赖

1
2
3
4
5
<!--监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置文件

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
server:
port: 8080
servlet:
context-path: /demo
# 若要访问端点信息,需要配置用户名和密码
spring:
security:
user:
name: xkcoding
password: 123456
management:
# 端点信息接口使用的端口,为了和主系统接口使用的端口进行分离
server:
port: 8090
servlet:
context-path: /sys
# 端点健康情况,默认值"never",设置为"always"可以显示硬盘使用情况和线程情况
endpoint:
health:
show-details: always
httptrace:
# 设置端点暴露的哪些内容,默认["health","info"],设置"*"代表暴露所有可访问的端点
endpoints:
web:
exposure:
include: '*'

SpringBootAdmin

  • Spring Boot Admin用于管理和监控一个或多个Spring Boot服务,其分为Server端和Client端,Server端相当于一个注册中心,Client端通过Http请求向Server端进行注册,也可以结合Eureka、Nacos等注册中心实现服务注册。

  • SpringBootAdmin是一个针对 Spring Boot 的 Actuator 接口进行 UI 美化封装的监控工具

  • 它可以在列表中浏览所有被监控 spring-boot 项目的基本信息

    • 详细的 Health 信息、内存信息、JVM 信息、垃圾回收信息、各种配置信息(比如数据源、缓存列表和命中率)等。
  • 可分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client)

  • 服务端和客户端之间采用http通讯方式实现数据交互。服务端server需要单独启动一个服务,而客户端client只需要集成到各个微服务中。

SpringBoot快速集成SpringBootAdmin管控台监控服务

SpringBoot整合Spring Boot Admin实现服务监控

注意在服务端开启@EnableAdminServer

依赖

  • 客户端
1
2
3
4
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
  • 服务器
1
2
3
4
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

配置文件

客户端:

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
server:
port: 8080
servlet:
context-path: /demo
spring:
application:
# Spring Boot Admin展示的客户端项目名,不设置,会使用自动生成的随机id
name: spring-boot-demo-admin-client
boot:
admin:
client:
# Spring Boot Admin 服务端地址
url: "http://localhost:8000/"
instance:
metadata:
# 客户端端点信息的安全认证信息
user.name: ${spring.security.user.name}
user.password: ${spring.security.user.password}
security:
user:
name: xkcoding
password: 123456
management:
endpoint:
health:
# 端点健康情况,默认值"never",设置为"always"可以显示硬盘使用情况和线程情况
show-details: always
endpoints:
web:
exposure:
# 设置端点暴露的哪些内容,默认["health","info"],设置"*"代表暴露所有可访问的端点
include: "*"

日志

Java系统中常用日志框架

异常统一处理

handler相当于是平常业务代码中每个请求对应的的controller类以及方法信息.

@ControllerAdvice注解

  • 首先,ControllerAdvice本质上是一个Component,因此也会被当成组建扫描

  • 这个类是为那些声明了(@ExceptionHandler@InitBinder@ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。

    • 可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是
    • 说白了,就是aop思想的一种实现,你告诉我需要拦截规则,我帮你把他们拦下来,具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler@InitBinder@ModelAttribute这三个注解以及被其注解的方法来自定义
  • @ControllerAdvice就是@Controller 的增强版。@ControllerAdvice主要用来进行全局的处理


@ExceptionHandler注解

该注解作用对象为方法,并且在运行时有效,value()可以指定异常类。由该注解注释的方法可以具有灵活的输入参数

异常类的自定义

  • 基类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Data
@EqualsAndHashCode(callSuper = true)
public class BaseException extends RuntimeException {
private Integer code;
private String message;

public BaseException(Status status) {
super(status.getMessage());
this.code = status.getCode();
this.message = status.getMessage();
}

public BaseException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
}
  • 子类:
1
2
3
4
5
6
7
8
9
10
public class JsonException extends BaseException {

public JsonException(Status status) {
super(status);
}

public JsonException(Integer code, String message) {
super(code, message);
}
}
  • 子类:
1
2
3
4
5
6
7
8
9
10
public class PageException extends BaseException {

public PageException(Status status) {
super(status);
}

public PageException(Integer code, String message) {
super(code, message);
}
}
  1. callSuper = true,根据子类自身的字段值和从父类继承的字段值 来生成hashcode,当两个子类对象比较时,只有子类对象的本身的字段值和继承父类的字段值都相同,equals方法的返回值是true。

  2. callSuper = false,根据子类自身的字段值 来生成hashcode, 当两个子类对象比较时,只有子类对象的本身的字段值相同,父类字段值可以不同,equals方法的返回值是true。

异常统一处理

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
@ControllerAdvice
@Slf4j
public class DemoExceptionHandler {
private static final String DEFAULT_ERROR_VIEW = "error";

/**
* 统一 json 异常处理
*
* @param exception JsonException
* @return 统一返回 json 格式
*/
@ExceptionHandler(value = JsonException.class)
@ResponseBody
public ApiResponse jsonErrorHandler(JsonException exception) {
log.error("【JsonException】:{}", exception.getMessage());
return ApiResponse.ofException(exception);
}

/**
* 统一 页面 异常处理
*
* @param exception PageException
* @return 统一跳转到异常页面
*/
@ExceptionHandler(value = PageException.class)
public ModelAndView pageErrorHandler(PageException exception) {
log.error("【DemoPageException】:{}", exception.getMessage());
ModelAndView view = new ModelAndView();
view.addObject("message", exception.getMessage());
view.setViewName(DEFAULT_ERROR_VIEW);
return view;
}
}

@ControllerAdvice 的介绍及三种用法

@ModelAttribute运用详解

集成mybatis/plus

依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

配置文件

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
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
# initialization-mode: always 此处是spring项目启动是否执行sql的选项
# continue-on-error: true
# schema:
# - "classpath:db/schema.sql"
# data:
# - "classpath:db/data.sql"
hikari:
minimum-idle: 5
connection-test-query: SELECT 1 FROM DUAL
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: SpringBootDemoHikariCP
max-lifetime: 60000
connection-timeout: 30000
logging:
level:
com.xkcoding: debug
com.xkcoding.orm.mybatis.mapper: trace
mybatis:
configuration:
# 下划线转驼峰
map-underscore-to-camel-case: true
mapper-locations: classpath:mappers/*.xml
type-aliases-package: com.xkcoding.orm.mybatis.entity

Lombok中@Builder 注释为你的类生成相对略微复杂的构建器,可以让你以下面显示的那样调用你的代码来初始化你的实例对象:

1
2
3
4
5
6
7
Student.builder()
.sno( "001" )
.sname( "admin" )
.sage( 18 )
.sphone( "110" )
.build();
123456

mybatisplus集成

依赖

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

配置

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
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
initialization-mode: always
continue-on-error: true
schema:
- "classpath:db/schema.sql"
data:
- "classpath:db/data.sql"
hikari:
minimum-idle: 5
connection-test-query: SELECT 1 FROM DUAL
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: SpringBootDemoHikariCP
max-lifetime: 60000
connection-timeout: 30000
logging:
level:
com.xkcoding: debug
com.xkcoding.orm.mybatis.plus.mapper: trace
mybatis-plus:
mapper-locations: classpath:mappers/*.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.xkcoding.orm.mybatis.plus.entity
global-config:
# 数据库相关配置
db-config:
#主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
field-strategy: not_empty
#驼峰下划线转换
table-underline: true
#是否开启大写命名,默认不开启
#capital-mode: true
#逻辑删除配置
#logic-delete-value: 1
#logic-not-delete-value: 0
db-type: mysql
#刷新mapper 调试神器
refresh: true
# 原生配置
configuration:
map-underscore-to-camel-case: true
cache-enabled: true

文件上传

依赖

1
2
3
4
5
6
<dependency>
<!--七牛云-->
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.2.0, 7.2.99]</version>
</dependency>

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8080
servlet:
context-path: /demo
spring:
servlet:
multipart:
enabled: true #是否开启文件上传
file-size-threshold: 0 #文件写入磁盘的阙值
location: D:\\temp #上传文件临时保持位置
max-file-size: 1MB #单文件上传大小
max-request-size: 10MB #多文件上传大小
resolve-lazily: false #是否延迟解析
  • 配置类
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
//标明是配置类
@Configuration
//是当项目中存在以下三个类类时才会使标有该注解的类或方法生效;
@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})
//当存在配置文件符合以下条件则生效
@ConditionalOnProperty(prefix = "spring.http.multipart", name = "enabled", matchIfMissing = true)
//使得ConfigurationProperties标注的类生效
@EnableConfigurationProperties(MultipartProperties.class)
public class UploadConfig {

//与上边的配置文件是相互绑定的
private final MultipartProperties multipartProperties;

@Autowired
public UploadConfig(MultipartProperties multipartProperties) {
this.multipartProperties = multipartProperties;
}

/**
* 上传配置
* MultipartProperties传递给MultipartConfigElement才能生效
*/
@Bean
@ConditionalOnMissingBean
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}

/**
* 注册解析器
* 有了解析器才能将文件对象转为Multipart对象
*/
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
//resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
return multipartResolver;
}

}
  • 控制层代码
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
@RestController
@Slf4j
@RequestMapping("/upload")
public class UploadController {
@Value("${spring.servlet.multipart.location}")
private String fileTempPath;

@PostMapping(value = "/local", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Dict local(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Dict.create().set("code", 400).set("message", "文件内容为空");
}
String fileName = file.getOriginalFilename();
String rawFileName = StrUtil.subBefore(fileName, ".", true);
String fileType = StrUtil.subAfter(fileName, ".", true);
String localFilePath = StrUtil.appendIfMissing(fileTempPath, "/") + rawFileName + "-" + DateUtil.current(false) + "." + fileType;
try {
file.transferTo(new File(localFilePath));
} catch (IOException e) {
log.error("【文件上传至本地】失败,绝对路径:{}", localFilePath);
return Dict.create()
.set("code", 500)
.set("message", "文件上传失败");
}

log.info("【文件上传至本地】绝对路径:{}", localFilePath);
return Dict.create()
.set("code", 200)
.set("message", "上传成功")
.set("data", Dict.create()
.set("fileName", fileName)
.set("filePath", localFilePath));
}
}

下载见mvc

缓存集成Redis

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 对象池,使用redis时必须引入 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

<!-- 引入 jackson 对象json转换 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
redis:
host: localhost
# 连接超时时间(记得添加单位,Duration)
timeout: 10000ms
# Redis默认情况下有16个分片,这里配置具体使用的分片
# database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1ms
# 连接池中的最大空闲连接 默认 8
max-idle: 8
# 连接池中的最小空闲连接 默认 0
min-idle: 0
cache:
# 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
type: redis

配置类

  • StringRedisSerializer:只能存储类型为String的value,当存储其他类型的数据,如double,则无法将value保存到redis

  • Jackson2JsonRedisSerializer:使用Jackson库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口

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
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@EnableCaching//记得开启Spring的缓冲功能
public class RedisConfig {

/**
* 设置Redis相关
* RedisTemplate辅助类,简化了数据访问代码
* 默认情况下的模板只能支持RedisTemplate<String, String>,也就是只能存入字符串,因此支持序列化
*/
@Bean
public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<>();
//设置key的序列化,支持字符串
template.setKeySerializer(new StringRedisSerializer());
//设置value的序列化 支持对象(用了json转换)
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//设置对应的连接池
template.setConnectionFactory(redisConnectionFactory);
return template;
}

/**
* 设置SpringCache相关
* 其实就是把Redis相关的缓冲配置注册进Spring
* 配置使用注解的时候缓存配置,默认是序列化反序列化的形式,加上此配置则为 json 形式
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration redisCacheConfiguration = config.
serializeKeysWith(RedisSerializationContext.
SerializationPair.fromSerializer(new StringRedisSerializer()))//设置key为string
.serializeValuesWith(RedisSerializationContext.
SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));//json

return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
}
}
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
55
56
57
58
59
60
@Service
@Slf4j
public class UserServiceImpl implements UserService {
/**
* 模拟数据库
*/
private static final Map<Long, User> DATABASES = Maps.newConcurrentMap();

/**
* 初始化数据
*/
static {
DATABASES.put(1L, new User(1L, "user1"));
DATABASES.put(2L, new User(2L, "user2"));
DATABASES.put(3L, new User(3L, "user3"));
}

/**
* 保存或修改用户
*
* @param user 用户对象
* @return 操作结果
*/
//CachePut会更新缓存
@CachePut(value = "user", key = "#user.id")
@Override
public User saveOrUpdate(User user) {
DATABASES.put(user.getId(), user);
log.info("保存用户【user】= {}", user);
return user;
}

/**
* 获取用户
*
* @param id key值
* @return 返回结果
*/
//@CachePut当调用这个方法的时候,会从一个名叫 user 的缓存中查询,如果没有,则执行实际的方法(即查询数据库)
@Cacheable(value = "user", key = "#id")
@Override
public User get(Long id) {
// 我们假设从数据库读取
log.info("查询用户【id】= {}", id);
return DATABASES.get(id);
}

/**
* 删除
*
* @param id key值
*/
//@CacheEvict 当调用时会删除缓存
@CacheEvict(value = "user", key = "#id")
@Override
public void delete(Long id) {
DATABASES.remove(id);
log.info("删除用户【id】= {}", id);
}
}

tips

1
2
3
4
5
6
7
8
9
//当调用这个方法的时候,会从一个名叫 menuById 的缓存中查询,如果没有,则执行实际的方法(即查询数据库)
//key,缓存对象的唯一标识,因为对于一个方法来说,不同的参数会有不同的返回值,因此需要用key来标识不同的缓存
//不写的话会采用参数的排列组合
//虽然他们的名字都叫menuById
@Override
@Cacheable(value = {"menuById"}, key = "'hash' + #menu.hashCode()")
public Menu findByHash(Menu menu) {
return menu;
}

img

定时任务

配置类

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
//定时任务配置,配置线程池,使用不同线程执行任务,提升效率
@Configuration
@EnableScheduling//开启定时任务的支持
@ComponentScan(basePackages = {"com.xkcoding.task.job"})
public class TaskConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}

/**
* 这里等同于配置文件配置
* {@code spring.task.scheduling.pool.size=20}
- Maximum allowed number of threads.
* {@code spring.task.scheduling.thread-name-prefix=Job-Thread- }
- Prefix to use for the names of newly created threads.
* {@link org.springframework.boot.autoconfigure.task.TaskSchedulingProperties}
* 通过线程池去执行定时任务,高效
*/
@Bean
public Executor taskExecutor() {
return new ScheduledThreadPoolExecutor
(20,
new BasicThreadFactory.Builder()
.namingPattern("Job-Thread-%d")
.build()
);
}
}

相关执行的类

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
//定时任务
@Component
@Slf4j
public class TaskJob {
/**
* 按照标准时间来算,每隔 10s 执行一次
*/
@Scheduled(cron = "0/10 * * * * ?")
public void job1() {
log.info("【job1】开始执行:{}", DateUtil.formatDateTime(new Date()));
}
/**
* 从启动时间开始,间隔 2s 执行
* 固定间隔时间
*/
@Scheduled(fixedRate = 2000)
public void job2() {
log.info("【job2】开始执行:{}", DateUtil.formatDateTime(new Date()));
}

/**
* 从启动时间开始,延迟 5s 后间隔 4s 执行
* 固定等待时间
*/
@Scheduled(fixedDelay = 4000, initialDelay = 5000)
public void job3() {
log.info("【job3】开始执行:{}", DateUtil.formatDateTime(new Date()));
}
}
  • 在需要定时执行的方法上加入@Scheduled

    • @Scheduled(fixedDelay = 5000)

    • 延迟执行。任务在上个任务完成后达到设置的延时时间就执行。

      • 此处,任务会在上个任务完成后经过5s再执行。
    • @Scheduled(fixedRate = 5000)

    • 定时执行。任务间隔规定时间即执行。

      • 此处,任务每隔五秒便会执行一次。
    • @Scheduled(cron = “0 0 2 * * ?”)

      • 通过cron表达式执行任务

CRON表达式详解