Quartz定时任务

定时任务

Java实现定时任务的方式

一、线程等待(不建议使用,任务复杂时存在内存泄露风险)

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

package com.changan.test;
​
import java.util.Timer;
import java.util.TimerTask;
​
public class Main {
    public static void main(String[] args) {
        /*Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("执行定时任务");
            }
        },1000,1000);*/
​
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("TimerTask is called!");
            }
        };
​
        Timer timer = new Timer();
        /*
         * schedule 和 scheduleAtFixedRate 区别:
         *  可将schedule理解为scheduleAtFixedDelay,
         *  两者主要区别在于delay和rate
         *  1、schedule,如果第一次执行被延时(delay),
         *      随后的任务执行时间将以上一次任务实际执行完成的时间为准
         *  2、scheduleAtFixedRate,如果第一次执行被延时(delay),
         *      随后的任务执行时间将以上一次任务开始执行的时间为准(需考虑同步)
         *
         *  参数:1、任务体    2、延时时间(可以指定执行日期)3、任务执行间隔时间
         */
        // timer.schedule(task, 0, 1000 * 3);
        timer.scheduleAtFixedRate(task, 0, 1000 * 3);
    }
}

三、ScheduledExecutorService

package com.changan.test;
​
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
​
public class Main {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println("ScheduledExecutorService Task is called!");
            }
        };
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        // 参数:1、任务体 2、首次执行的延时时间
        //      3、任务执行间隔 4、间隔时间单位
        service.scheduleAtFixedRate(runnable, 0, 3, TimeUnit.SECONDS);
    }
}

四、@Scheduled

1、配置

在spring boot的启动类上加@EnableScheduling注解,允许支持@Scheduled:

@SpringBootApplication
@EnableScheduling         //开启定时任务
public class Quartz01Application {
​
    public static void main(String[] args) {
        SpringApplication.run(Quartz01Application.class, args);
    }
}

2、任务类

@Component
public class ScheduleTask {
​
    // 每隔5秒执行一次
    @Scheduled(cron = "0/5 * * * * ?")
    public void printSay() {
        System.out.println("每隔5秒执行一次:" + new Date());
    }
}

Quartz

一、Quartz介绍

quartz是一种基于java实现的任务调度框架,可以定时自动的执行你想要执行的任何任务。

quartz官网:Quartz Enterprise Job Scheduler

二、Quartz的组成

任务Job(你要做什么事? 将要执行的操作)

job就是你想要实现的任务类,每一个job必须实现org.quartz.job接口。

触发器Trigger(你什么时候去做? cron表达式)

Trigger为你执行任务的触发器,比如你想每天定时3点发送一份统计邮件,Trigger将会设置3点进行执行该任务。

调度器Scheduler(你什么时候需要做什么事?)

Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job。

三、使用java实现一个简单的Quartz例子

1、新建一个maven项目,并引入Quartz依赖 https://mvnrepository.com/search?q=quartz

<dependencies>
    <!--核心包-->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.2</version>
    </dependency>
    <!--工具-->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz-jobs</artifactId>
        <version>2.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.7</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

2、编写一个Job类,用来编写定时任务要做什么

package com.changan.test.service;
​
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);
    }
}

3、编写触发器和调度器

package com.changan.test;
​
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();
    }
}

四、使用Springboot整合Quartz定时任务框架

1.pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
​
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2、 job类

package com.changan.service;
​
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
​
import java.util.Date;
​
    public class QuartzDemo implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("Execute..."+new Date());
    }
}

3、配置类,配置触发器与任务调度器

package com.changan.config;
​
import com.changan.service.QuartzDemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
​
/**
 * Quartz配置类
 */
@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 SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();
        //关联JobDetail对象
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //该参数表示一个执行的毫秒数
        factoryBean.setRepeatInterval(2000); //每隔2秒执行一次
        //重复次数
        factoryBean.setRepeatCount(5);
        return factoryBean;
    }
​
    /**
     * 3、创建Scheduler
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){
        SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
        //关联trigger
        factoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
        return factoryBean;
    }
}

4、启动类

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

五、使用Springboot+mybatis整合Quartz定时任务框架实现定时向数据库插入一条数据

QuartzDemo

package com.changan.service;
​
import com.changan.entity.User;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
​
import java.util.Date;
​
public class QuartzDemo implements Job {
​
    @Autowired
    private UserService userService;
​
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        User user = new User();
        user.setEmail("123123");
        user.setAge(12);
        user.setName("456");
        userService.save(user);
    }
}

因此我们需要手动的把QuartzDemoJob类注入到SpringIOC容器中。

编写一个类MyAdaptableJobFactory继承AdaptableJobFactory,覆盖createJobInstance()方法。

MyadaptableJobFactory

package com.changan.config;
​
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;
    }
}

QuartzConfig

package com.changan.config;
​
import com.changan.service.QuartzDemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
​
/**
 * Quartz配置类
 */
@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 SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();
        //关联JobDetail对象
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        //该参数表示一个执行的毫秒数
        factoryBean.setRepeatInterval(2000); //每隔2秒执行一次
        //重复次数
        factoryBean.setRepeatCount(5);
        return factoryBean;
    }
​
    /**
     * 3、创建Scheduler
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){
        SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
        //关联trigger
        factoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
        factoryBean.setJobFactory(myadaptableJobFactory);
        return factoryBean;
    }
}

CronExpression表达式

格式:[秒] [分] [时] [每月的第几日] [月] [每周的第几日] [年]

字段名必须的允许值允许的特殊字符
SecondsYES0-59, - * /
MinutesYES0-59, - * /
HoursYES0-23, - * /
Day of monthYES1-31, - * ? / L W
MonthYES1-12 or JAN-DEC, - * /
Day of weekYES1-7 or SUN-SAT, - * ? / L #
YearNOempty, 1970-2099, - * /

注意:有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推

特殊字符说明:

字符含义
*用于 指定字段中的所有值。比如:* 在分钟中表示 每一分钟
?用于 指定日期中的某一天,或是 星期中的某一个星期
-用于 指定范围。比如:10-12 在小时中表示 10 点,11 点,12 点
,用于 指定额外的值。比如:MON,WED,FRI 在日期中表示 星期一, 星期三, 星期五
/用于 指定增量。比如:0/15 在秒中表示 0 秒, 15 秒, 30 秒, 45 秒5/15 在秒中表示 5 秒,20 秒,35 秒,50 秒
L在两个字段中拥有不同的含义。比如:L 在日期(Day of month)表示 某月的最后一天。在星期(Day of week)只表示 7SAT。但是,值L 在星期(Day of week)中表示 某月的最后一个星期几。比如:6L 表示 某月的最后一个星期五。也可以在日期(Day of month)中指定一个偏移量(从该月的最后一天开始).比如:L-3 表示 某月的倒数第三天
W用于指定工作日(星期一到星期五)比如:15W 在日期中表示 到 15 号的最近一个工作日。如果第十五号是周六, 那么触发器的触发在 第十四号星期五。如果第十五号是星期日,触发器的触发在 第十六号周一。如果第十五是星期二,那么它就会工作开始在 第十五号周二。然而,如果指定 1W 并且第一号是星期六,那么触发器的触发在第三号周一,因为它不会 "jump" 过一个月的日子的边界。
LW可以在日期(day-of-month)合使用,表示 月份的最后一个工作日
#用于 指定月份中的第几天。比如:6#3 表示 月份的第三个星期五(day 6 = Friday and "#3" = the 3rd one in the month)。其它的有,`2#1 表示 月份第一个星期一4#5 表示 月份第五个星期三。注意: 如果只是指定 #5,则触发器在月份中不会触发。`

注意:字符不区分大小写,MONmon 相同。

cronExpression 示例

表达式含义
0 0 12 * * ?每天中午 12 点
0 15 10 ? * *每天上午 10 点 15 分
0 15 10 * * ?每天上午 10 点 15 分
0 15 10 * * ? *每天上午 10 点 15 分
0 15 10 * * ? 2005在 2005 年里的每天上午 10 点 15 分
0 * 14 * * ?每天下午 2 点到下午 2 点 59 分的每一分钟
0 0/5 14 * * ?每天下午 2 点到 2 点 55 分每隔 5 分钟
0 0/5 14,18 * * ?每天下午 2 点到 2 点 55 分, 下午 6 点到 6 点 55 分, 每隔 5 分钟
0 0-5 14 * * ?每天下午 2 点到 2 点 5 分的每一分钟
0 10,44 14 ? 3 WED3 月每周三的下午 2 点 10 分和下午 2 点 44 分
0 15 10 ? * MON-FRI每周一到周五的上午 10 点 15 分
0 15 10 15 * ?每月 15 号的上午 10 点 15 分
0 15 10 L * ?每月最后一天的上午 10 点 15 分
0 15 10 L-2 * ?每月最后两天的上午10点15分
0 15 10 ? * 6L每月的最后一个星期五的上午 10 点 15 分
0 15 10 ? * 6L 2002-20052002 年到 2005 年每个月的最后一个星期五的上午 10 点 15 分
0 15 10 ? * 6#3每月的第三个星期五的上午 10 点 15 分
0 0 12 1/5 * ?每月的 1 号开始每隔 5 天的中午 12 点
0 11 11 11 11 ?每年 11 月 11 号上午 11 点 11 分
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值