SpringBoot实现定时任务和异步调用

本文实例为大家分享了SpringBoot实现定时任务和异步调用的具体代码,供大家参考,具体内容如下

环境:

jdk1.8;spring boot2.0.2;Maven3.3

摘要说明:

定时任务:定时任务是业务场景中经常出现的一种情况如:定时发送邮件,短信、定时统计监控数据、定时对账等

异步调用:一个都买流程可能包括下单、发货通知、短信推送、消息推送等,其实除了下单这个主要程序是主程序,其他子程序可以同时进行且不影响主程序的运行,这个时候就可以使用异步调用来调用这些子程序;

步骤:

1.定时任务

a.在spring boot主类上使用注解@EnableScheduling启动定时任务:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

//启动定时任务
@EnableScheduling
@SpringBootApplication
public class DemoApplication {

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

b.实现定时任务(使用@Component注解来标注组件)

 /**
 * @模块名:demo
 * @包名:com.example.demo.test1.component
 * @描述:SchedulingComponent.java
 * @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日上午10:19:37
 */

package com.example.demo.test1.component;

import java.util.Date;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * @模块名:demo
 * @包名:com.example.demo.test1.component @类名称: SchedulingComponent
 * @类描述:【类描述】用于测试定时任务 @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日上午10:19:37
 */
@Component
public class SchedulingComponent {

 /**
 *
 * @方法名:testScheduling1
 * @方法描述【方法功能描述】测试定时任务,没三秒执行一次
 * @修改描述【修改描述】
 * @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日 上午10:26:20
 * @修改人:cc
 * @修改时间:2018年9月29日 上午10:26:20
 */
 @Scheduled(fixedRate = 3000)
 public void testScheduling1() {

 System.out.println("执行时间为"+new Date()+"执行testScheduling1");
 }
}
@Scheduled注解和之前spring使用xml配置定时任务类似:

@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则

c.上述方法写好后启动服务看下控制台结果:

2.异步调用

a.首先在spring boot主类上使用注解@EnableAsync启动异步调用

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

//启动异步调用
@EnableAsync
@SpringBootApplication
public class DemoApplication {

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

b.sping boot异步调用很简单,只需使用@Async注解标明方法(接口方法)异步

package com.example.demo.test1.component;

public interface TaskComponent {
 void test1() throws Exception;

 void test2() throws Exception;

 void test3() throws Exception;
}
package com.example.demo.test1.component.impl;

import java.util.Random;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.example.demo.test1.component.TaskComponent;

@Component
public class TaskComponentImpl implements TaskComponent {
 public static Random random = new Random();

 @Override
 @Async
 public void test1() throws InterruptedException {
 System.out.println("开始做任务一");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");

 }

 @Override
 @Async
 public void test2() throws InterruptedException {
 System.out.println("开始做任务二");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");

 }

 @Override
 @Async
 public void test3() throws InterruptedException {
 System.out.println("开始做任务三");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");

 }

}

c.使用测试类进行测试:

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.demo.test1.component.TaskComponent;

@RunWith(SpringRunner.class)
// 引入SpringBootTest并生成随机接口
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AsyncTest {

 // 注入随机接口
 @LocalServerPort
 private int port;

 @Autowired
 private TaskComponent taskComponent;

 @Test
 public void testTask() {
 try {
 taskComponent.test1();
 taskComponent.test2();
 taskComponent.test3();
 System.out.println("执行主线程");
 // 主线程休眠10秒等待上述异步方法执行
 Thread.sleep(10000);
 }
 catch (Exception e) {
 System.out.println(e);
 }

 }
}

执行结果如下;可以看出三个异步方法互不影响,且不影响主线程的运行

执行主线程
开始做任务一
开始做任务二
开始做任务三
完成任务一,耗时:1401毫秒
完成任务二,耗时:4284毫秒
完成任务三,耗时:5068毫秒

d.对于这些异步执行的调用往往会给我们带来思考是不是异步调用越多越好,答案当然是否;所以在这里引入线程池来进行异步调用控制:

在spring boot主类上标注线程池:

package com.example.demo;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

//启动定时任务

@EnableScheduling
@SpringBootApplication
public class DemoApplication {

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

 // 启动异步调用
 @EnableAsync
 @Configuration
 class TaskPoolConfig {
 // 核心线程数(setCorePoolSize)10:线程池创建时候初始化的线程数
 // 最大线程数(setMaxPoolSize)20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
 // 缓冲队列(setQueueCapacity)200:用来缓冲执行任务的队列
 // 允许线程的空闲时间(setKeepAliveSeconds)60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
 // 线程池名的前缀(setThreadNamePrefix):设置好了之后可以方便我们定位处理任务所在的线程池
 // 线程池对拒绝任务的处理策略(setRejectedExecutionHandler):这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute
 // 方法的调用线程中运行被拒绝的任务(setWaitForTasksToCompleteOnShutdown);如果执行程序已关闭,则会丢弃该任务
 // setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁。
 // 同时,这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
 @Bean("taskExecutor")
 public Executor taskExecutor() {
 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 executor.setCorePoolSize(10);
 executor.setMaxPoolSize(20);
 executor.setQueueCapacity(200);
 executor.setKeepAliveSeconds(60);
 executor.setThreadNamePrefix("taskExecutor-");
 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
 executor.setWaitForTasksToCompleteOnShutdown(true);
 executor.setAwaitTerminationSeconds(60);
 return executor;
 }
 }
}

在方法实现类上使用@Async的同时标注线程池:

package com.example.demo.test1.component.impl;

import java.util.Random;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.example.demo.test1.component.TaskComponent;

@Component
public class TaskComponentImpl implements TaskComponent {
 public static Random random = new Random();

 @Override
 @Async("taskExecutor")
 public void test1() throws InterruptedException {
 System.out.println("开始做任务一");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");

 }

 @Override
 @Async("taskExecutor")
 public void test2() throws InterruptedException {
 System.out.println("开始做任务二");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");

 }

 @Override
 @Async("taskExecutor")
 public void test3() throws InterruptedException {
 System.out.println("开始做任务三");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");

 }

}

再次调用测试来发现结果没什么区别:

执行主线程
开始做任务一
开始做任务二
开始做任务三
完成任务一,耗时:1117毫秒
完成任务二,耗时:3964毫秒
完成任务三,耗时:8886毫秒

接着我们修改线程池线程数为2:

executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);

再次启动测试类可以看到,同时执行的线程数为2,只有等待前一个线程结束才能执行一个新的线程;

执行主线程
开始做任务一
开始做任务二
完成任务二,耗时:620毫秒
开始做任务三
完成任务一,耗时:2930毫秒
完成任务三,耗时:4506毫秒

3.demo地址:链接地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springboot集成schedule实现定时任务

    背景 在项目开发过程中,我们经常需要执行具有周期性的任务.通过定时任务可以很好的帮助我们实现. 我们拿常用的几种定时任务框架做一个比较: 从以上表格可以看出,Spring Schedule框架功能完善,简单易用.对于中小型项目需求,Spring Schedule是完全可以胜任的. 1.springboot集成schedule 1.1 添加maven依赖包 由于Spring Schedule包含在spring-boot-starter基础模块中了,所有不需要增加额外的依赖. <dependenci

  • SpringBoot 定时任务遇到的坑

    前言 springboot已经支持了定时任务Schedule模块,一般情况已经完全能够满足我们的实际需求.今天就记录一下我使用 schedule 时候踩的坑吧. 想要使用定时,我们首先要开启支持,其实就是在启动类上面加个注解就 Ok. @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(A

  • springboot 异步调用的实现方法

    说异步调用前,我们说说它对应的同步调用.通常开发过程中,一般上我们都是同步调用,即:程序按定义的顺序依次执行的过程,每一行代码执行过程必须等待上一行代码执行完毕后才执行.而异步调用指:程序在执行时,无需等待执行的返回值可继续执行后面的代码.显而易见,同步有依赖相关性,而异步没有,所以异步可并发执行,可提高执行效率,在相同的时间做更多的事情. 同步 程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回. 异步 程

  • 详解SpringBoot定时任务说明

    1. 定时任务实现方式 定时任务实现方式: Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行.一般用的较少,这篇文章将不做详细介绍. 使用Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂,有空介绍. SpringBoot自带的Scheduled,可以将它看成一个轻量级的Quartz,而且使用起来比Q

  • SpringBoot定时任务两种(Spring Schedule 与 Quartz 整合 )实现方法

    前言 最近在项目中使用到定时任务,之前一直都是使用Quartz 来实现,最近看Spring 基础发现其实Spring 提供 Spring Schedule 可以帮助我们实现简单的定时任务功能. 下面说一下两种方式在Spring Boot 项目中的使用. Spring Schedule 实现定时任务 Spring Schedule 实现定时任务有两种方式 1. 使用XML配置定时任务, 2. 使用 @Scheduled 注解. 因为是Spring Boot 项目 可能尽量避免使用XML配置的形式,

  • Springboot整个Quartz实现动态定时任务的示例代码

    简介 Quartz是一款功能强大的任务调度器,可以实现较为复杂的调度功能,如每月一号执行.每天凌晨执行.每周五执行等等,还支持分布式调度.本文使用Springboot+Mybatis+Quartz实现对定时任务的增.删.改.查.启用.停用等功能.并把定时任务持久化到数据库以及支持集群. Quartz的3个基本要素 Scheduler:调度器.所有的调度都是由它控制. Trigger: 触发器.决定什么时候来执行任务. JobDetail & Job: JobDetail定义的是任务数据,而真正的

  • 详解SpringBoot 创建定时任务(配合数据库动态执行)

    序言:创建定时任务非常简单,主要有两种创建方式:一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就大派用场了. 一.静态定时任务(基于注解) 基于注解来创建定时任务非常简单,只需几行代码便可完成. @Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应

  • springboot整合quartz实现定时任务示例

    在做项目时有时候会有定时器任务的功能,比如某某时间应该做什么,多少秒应该怎么样之类的. spring支持多种定时任务的实现.我们来介绍下使用spring的定时器和使用quartz定时器 1.我们使用spring-boot作为基础框架,其理念为零配置文件,所有的配置都是基于注解和暴露bean的方式. 2.使用spring的定时器: spring自带支持定时器的任务实现.其可通过简单配置来使用到简单的定时任务. @Component @Configurable @EnableScheduling p

  • 详解SpringBoot中异步请求和异步调用(看完这一篇就够了)

    一.SpringBoot中异步请求的使用 1.异步请求与同步请求 特点: 可以先释放容器分配给请求的线程与相关资源,减轻系统负担,释放了容器所分配线程的请求,其响应将被延后,可以在耗时处理完成(例如长时间的运算)时再对客户端进行响应.一句话:增加了服务器对客户端请求的吞吐量(实际生产上我们用的比较少,如果并发请求量很大的情况下,我们会通过nginx把请求负载到集群服务的各个节点上来分摊请求压力,当然还可以通过消息队列来做请求的缓冲). 2.异步请求的实现 方式一:Servlet方式实现异步请求

  • springboot整合Quartz实现动态配置定时任务的方法

    前言 在我们日常的开发中,很多时候,定时任务都不是写死的,而是写到数据库中,从而实现定时任务的动态配置,下面就通过一个简单的示例,来实现这个功能. 一.新建一个springboot工程,并添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency

随机推荐