Java中的任务调度框架quartz详细解析

 更新时间:2023年11月13日 09:40:07   作者:小申ee  
这篇文章主要介绍了Java中的任务调度框架quartz详细解析,Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制,需要的朋友可以参考下

一、Quartz相关介绍

1.简介  

  1. Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。  
  2. Quartz 可以与 J2EE 与 J2SE 应用程序相结合也可以单独使用。  
  3.  Quartz 允许程序开发人员根据时间的间隔来调度作业。  
  4. Quartz 实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。

2.Quartz 核心概念  

我们需要明白 Quartz 的几个核心概念,这样理解起 Quartz 的原理就会变得简单了。  

  1. Job 表示一个工作,要执行的具体内容。此接口中只有一个方法:void execute(JobExecutionContext context)
  2. JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。  
  3. Trigger 代表一个调度参数的配置,什么时候去调。  
  4. Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

项目层级

在这里插入图片描述

常见的几种定时方法

线程休眠

先讲个故事

一名程序员网友发帖晒出了自己写的一段代码,是一段定时代码,根据他的语气,可以看出他对自己写的代码感觉很好,是一段java代码,好家伙,代码中多线程都用上了,还有sleep,然后自己这样写了就直接被老板赶走了,走之前为了面子还说到,你这公司我还看不上呢,其实一想写的确实没问题功能能实现,但是

Java线程实现采用内核线程实现,线程的休眠及唤醒(状态切换)需借助操作系统进行,这是一个极其耗时耗力的操作。在线程休眠或运行时间较长的情景下,其对性能的影响还不算明显,因为对线程状态的切换并不频繁。但若线程休眠及运行的时间都很短(例如毫秒/秒,文中案例就是一个典型案例),系统将频繁的对线程状态进行切换,导致严重的性能损耗,并对着循环次数的递增而放大。

所以是不推荐使用的!

/***
 * 使用线程休眠实现定时任务,这种写法是不建议写的
 */
public class Task01 {
    public static void main(String[] args) {
        Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("TestThreadWait is called!");
                    try {
                        // 使用线程休眠来实现周期执行
                        Thread.sleep(1000 * 3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        myThread.start();
    }
}

Timer

/***
 * 延时任务
 */
public class Task02 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        /***
         * 参数一:需要执行的任务
         * 参数二:延迟多久   参数二不加只会执行一次=定时任务
         * 参数三,执行的频率
         */
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("使用timer实现定时任务");
            }
        }, 0,1000);
    }
}

通过ScheduledExecutorService实现定时任务

package com.changan.test;

import com.sun.org.apache.bcel.internal.generic.NEW;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @program: springcloudalibaba
 * @description:
 * @author: Mr.shen
 * @create: 2022-06-27 09:35
 **/
public class Task03 {
    public static void main(String[] args) {
        Runnable runnable= new Runnable() {
            @Override
            public void run() {
                System.out.println("通过ScheduledExecutorService实现定时任务");
            }
        };
        ScheduledExecutorService service= Executors.newSingleThreadScheduledExecutor();
        service.scheduleAtFixedRate(runnable,1,2, TimeUnit.SECONDS);
    }
}

进阶

quartz(编写触发器和调度器 )

package com.changan.test;

/**
 * @program: springcloudalibaba
 * @description: 编写触发器和调度器
 * @author: Mr.shen
 * @create: 2022-06-27 10:28
 **/
import com.changan.job.HelloJob;
//import com.changan.test.service.HelloJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws Exception{
        //1、调度器(Schedular),从工厂中获取调度实例(默认:实例化new StdSchedulerFactory();)
        Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
        //2、任务实例(JobDetail)
        JobDetail jobDetail= JobBuilder.newJob(HelloJob.class) //加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
                .withIdentity("job1","group1") //参数1:任务的名称(唯一实例);参数2:任务组的名称
                .build();
        //3、触发器(Trigger)
        Trigger trigger= TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1") //参数1:触发器的名称(唯一实例);参数2:触发器组的名称
                .startNow() //马上启动触发器
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)) //每5秒执行一次
                .build();
        //让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail,trigger);
        //启动
        scheduler.start();
    }
}

job

package com.changan.job;

/**
 * @program: springcloudalibaba
 * @description: 编写一个Job类,用来编写定时任务要做什么
 * @author: Mr.shen
 * @create: 2022-06-27 10:25
 **/
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HelloJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出当前时间
        Date date=new Date();
        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString=dateFormat.format(date);
        //工作内容
        System.out.println("执行定时任务,时间是:"+dateString);
    }
}

高阶(使用springboot整合quartz并插入一条数据进入数据库)

下面也需要用到CronExpression表达式

yaml

server:
  port: 8085
spring:
  application:
    name: quartz-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tcw?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
    username: root
    password: 123456


mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #??????
    map-underscore-to-camel-case: true    #??????? ????????create_time?????_??
  mapper-locations: classpath*:/mapper/*Mapper.xml  #????
  type-aliases-package: com.changan.entity  #??
  • pom.xml
    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-quartz</artifactId>        </dependency>        <!-- mybatis-plus-->        <dependency>            <groupId>com.baomidou</groupId>            <artifactId>mybatis-plus-boot-starter</artifactId>            <version>3.5.1</version>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <scope>runtime</scope>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>        </dependency>    </dependencies>
  • 启动器
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <!-- mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
  • Quartz配置类
package com.changan.config;

import com.changan.adapter.MyadaptableJobFactory;
import com.changan.job.QuartzDemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

/**
 * @program: springcloudalibaba
 * @description: Quartz配置类
 * @author: Mr.shen
 * @create: 2022-06-27 10:54
 **/
@Configuration
public class QuartzConfig {
    /**
     * 1、创建Job对象
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
        //关联我们自己的Job类
        factoryBean.setJobClass(QuartzDemo.class); //就是触发这个定时任务执行的任务
        return factoryBean;
    }

    /**
     * 2、创建Trigger对象
     */
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        CronTriggerFactoryBean factoryBean=new CronTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());//将任务代进去
        factoryBean.setCronExpression("0/5 * * * * ?");//设置任务触发条件 CronExpression表达式
        return factoryBean;
    }

    /**
     * 3、创建Scheduler
     * 实现调度任务的配置
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){
        SchedulerFactoryBean  factoryBean=new SchedulerFactoryBean();

        factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
        factoryBean.setJobFactory(myadaptableJobFactory);
        return factoryBean;
    }
}

  • Job类(就是你时间到了触发的方法)
	package com.changan.job;

import com.changan.entity.User;
import com.changan.service.Userservice;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

/**
 * @program: springcloudalibaba
 * @description: job类
 * @author: Mr.shen
 * @create: 2022-06-27 10:40
 **/
public class QuartzDemo implements Job {

    @Autowired
    private Userservice userService;
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        User user = new User();
        user.setAge(12);
        user.setHead("dwwd");
        user.setManager(123);
        user.setSex("dw");
        user.setUpwd("wdwdw");
 user.setUname("111");
        System.out.println(userService.userinsert(user));
        System.out.println("Execute..."+new Date());
    }
}

做完这些操作之后你运行插入你会发现Userservice并没有注入bean 就算加service也不行下面就需要一个配置类了

  • MyadaptableJobFactory(注入对象)
package com.changan.adapter;

/**
 * @program: springcloudalibaba
 * @description: 编写一个类MyAdaptableJobFactory继承AdaptableJobFactory,覆盖createJobInstance()方法。
 * @author: Mr.shen
 * @create: 2022-06-27 10:54
 **/
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component("myadaptableJobFactory")  //将该类实例化,使得可以直接用
public class MyadaptableJobFactory extends AdaptableJobFactory {
    //AutowireCapableBeanFactory可以将一个对象添加到Spring IOC容器中,并且完成该对象注入
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    //该方法将实例化的任务对象手动的添加到SpringIOC容器中并且完成对象的注入
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object object = super.createJobInstance(bundle);
        //将object对象添加到Spring IOC容器中并完成注入
        this.autowireCapableBeanFactory.autowireBean(object);
        return object;
    }
}

到此这篇关于Java中的任务调度框架quartz详细解析的文章就介绍到这了,更多相关Java任务调度框架quartz内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Java动态代理的实现机制

    详解Java动态代理的实现机制

    这篇文章主要为大家详细介绍了Java动态代理的实现机制,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • 使用SpringEvent解决WebUploader大文件上传解耦问题

    使用SpringEvent解决WebUploader大文件上传解耦问题

    Spring Event是Spring框架内建的一种发布/订阅模式的实现,它允许应用内部不同组件之间通过事件进行通信,本文以WebUploader大文件上传组件为例,在大文件处理的场景中使用SpringEvent的事件发布机制,灵活的扩展对文件的处理需求,需要的朋友可以参考下
    2024-07-07
  • SpringBoot实现多数据源配置的示例详解

    SpringBoot实现多数据源配置的示例详解

    这篇文章主要为大家详细介绍了SpringBoot实现多数据源配置的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-12-12
  • 关于Android触摸事件分发的原理详析

    关于Android触摸事件分发的原理详析

    触摸事件分发机制一直以来都是Android中比较重要的一大块,自定义view,各种复杂的自定义手势交互都与触摸事件分发机制关系密,下面这篇文章主要给大家介绍了关于Android触摸事件分发原理的相关资料,需要的朋友可以参考下
    2022-01-01
  • Java随机值设置(java.util.Random类或Math.random方法)

    Java随机值设置(java.util.Random类或Math.random方法)

    在编程中有时我们需要生成一些随机的字符串作为授权码、验证码等,以确保数据的安全性和唯一性,这篇文章主要给大家介绍了关于Java随机值设置的相关资料,主要用的是java.util.Random类或Math.random()方法,需要的朋友可以参考下
    2024-08-08
  • redisson分布式限流RRateLimiter源码解析

    redisson分布式限流RRateLimiter源码解析

    这篇文章主要为大家介绍了redisson分布式限流RRateLimiter源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Java中的Kafka为什么性能这么快及4大核心详析

    Java中的Kafka为什么性能这么快及4大核心详析

    这篇文章主要介绍了Java中的Kafka为什么性能这么快及4大核心详析,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • java中Path和ClassPath用法比较

    java中Path和ClassPath用法比较

    在本篇文章里小编给大家分享了关于java中Path和ClassPath用法比较内容,有需要的朋友们学习下。
    2019-01-01
  • 深入理解Java多线程与并发编程

    深入理解Java多线程与并发编程

    这篇文章主要介绍了Java多线程与并发编程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能

    JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能

    这篇文章主要介绍了JAVA实现 SpringMVC方式的微信接入、实现简单的自动回复功能的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-11-11

最新评论