• Quartz定时任务


    一、Quartz简介
    二、Quartz使用
    三、Trigger(重 点)
    四、Job并发(重点)
    五、Spring整合Quartz (重点)
    六、持久化
    七、springboot整合 自带的quartz

    版本:

    Quartz 2.2.3

    官网链接

    一、Quartz简介

    1.1、简介

    Quartz是一个任务调度框架。比如你遇到这样的问题
    想每月29号,信用卡自动还款
    想每年4月1日自己给当年暗恋女神发一封匿名贺卡
    想每隔1小时,备份一下自己的学习笔记
    
    这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。
    Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活
    如果应用程序需要在给定时间执行任务,或者如果系统有连续维护作业,那么Quartz是理想的解决方案。
    

    1.2、特点

    1.2.1、作业调度

    作业被安排在-个给定的触发时运行。触发器可以使用以下指令的组合来创建:
    
    在一天中的某个时间(到毫秒)
    在一周的某几天
    在每月的某一天
    在一年中的某些日期
    不在注册的日历中列出的特定日期(如商业节假日除外)
    重复特定次数
    重复进行,直到一个特定的时间/日期
    无限重复
    重复的延迟时间间隔
    

    1.2.2、作业持久性

    Quartz的设计包括一个作业存储接口,有多种实现。
    通过使用包含的JDBCJobStore,所有的作业和触发器配置为“非挥发性"都存储在通过JDBC关系数据库。
    通过使用包含的RAMJobStore,所有的作业和触发器存储在RAM,因此不计划执行仍然存在 - 但这是无需使用外部数据库的优势。
    

    二、Quartz使用

    2.1、导入依赖

     <!--Quartz任务调度-->
        <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
          <version>2.2.3</version>
        </dependency>
    

    2.2、定义Job

    @DisallowConcurrentExecution
    public class MyJob implements Job{
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            //创建工作详情
            JobDetail jobDetail=context.getJobDetail();
            //获取工作的名称
            String name = jobDetail.getKey().getName();//任务名
            String group = jobDetail.getKey().getGroup();//任务group
            String job=jobDetail.getJobDataMap().getString("data04");//任务中的数据
            System.out.println("job执行,job名:"+name+" group:"+group+new Date()+job);//这里是我们最终要定时的任务
        }
    }
    

    2.3、API测试

    package com.xibei.test;
    
    
    import com.xibei.job.MyJob;
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    
    import static org.quartz.DateBuilder.*;
    
    public class TestQuartz {
        public static void main(String[] args) throws SchedulerException, InterruptedException {
            testSimpleTrigger();
        }
    
    
        public static void testSimpleTrigger() throws SchedulerException, InterruptedException {
            // 1. 创建scheduler,调度器  核心组件
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            // 2. 定义一个Trigger,创建触发器:Trigger
            /*Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1") //定义触发器name/group
                    .startNow()//一旦加入scheduler,立即生效,即开始时间
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(2)//每隔2秒执行一次
                            .withRepeatCount(2))//一共执行几次
                    .build();*/
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1") //定义name/group
                    .startNow()//一旦加入scheduler,立即生效,即开始时间
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(2)
                            .repeatForever())//一直执行下去
                    //.endAt(new GregorianCalendar(2019,9,19,9,59,10).getTime())//设置最终停止时间
                    .build();
    
            // 3. 创建JobDetail,JobBuilder(任务)
            JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                    .withIdentity("job04", "group04")//任务的名字和组
                    .usingJobData("data04", "hello world~~")//任务中的数据和值
                    .build();
            // 4. 注册 JobDetail 和 Trigger
            scheduler.scheduleJob(jobDetail, trigger);//将任务和触发器注册到调度器
            // 5. 启动调度器, 内部注册的所有触发器开始计时
            scheduler.start();
            // 6.关闭调度器
            Thread.sleep(10000);//用线程睡眠来操作调度器运行的时间
            scheduler.shutdown();
        }
    }
    

    2.4、配置

    # 指定调度器名称,非实现类
    org.quartz.scheduler.instanceName = DefaultQuartzScheduler04
    # 指定线程池实现类
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    # 线程池线程数量
    org.quartz.threadPool.threadCount = 15
    # 优先级,默认5
    org.quartz.threadPool.threadPriority = 5
    # 非持久化job
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    

    2.5、核心类说明

    Scheduler:调度器。所有的调度都是由它控制
    	Scheduler就是Quartz的大脑,所有任务都是由它来设施
    	Schduelr包含一个两个重要组件: JobStore和ThreadPool
    		JobStore是会来存储运行时信息的,包括Trigger ,Schduler , JobDetail,业务锁等
    		ThreadPool就是线程池,Quartz有 自己的线程池实现。所有任务的都会由线程池执行
    
    SchdulerFactory,顾名思义就是来用创建Schduler了,有两个实现: DirectSchedulerFactory和StdSchdulerFactory。 前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz .properties (不存 在就都使用默认值)配置来实例化Schduler。通常来讲,我们使用StdSchdulerF actory也就足够了。
    SchdulerFactory本身是支持创建RMI stub的, 可以用来管理远程的Scheduler,功能与本地一样
    

    三、Trigger(重点)

    3.1 、SimpleTrigger

    指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。
    它适合的任务类似于: 9:00开始,每隔1小时,执行一次。
    它的属性有:
    	repeatInterval重复间隔
    	repeatCount重复次数。实际执行次数是repeatCount+1。 因为在startTime的时候一定会执行一次。
    

    示例:

    SimpleScheduleBuilder.simpleSchedule().
    					withIntervalInSeconds(10).//每隔10秒执行-次
    					repeatForever().//永远执行
    					build();
    
    SimpleScheduleBuilder.simpleSchedule().
    					withIntervalInMinutes(3).//每隔3分钟执行一-次
    					withRepeatCount(3).//执行3次
    					build();
    
    

    3.2、CalendarlntervalTrigger

    类似于SimpleTrigger,指定从某一个时间开始, 以一定的时间间隔执行的任务。但是不同的是SimpleT rigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值), 而CalendarIntervalTrigger支持的间隔单 位有秒,分钟,小时,天,月,年,星期。
    

    示例:

    CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
    					.withIntervalInDays(2) //每2天执行一次
    					.build();
    
    CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
    					.withIntervalInWeeks(1) //每周执行一次
    					.build();
    

    3.3、DailyTimelntervalTrigger

    指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。
    它适合的任务类似于:指定每天9:00至18:00 ,每隔70秒执行一次,并且只要周一至周五执行。
    它的属性有:
    startTime0fDay每天开始时间
    endTime0fDay每天结束时间
    daysOfWeek需要执行的星期
    interval执行间隔
    intervalUnit执行间隔的单位(秒, 分钟,小时,天,月,年,星期)
    repeatCount重复次数
    
    示例:
    DailyTimeIntervalScheduleBuilder.dailyTime IntervalSchedule()
    					.start ingDailyAt (TimeOfDay.hourAndMinute0fDay(9, 0)) //每天9:00开始
    					.endingDailyAt (TimeOfDay.hour AndMinute0fDay(18, 0)) //18:00结束
    					.onDaysOfTheWeek( MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行
    					.withIntervalInHours(1) //每间隔1小时执行一次
    					.withRepeatCount(100) //最多重复100次(实际执行100+1次)
    					.build();
    
    DailyTimeIntervalScheduleBuilder.dailyTime IntervalSchedule()
    							.start ingDailyAt(Time0fDay.hourAndMinuteOfDay(10,0)) //每天10:00开始
    							.endingDailyAfterCount(10)//每天执行10次, 这个方法实际上根据startTimeOfDaytinterval*count算出endTimeOfDay
    							.onDaysOfTheWeek(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY)//周一至周五执行
    							.withIntervalInHours(1)//每间隔1小时执行一次
    							.build();
    
    

    3.4 CronTrigger (重点)

    适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部) -- 当然,也更难理解。
    它适合的任务类似于:每天0:00,9:00,18:00各执行-次。
    它的属性只有:
    Cron表达式。但这个表示式本身就够复杂了
    

    示例:

    CronScheduleBuilder.cronSchedule("0 0/2 10-12 * * ?") //每天10:00-12:00, 每隔2分钟执行一次
    .build();
    
    cronSchedule("0 30 9 ? * MON") //每周一,9:30执行一次
    .build();
    
    CronScheduleBuilder.week1yOnDayAndHourAndMinute(MONDAY,9,30) //等同于 0 30 9 ? * MON
    . build();
    

    3.4.1、Cron表达式

    [1] [2] [3] ? [5] 3#5

    星号(*): 可用在所有字段中,表示对应时间域的每一个时刻,例如,在分钟字段时, 表示“每分钟”;
    
    问号(?): 该字符只在日期和星期字段中使用,它通常指定为“不确定值”
    
    减号(-): 表达一一个范围,如在小时字段中使用“10-12",则表示从10到12点,即10, 11,12;
    
    逗号(,): 表达一个列表值,如在星期字段中使用“MON, WED, FRI",则表示星期一,星期三和星期五;
    
    斜杠(/): x/y表达一个等步长序列, x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为日,15,30和45秒,而5/15在分钟字段中表示5, 20, 35, 50,你也可以使用*/y,它等同于0/y;
    
    L: 该字符只在日期和星期字段中使用,代表"Last"的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有-个数值X,则表示"这个月的最后一个周x",例如,6L表示该月的最后星期五;
    
    W: 该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如1 5W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
    
    LW组合: 在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
    

    表达式示例:

    Calendar不是jdk的java.util.Calendar,不是为了计算日期的。它的作用是在于补充Trigger的时间。可以排除或加入某一些特定的时间点。
    以”每月29日零点自动还信用卡“为例,我们想排除掉每年的2月29号零点这个时间点(因为平年和润年2月不一样)。这个时间,就可以用Calendar来实现。

    Quartz提供以下几种Calendar,注意,所有的Calendar既可以是排除, 也可以是包含,取决于:
    HolidayCalendar。指定特定的日期,比如20140613。 精度到天。
    DailyCalendar.指定每天的时间段(rangeStartingTime, rangeEndingTime),格式是HH:M:SS[:mmm]]。 也就是最大精度可以到毫秒。
    WeeklyCalendar。指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY.精度是天。
    MonthlyCalendar。指定每月的几号。可选值为1-31。精度是天
    AnnualCalendar。指定每年的哪一天。使用方式如上例。精度是天。
    CronCalendar。指定Cron表达式。精度取决于Cron表达式,也就是最大精度可以到秒。

    当scheduler比较繁忙的时候,可能在同一个时刻,有多个Trigger被触发了,但资源不足(比如线程池不足)。那么这个时候比剪刀石头布更好的方式,就是设置优先级。优先级高的先执行。
    需要注意的是,优先级只有在同一时刻执行的Trigger之间才会起作用,如果一个Trigger是9:00, 另-个Trigger是9:30。那么无论后一个优先级多高, 前一个都是先执行。
    优先级的值默认是5,当为负数时使用默认值。最大值似乎没有指定,但建议遵循Java的标准,使用1-10,不然鬼才知道看到[优先级为10]是时,上头 还有没有更大的值。

    四、Job并发(重点)

    job是有可能并发执行的,比如一个任务要执行10秒中,而调度算法是每秒中触发1次,那么就有可能多个任务被并发执行。
    
    有时候我们并不想任务并发执行,比如这个任务要去"获得数据库中所有未发送邮件的名单”,如果是并发执行,就需要一个数据库 锁去避免一个数据被多次处理。这个时候一个@DisallowConcurrentExecution解决这个问题
    
    @DisallowConcur rentExecution
    public class DoNothingJob implements Job {
    	public void execute (JobExecutionContext context) throws JobExecut ionE xception {
    		System.out.println( "操作"):
    	}
    }
    
    注意,@DisallowConcurrentExecution是对 JobDetail实例生效,也就是如果你定义两个JobDetail,引用同一个Job类,是可以并发执行的
    

    代码示例:

    @DisallowConcurrentExecution //会不允许并发执行,(如果每1s触发 -次,但每个j ob要执行3秒)
    public class MyJob implements Job{
    	@Override
    	public void execute (JobExecutionContext context) throws JobExecutionException {
    		try {
    			Thread.sleep(3000);
    		} catch (InterruptedException e) {
    			e. printStackTrace();
            }
    		System.out.println("任务调度:组:"+group+",工作名:" +name+" "+data+new Date());
        }
    }
    

    五、Spring整合Quartz (重点)

    5.1、依赖

     <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <springframework.version>4.3.6.RELEASE</springframework.version>
        <quartz.version>2.2.3</quartz.version>
        <druid>1.1.12</druid>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
        <!--Quartz任务调度-->
        <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
          <version>2.2.3</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>${springframework.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>${springframework.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${springframework.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
          <version>${quartz.version}</version>
        </dependency>
    
        <!-- druid依赖 -->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>${druid}</version>
        </dependency>
        <!-- mysql驱动 依赖 -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.25</version>
          <scope>runtime</scope>
        </dependency>
    
        <!-- lombok -->
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.4</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    

    5.2、配置

    调度器   SchedulerFactoryBean
    触发器   CronTriggerFactoryBean
    JobDetail   JobDetailFactoryBean
    

    1、applicationContext_quartz.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--
            Spring整合Quartz进行配置遵循下面的步骤:
            1:定义工作任务的Job
            2:定义触发器Trigger,并将触发器与工作任务绑定
            3:定义调度器,并将Trigger注册到Scheduler
         -->
    
        <!-- 1:定义任务的bean ,这里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置类似-->
        <bean name="lxJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <!-- 指定job的名称 -->
            <property name="name" value="job1"/>
            <!-- 指定job的分组 -->
            <property name="group" value="group1"/>
            <!-- 指定具体的job类 -->
            <property name="jobClass" value="com.xibei.job.MyJob"/>
            <!-- 如果为false,当没有活动的触发器与之关联时会在调度器中会删除该任务 (可选) -->
            <property name="durability" value="true"/>
            <!-- (可选)
                 指定spring容器的key,如果不设定在job中的jobmap中是获取不到spring容器的
                 其实现了ApplicationContextWare,则其中的setApplicationContext方法会得到
                 当前的工厂对象,且将工厂对象存在了类中的一个属性“applicationContext”中,源码如下
    
                 getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
                 则在Job的jobmap中可以获得工厂对象,如果需要可以使用
    			 (ApplicationContext) jobDataMap.get("applicationContext04");
    			 jobDataMap.get("data04");
    
    			 .usingJobData("data04", "hello world~~")
    			 .usingJobData("applicationContext04",spring工厂对象)
            -->
            <!--<property name="applicationContextJobDataKey" value="applicationContext04"/>-->
        </bean>
    
    
        <!-- 2.2:定义触发器的bean,定义一个Cron的Trigger,一个触发器只能和一个任务进行绑定 -->
        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
            <!-- 指定Trigger的名称 -->
            <property name="name" value="hw_trigger"/>
            <!-- 指定Trigger的名称 -->
            <property name="group" value="hw_trigger_group"/>
            <!-- 指定Tirgger绑定的Job -->
            <property name="jobDetail" ref="lxJob"/>
            <!-- 指定Cron 的表达式 ,当前是每隔5s运行一次 -->
            <property name="cronExpression" value="* * * * * ?" />
        </bean>
    
        <!-- 3.定义调度器,并将Trigger注册到调度器中 -->
        <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="cronTrigger"/>
                </list>
            </property>
            <!-- 添加 quartz 配置,如下两种方式均可 -->
            <!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
            <property name="quartzProperties">
                <value>
                    # 指定调度器名称,实际类型为:QuartzScheduler
                    org.quartz.scheduler.instanceName = MyScheduler
                    # 指定连接池
                    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
                    # 连接池线程数量
                    org.quartz.threadPool.threadCount = 11
                    # 优先级
                    org.quartz.threadPool.threadPriority = 5
                    # 不持久化job
                    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
                </value>
            </property>
        </bean>
    </beans>
    

    web.xml项目的全局配置

    
    

    5.3、代码

    MyJob自定义任务类

    TestQuartzSpring

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext_quartz.xml")
    public class TestQuartzSpring {
    
        @Autowired
        private StdScheduler scheduler;
    
        @Test
        public void test1() throws InterruptedException, SchedulerException {
            System.out.println("hello");
            Thread.sleep(5000);
    
            // 删除 job
            /*scheduler.pauseTrigger(TriggerKey.triggerKey("hw_trigger","hw_trigger_group"));//暂停触发器的计时
            scheduler.unscheduleJob(TriggerKey.triggerKey("hw_trigger", "hw_trigger_group"));// 移除触发器中的任务
            scheduler.deleteJob(JobKey.jobKey("job1","group1"));//移除trigger后,删除工作*/
    
            // job 暂停 和 恢复
           /* scheduler.pauseJob(JobKey.jobKey("job1","group1"));
            Thread.sleep(30000);
            scheduler.resumeJob(JobKey.jobKey("job1","group1"));*/
    
            GroupMatcher<JobKey> groups = GroupMatcher.groupEquals("group1");//名字等于group1
            scheduler.pauseJobs(groups);// 暂停组内所有的job
            Thread.sleep(5000);
            scheduler.resumeJobs(groups);
            Thread.sleep(5000);
        }
    }
    

    六、持久化

    6.1、建表

    quartz官方提供了完整的持久化job的支持,并给出了一套库表

    CREATE TABLE QRTZ_JOB_DETAILS(  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    JOB_NAME VARCHAR(200) NOT NULL,  
    JOB_GROUP VARCHAR(200) NOT NULL,  
    DESCRIPTION VARCHAR(250) NULL,  
    JOB_CLASS_NAME VARCHAR(250) NOT NULL,  
    IS_DURABLE VARCHAR(1) NOT NULL,  
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,  
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,  
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,  
    JOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    JOB_NAME VARCHAR(200) NOT NULL,  
    JOB_GROUP VARCHAR(200) NOT NULL,  
    DESCRIPTION VARCHAR(250) NULL,  
    NEXT_FIRE_TIME BIGINT(13) NULL,  
    PREV_FIRE_TIME BIGINT(13) NULL,  
    PRIORITY INTEGER NULL,  
    TRIGGER_STATE VARCHAR(16) NOT NULL,  
    TRIGGER_TYPE VARCHAR(8) NOT NULL,  
    START_TIME BIGINT(13) NOT NULL,  
    END_TIME BIGINT(13) NULL,  
    CALENDAR_NAME VARCHAR(200) NULL,  
    MISFIRE_INSTR SMALLINT(2) NULL,  
    JOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)  
    REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SIMPLE_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    REPEAT_COUNT BIGINT(7) NOT NULL,  
    REPEAT_INTERVAL BIGINT(12) NOT NULL,  
    TIMES_TRIGGERED BIGINT(10) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_CRON_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    CRON_EXPRESSION VARCHAR(120) NOT NULL,  
    TIME_ZONE_ID VARCHAR(80),  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SIMPROP_TRIGGERS  
      (            
        SCHED_NAME VARCHAR(120) NOT NULL,  
        TRIGGER_NAME VARCHAR(200) NOT NULL,  
        TRIGGER_GROUP VARCHAR(200) NOT NULL,  
        STR_PROP_1 VARCHAR(512) NULL,  
        STR_PROP_2 VARCHAR(512) NULL,  
        STR_PROP_3 VARCHAR(512) NULL,  
        INT_PROP_1 INT NULL,  
        INT_PROP_2 INT NULL,  
        LONG_PROP_1 BIGINT NULL,  
        LONG_PROP_2 BIGINT NULL,  
        DEC_PROP_1 NUMERIC(13,4) NULL,  
        DEC_PROP_2 NUMERIC(13,4) NULL,  
        BOOL_PROP_1 VARCHAR(1) NULL,  
        BOOL_PROP_2 VARCHAR(1) NULL,  
        PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
        FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)   
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_BLOB_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    BLOB_DATA BLOB NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),  
    INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),  
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)  
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_CALENDARS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    CALENDAR_NAME VARCHAR(200) NOT NULL,  
    CALENDAR BLOB NOT NULL,  
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_FIRED_TRIGGERS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    ENTRY_ID VARCHAR(95) NOT NULL,  
    TRIGGER_NAME VARCHAR(200) NOT NULL,  
    TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    INSTANCE_NAME VARCHAR(200) NOT NULL,  
    FIRED_TIME BIGINT(13) NOT NULL,  
    SCHED_TIME BIGINT(13) NOT NULL,  
    PRIORITY INTEGER NOT NULL,  
    STATE VARCHAR(16) NOT NULL,  
    JOB_NAME VARCHAR(200) NULL,  
    JOB_GROUP VARCHAR(200) NULL,  
    IS_NONCONCURRENT VARCHAR(1) NULL,  
    REQUESTS_RECOVERY VARCHAR(1) NULL,  
    PRIMARY KEY (SCHED_NAME,ENTRY_ID))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_SCHEDULER_STATE (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    INSTANCE_NAME VARCHAR(200) NOT NULL,  
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,  
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))  
    ENGINE=InnoDB;  
      
    CREATE TABLE QRTZ_LOCKS (  
    SCHED_NAME VARCHAR(120) NOT NULL,  
    LOCK_NAME VARCHAR(40) NOT NULL,  
    PRIMARY KEY (SCHED_NAME,LOCK_NAME))  
    ENGINE=InnoDB;  
    

    6.2、配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 定义调度器,并将Trigger注册到调度器中 -->
        <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <!-- 添加 quartz 配置,如下两种方式均可 -->
            <!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
            <property name="quartzProperties">
                <value>
                    # 指定调度器名称,实际类型为:QuartzScheduler
                    org.quartz.scheduler.instanceName = MyScheduler
                    # 指定连接池
                    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
                    # 连接池线程数量
                    org.quartz.threadPool.threadCount = 11
                    # 优先级
                    org.quartz.threadPool.threadPriority = 5
                    # 不持久化job
                    # org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
                    #持久化
                    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
                    #quartz表的前缀
                    org.quartz.jobStore.tablePrefix = QRTZ_
                </value>
            </property>
            <property name="dataSource" ref="druid"/>
        </bean>
    
        <!-- 导入外部参数文件 -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <!-- 连接池:druid -->
        <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
              destroy-method="close">
            <!-- 基本属性 url、user、password -->
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.user}"/>
            <property name="password" value="${jdbc.password}"/>
    
            <!-- 配置初始化大小、最小、最大 -->
            <property name="initialSize" value="1"/>
            <property name="minIdle" value="1"/>
            <property name="maxActive" value="${jdbc.maxPoolSize}"/>
    
            <!-- 配置获取连接等待超时的时间 -->
            <property name="maxWait" value="3000"/>
    
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    
            <!-- 配置一个连接在池中最小空闲的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="300000"/>
    
            <property name="validationQuery" value="SELECT 'x'"/>
            <property name="testWhileIdle" value="true"/>
            <property name="testOnBorrow" value="false"/>
            <property name="testOnReturn" value="false"/>
        </bean>
    </beans>
    

    mvc.xml

    <beans 	xmlns="http://www.springframework.org/schema/beans"
              xmlns:context="http://www.springframework.org/schema/context"
              xmlns:mvc="http://www.springframework.org/schema/mvc"
              xmlns:aop="http://www.springframework.org/schema/aop"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans
    							http://www.springframework.org/schema/beans/spring-beans.xsd
    							http://www.springframework.org/schema/context
    							http://www.springframework.org/schema/context/spring-context.xsd
    							http://www.springframework.org/schema/mvc
    							http://www.springframework.org/schema/mvc/spring-mvc.xsd
                                http://www.springframework.org/schema/aop
    							http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 告知springmvc  哪些包中 存在 被注解的类
             use-default-filters="false"  遇到到 @Controller  @Service  @Repository  @Component类,都会忽略
        -->
        <context:component-scan base-package="com.xibei" use-default-filters="false">
            <!-- 只扫描  有@Controller注解的类 -->
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
        <!-- 注册注解开发驱动 -->
        <mvc:annotation-driven/>
    
        <!-- 视图解析器
    	     作用:1.捕获后端控制器的返回值="index"
    	          2.解析: 在返回值的前后 拼接 ==> "/index.jsp"
    	 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 前缀 -->
            <property name="prefix" value="/"></property>
            <!-- 后缀 -->
            <property name="suffix" value=".jsp"></property>
        </bean>
        <!-- 在项目中 自动添加一个 映射{"/**" : DefaultServletHttpRequestHandler}
             请求进入前端后,会先匹配自定义的Handler,如果没有匹配的则进入DefaultServletHttpRequestHandler。
             DefaultServletHttpRequestHandler会将请求转发给Tomcat中名为"default"的servlet。
             最终实现了静态资源的访问
        -->
        <mvc:default-servlet-handler/>
    
    
    </beans>
    

    web.xml

    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                          http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
        <display-name>Archetype Created Web Application</display-name>
    
        <servlet>
            <servlet-name>mvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:mvc.xml</param-value>
            </init-param>
            <load-on-startup>2</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>mvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!-- Post请求中文参数乱码解决 -->
        <filter>
            <filter-name>encode</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>utf-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encode</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext_quartz2.xml</param-value>
        </context-param>
    </web-app>
    
    

    6.3、增加任务

    定义一个springMVC的Handler

    JobAndTrigger

    public class JobAndTrigger {
        private String jobName;
        private String jobGroup;
        private String jobClassName;
        private String triggerName;
        private String triggerGroup;
        private BigInteger repeatInterval;
        private BigInteger timesTriggered;
        private String cronExpression;
        private String timeZoneId;
    }
    

    QuartzController

    @Controller
    @RequestMapping("/quartz")
    public class QuartzController {
    
        @Autowired //注入了工厂中 调度器
        private Scheduler scheduler;
    
        @RequestMapping("/add")
        public String addJob(JobAndTrigger jt) throws ClassNotFoundException, SchedulerException {
            // 创建JobDetail
            JobDetail jobDetail=null;
            jobDetail = JobBuilder.newJob((Class<? extends Job>)Class.forName(jt.getJobClassName()))
                    .withIdentity(jt.getJobName(), jt.getJobGroup()).storeDurably(true).build();
            CronTrigger cronTrigger = null;
            cronTrigger = TriggerBuilder.newTrigger().withIdentity(jt.getJobName(),jt.getJobGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(jt.getCronExpression()))
                    .build();
            scheduler.scheduleJob(jobDetail,cronTrigger);
            return "index";
        }
    }
    

    addjob.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <form action="${pageContext.request.contextPath}/quartz/add" method="post">
        jobName: <input type="text" name="jobName"> <br>
        jobGroup: <input type="text" name="jobGroup"> <br>
        cronExp: <input type="text" name="cronExpression"> <br>
        jobClass: <input type="text" name="jobClassName"> <br>
        <input type="submit" value="增加">
    </form>
    </body>
    </html>
    

    启动Tomcat测试

    七、springboot整合自带的quartz

    7.1、简单任务

    1、SimpleJob

    @Configuration
    public class SimpleJob {
        @Scheduled(cron = "0/1 * * * * ?")
        public void run() {
            //任务
            System.err.println(LocalDateTime.now()+"我是简单的");//输出红色
    
        }
    

    2、SpringbootQuartzApplication

    @EnableScheduling//开启任务调度支持
    @SpringBootApplication
    public class SpringbootQuartzApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootQuartzApplication.class, args);
        }
    }
    

    7.2、复杂任务

    1、pom.xml

     <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>com.oracle.ojdbc</groupId>
                <artifactId>ojdbc8</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    2、连接Oracle数据库

    数据表

    cron_id cron
    1 0/1 * * * * ?
    2 0/5 * * * * ?

    查询语句

    select "cron" from "cron" where "cron_id"=1
    

    application.properties

    spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
    spring.datasource.url= jdbc:oracle:thin:@localhost:1521:MLDN
    spring.datasource.password=zhu
    spring.datasource.username=zhu
    

    3、ComplexJob

    @Configuration
    public class ComplexJob implements SchedulingConfigurer {
        @Mapper
        public interface CronMapper {
            @Select("select "cron" from "cron" where "cron_id"=1")
            String getCron();//返回查询结果
        }
    
        //将cronMapper注入给ComplexJob
        @Autowired
        CronMapper cronMapper;
    
    
        //任务,触发器
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.addTriggerTask(
                    () -> System.out.println(LocalDateTime.now()+"我是复杂的"),//任务
                    triggerContext -> {
                        String cron = cronMapper.getCron();
                        return new CronTrigger(cron).nextExecutionTime(triggerContext);//触发器
                    });
    
    
            /*scheduledTaskRegistrar.addTriggerTask(new Runnable() { //任务
                @Override
                public void run() {
                    System.out.println(LocalDateTime.now()+"我是复杂的");
                }
            }, new Trigger() {//触发器
                @Override
                public Date nextExecutionTime(TriggerContext triggerContext) {
                    String cron = cronMapper.getCron();
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
            });*/
    
    
        }
    }
    

    4、SpringbootQuartzApplication

    @EnableScheduling//开启任务调度支持
    @SpringBootApplication
    public class SpringbootQuartzApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootQuartzApplication.class, args);
        }
    
    }
    

    5、测试

    调度器作用:调度安排一些工作,

    触发器作用:每个任务在某个时间触发执行,触发谁

    一个job 对应一个触发器

    jobDetail封装了job

    调度器启动起来,启动调度器中所有触发器+任务(job)

    http://www.bejson.com/othertools/cronvalidate/

  • 相关阅读:
    java入门-使用idea创建web项目
    java入门-gitlab
    linux基础:source和sh的区别
    github基本使用
    docker-compose
    k8s学习笔记之六:flannel网络配置
    计算机网络
    python自学之路--python面试题
    ASP.NET前后端分离框架(转载)
    ASP.NET Core初步使用Quartz.NET(转载)
  • 原文地址:https://www.cnblogs.com/zhuchengbo/p/12722926.html
Copyright © 2020-2023  润新知