定时任务:有时候我们需要做定时的一些操作,比如统计信息,定时发送邮件等

在SpringBoot中如何进行整合和使用呢?

有哪些方式可以实现定时任务呢?

Java自带的java.util.timer:

优点:Java自带,无需导包

缺点:配置复杂,时间延后等问题

Quartz框架:

优点:配置简单,使用方便

缺点:需要导包

@EnableSchedule:

优点:SpringBoot自带,高兼容,无需导包

使用:

在启动类加入@EnableScheduling注解

package org.dreamtech.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication
@EnableScheduling
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} }

定义Task:

package org.dreamtech.demo.task;

import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; @Component
public class TestTask {
@Scheduled(fixedRate = 2000)
public void test() {
System.out.println("[ " + "当前时间 : " + new Date() + " ]");
}
}

效果:控制台每过两秒打印一次当前时间

[ 当前时间 : Fri May 10 14:01:42 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:44 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:46 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:48 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:50 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:52 CST 2019 ]
[ 当前时间 : Fri May 10 14:01:54 CST 2019 ]

使用CRON表达式:

每两秒执行一次的另一种表达方式:

    @Scheduled(cron = "*/2 * * * * *")

关于CRON表达式的百度即可,一堆介绍,我就不多写了

异步任务:适用于发送短信、邮件、处理Log等问题

为什么需要异步任务?

比如电商网站用户下单,要做的事情有这几样:库存查询、用户校验、余额校验等

SpringBoot使用异步任务:@EnableAsync注解

基本实现:

启动类加入@EnableAsync注解

package org.dreamtech.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication
@EnableAsync
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} }

定义任务类:这里模拟耗时的操作

package org.dreamtech.demo.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; @Component
@Async
public class AsyncTask {
public void test1() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务1耗时 : " + (end - begin) + " ]");
} public void test2() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]");
} public void test3() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(3000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]");
}
}

Controller层做测试:

package org.dreamtech.demo.controller;

import org.dreamtech.demo.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TestController {
@Autowired
private AsyncTask task; @GetMapping("/test")
private Object test() {
long begin = System.currentTimeMillis();
try {
task.test1();
task.test2();
task.test3();
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("[ " + "Controller耗时 : " + (end - begin) + " ]");
return "test";
}
}

访问localhost:8080/test打印如下:

[ Controller耗时 : 4 ]
[ 任务1耗时 : 1000 ]
[ 任务2耗时 : 2000 ]
[ 任务2耗时 : 3000 ]

结论:异步任务的执行类似多线程,可以用来做一些耗时操作

有时候需要某个任务确定执行完毕才能继续其他操作

如何获取任务的执行结果呢?

package org.dreamtech.demo.task;

import java.util.concurrent.Future;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component; @Component
@Async
public class AsyncTask { public Future<String> test1() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务1耗时 : " + (end - begin) + " ]");
return new AsyncResult<String>("任务1");
} public Future<String> test2() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务2耗时 : " + (end - begin) + " ]");
return new AsyncResult<String>("任务2");
} public Future<String> test3() throws InterruptedException {
long begin = System.currentTimeMillis();
Thread.sleep(3000);
long end = System.currentTimeMillis();
System.out.println("[ " + "任务3耗时 : " + (end - begin) + " ]");
return new AsyncResult<String>("任务3");
}
}

Controller:

package org.dreamtech.demo.controller;

import java.util.concurrent.Future;

import org.dreamtech.demo.task.AsyncTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TestController {
@Autowired
private AsyncTask task; @GetMapping("/test")
private Object test() {
long begin = System.currentTimeMillis();
try {
Future<String> task1Result = task.test1();
Future<String> task2Result = task.test2();
Future<String> task3Result = task.test3();
while (true) {
if (task1Result.isDone() && task2Result.isDone() && task3Result.isDone()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("[ " + "Controller耗时 : " + (end - begin) + " ]");
return "test";
}
}

访问localhost:8080/test

等待3秒之后,打印如下:

[ 任务1耗时 : 1001 ]
[ 任务2耗时 : 2001 ]
[ 任务3耗时 : 3001 ]
[ Controller耗时 : 3007 ]

只有三个任务都完成,Controller层代码才会执行完毕

总结:异步任务大大地提高了开发的效率

顺便来记录Logback的使用:

Logback:一款优秀的日志框架

SpringBoot的Starter默认日志框架:Logback,默认级别:INFO

如果我们想以DEBUG方式启动:java -jar springboot.jar --debug

配置文件:官方推荐名称logback-spring.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration> <appender name="consoleApp"
class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
</pattern>
</layout>
</appender> <appender name="fileInfoApp"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
</pattern>
</encoder>
<!-- 滚动策略 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 路径 -->
<fileNamePattern>app_log/log/app.info.%d.log</fileNamePattern>
</rollingPolicy>
</appender> <appender name="fileErrorApp"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>
%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
</pattern>
</encoder>
<!-- 设置滚动策略 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 路径 -->
<fileNamePattern>app_log/log/app.err.%d.log</fileNamePattern>
<!-- 控制保留的归档文件的最大数量,超出数量就删除旧文件,假设设置每个月滚动, 且<maxHistory> 是1,则只保存最近1个月的文件,删除之前的旧文件 -->
<MaxHistory>1</MaxHistory>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="consoleApp" />
<appender-ref ref="fileInfoApp" />
<appender-ref ref="fileErrorApp" />
</root>
</configuration>

使用和测试:

package org.dreamtech.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class TestController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @GetMapping("/log")
private Object log() {
logger.debug("test");
logger.info("test");
logger.warn("test");
logger.error("test");
return "log";
}
}

访问localhost:8080/log

会在项目目录生成一个新目录app_log

存在两个文件:一个用来存放ERROR级别信息,一个存放INFO级别和WARN级别

2019-05-11 12:53:53.668 ERROR[http-nio-8080-exec-1]org.dreamtech.demo.controller.TestController.log:18 -test
2019-05-11 12:53:36.264 INFO [main]org.dreamtech.demo.DemoApplication.logStarting:50 -Starting DemoApplication on DESKTOP-59O94TD with PID 14180 (D:\PROJECT\STS_PROJECT\demo\target\classes started by 20235 in D:\PROJECT\STS_PROJECT\demo)
2019-05-11 12:53:36.266 INFO [main]org.dreamtech.demo.DemoApplication.logStartupProfileInfo:675 -No active profile set, falling back to default profiles: default
2019-05-11 12:53:37.019 INFO [main]o.s.boot.web.embedded.tomcat.TomcatWebServer.initialize:90 -Tomcat initialized with port(s): 8080 (http)
2019-05-11 12:53:37.031 INFO [main]org.apache.coyote.http11.Http11NioProtocol.log:173 -Initializing ProtocolHandler ["http-nio-8080"]
2019-05-11 12:53:37.039 INFO [main]org.apache.catalina.core.StandardService.log:173 -Starting service [Tomcat]
2019-05-11 12:53:37.041 INFO [main]org.apache.catalina.core.StandardEngine.log:173 -Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-05-11 12:53:37.122 INFO [main]o.a.catalina.core.ContainerBase.[Tomcat].[localhost].[/].log:173 -Initializing Spring embedded WebApplicationContext
2019-05-11 12:53:37.122 INFO [main]org.springframework.web.context.ContextLoader.prepareWebApplicationContext:296 -Root WebApplicationContext: initialization completed in 824 ms
2019-05-11 12:53:37.289 INFO [main]o.s.scheduling.concurrent.ThreadPoolTaskExecutor.initialize:171 -Initializing ExecutorService 'applicationTaskExecutor'
2019-05-11 12:53:37.413 INFO [main]org.apache.coyote.http11.Http11NioProtocol.log:173 -Starting ProtocolHandler ["http-nio-8080"]
2019-05-11 12:53:37.447 INFO [main]o.s.boot.web.embedded.tomcat.TomcatWebServer.start:204 -Tomcat started on port(s): 8080 (http) with context path ''
2019-05-11 12:53:37.450 INFO [main]org.dreamtech.demo.DemoApplication.logStarted:59 -Started DemoApplication in 1.528 seconds (JVM running for 2.39)
2019-05-11 12:53:53.641 INFO [http-nio-8080-exec-1]o.a.catalina.core.ContainerBase.[Tomcat].[localhost].[/].log:173 -Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-05-11 12:53:53.642 INFO [http-nio-8080-exec-1]org.springframework.web.servlet.DispatcherServlet.initServletBean:524 -Initializing Servlet 'dispatcherServlet'
2019-05-11 12:53:53.650 INFO [http-nio-8080-exec-1]org.springframework.web.servlet.DispatcherServlet.initServletBean:546 -Completed initialization in 8 ms
2019-05-11 12:53:53.668 INFO [http-nio-8080-exec-1]org.dreamtech.demo.controller.TestController.log:16 -test
2019-05-11 12:53:53.668 WARN [http-nio-8080-exec-1]org.dreamtech.demo.controller.TestController.log:17 -test
2019-05-11 12:54:23.513 INFO [RMI TCP Connection(2)-127.0.0.1]o.s.b.a.SpringApplicationAdminMXBeanRegistrar$SpringApplicationAdmin.shutdown:163 -Application shutdown requested.
2019-05-11 12:54:23.515 INFO [RMI TCP Connection(2)-127.0.0.1]o.s.scheduling.concurrent.ThreadPoolTaskExecutor.shutdown:208 -Shutting down ExecutorService 'applicationTaskExecutor'

SpringBoot 2.x (11):定时任务与异步任务的更多相关文章

  1. 【SpringBoot】整合定时任务和异步任务

    ========================10.SpringBoot整合定时任务和异步任务处理 =============================== 1.SpringBoot定时任务s ...

  2. 【SpringBoot】SpringBoot2.x整合定时任务和异步任务处理

    SpringBoot2.x整合定时任务和异步任务处理 一.项目环境 springboot2.x本身已经集成了定时任务模块和异步任务,可以直接使用 二.springboot常用定时任务配置 1.在启动类 ...

  3. SpringBoot2.x整合定时任务和异步任务处理

    SpringBoot2.x整合定时任务和异步任务处理 一.项目环境 springboot2.x本身已经集成了定时任务模块和异步任务,可以直接使用 二.springboot常用定时任务配置 1.在启动类 ...

  4. SpringBoot整合定时任务和异步任务处理

    SpringBoot定时任务schedule讲解 简介:讲解什么是定时任务和常见定时任务区别 1.常见定时任务 Java自带的java.util.Timer类 timer:配置比较麻烦,时间延后问题, ...

  5. SpringBoot整合定时任务和异步任务处理 3节课

    1.SpringBoot定时任务schedule讲解   定时任务应用场景: 简介:讲解什么是定时任务和常见定时任务区别 1.常见定时任务 Java自带的java.util.Timer类        ...

  6. SpringBoot(三) - Slf4j+logback 日志,异步请求,定时任务

    1.Slf4j+logback 日志 SpringBoot框架的默认日志实现:slf4j + logback: 默认日志级别:info,对应了实际生产环境日志级别: 1.1 日志级别 # 常见的日志框 ...

  7. 小D课堂 - 零基础入门SpringBoot2.X到实战_第10节 SpringBoot整合定时任务和异步任务处理_41、SpringBoot定时任务schedule讲解

    笔记 1.SpringBoot定时任务schedule讲解     简介:讲解什么是定时任务和常见定时任务区别 1.常见定时任务 Java自带的java.util.Timer类            ...

  8. SpringBoot的四种定时任务

    定时任务实现的几种方式: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务. 使用这种方式可以让你的程序按照某一个频度执行 ...

  9. 【SpringBoot】几种定时任务的实现方式

    SpringBoot 几种定时任务的实现方式 Wan QingHua 架构之路  定时任务实现的几种方式: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java ...

随机推荐

  1. LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal

    原题链接在这里:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/ 题 ...

  2. pycharm常用快捷键和自定义快捷键

     默认快捷键 编辑类: Ctrl + Space 基本的代码完成(类.方法.属性)Ctrl + Alt + Space 类名完成Ctrl + Shift + Enter 语句完成Ctrl + P 参数 ...

  3. DLL的远程注入技术

    DLL的远程注入技术是目前Win32病毒广泛使用的一种技术.使用这种技术的病毒体通常位于一个DLL中,在系统启动的时候,一个EXE程序会将这个DLL加载至某些系统进程(如Explorer.exe)中运 ...

  4. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  5. Robot Framework基础学习(一)

    Robot Framework语法学习: 一.变量的声明.赋值与使用 1.变量标识符:每个变量都可以用  变量标识符 ${变量名} 来表示. 2.变量声明:可以在TestSuite上点右键或者在Edi ...

  6. 7.11实习培训日志-Git Linux

    Git git子模块 先在GitHub创建两个空的respository,一个super_project和一个sub_project. 然后在git bash中向库中写入一些文件. 在super_pr ...

  7. Swift3.0 Alamofire网络请求的封装(get,post,upload图片上传)转

    转自: http://blog.csdn.net/C_calary/article/details/53193747 学习Swift 试着动手写个天气小app,搜集资料这个封装还蛮好用的. 我用的第三 ...

  8. P5137 polynomial(分治)

    传送门 神仙--这题有毒-- 一直在那里考虑没有逆元怎么办然后考虑解exgcd巴拉巴拉 最后只好看题解了 而且这题龟速乘都不行--得用代码里那种叫人半懂不懂的方式取模-- //minamoto #in ...

  9. 海思3559A QT 5.12移植(带webengine 和 opengl es)

    海思SDK版本:Hi3559AV100_SDK_V2.0.1.0 编译器版本:aarch64-himix100-linux-gcc 6.3.0(这个版本有点小问题,使用前需要先清除本地化设置) $ e ...

  10. MyBatist庖丁解牛(一)

    站在巨人的肩膀上,感谢! https://www.jianshu.com/p/ec40a82cae28?utm_campaign=maleskine&utm_content=note& ...