zoukankan      html  css  js  c++  java
  • 任务调度

      1. 任务调度

    定时任务调度:基于给定的时间点、给定的时间间隔、给定的执行次数自动执行的任务。

     

     

        1. unix crontab命令

    crontab [-u user] file

    crontab [-u user] [ -e | -l | -r]

     

     

     

        1. Timer

    介绍

    Timer,简单无门槛,一般也没人用。单线程。

     

    Timer位于java.util包下,其内部包含且仅包含一个后台线程(TimeThread)对多个业务任务(TimeTask)进行定时定频率的调度。

     

    https://pic4.zhimg.com/80/v2-4fb47836439037bec04cadbb07c548f3_hd.jpg

    参数说明:

    task:所要执行的任务,需要extends TimeTask override run()

    time/firstTime:首次执行任务的时间

    period:周期性执行Task的时间间隔,单位是毫秒

    delay:执行task任务前的延时时间,单位是毫秒

    很显然,通过上述的描述,我们可以实现:

    延迟多久后执行一次任务;指定时间执行一次任务;延迟一段时间,并周期性执行任务;指定时间,并周期性执行任务;

     

    注意点

    1:如果time/firstTime指定的时间,在当前时间之前,会发生什么呢?

    在时间等于或者超过time/firstTime的时候,会执行task!也就是说,如果time/firstTime指定的时间在当前时间之前,就会立即得到执行。

    延时问题!

     

    2:schedule和scheduleAtFixedRate有什么区别?

    scheduleAtFixedRate:每次执行时间为上一次任务开始起向后推一个period间隔,也就是说下次执行时间相对于上一次任务开始的时间点,因此执行时间不会延后,但是存在任务并发执行的问题。
    schedule:每次执行时间为上一次任务结束后推一个period间隔,也就是说下次执行时间相对于上一次任务结束的时间点,因此执行时间会不断延后。

     

    3:如果执行task发生异常,是否会影响其他task的定时调度?

    如果TimeTask抛出RuntimeException,那么Timer会停止所有任务的运行!

     

    4:Timer的一些缺陷?

    前面已经提及到Timer背后是一个单线程,因此Timer存在管理并发任务的缺陷:所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而前一个任务的延迟或者异常会影响到之后的任务。
    其次,Timer的一些调度方式还算比较简单,无法适应实际项目中任务定时调度的复杂度。

     

    5:停止和移除

    cancel():终止Timer计时器,丢弃所有当前已安排的任务(TimeTask也存在cancel()方法,不过终止的是TimeTask)

    purge():从计时器的任务队列中移除已取消的任务,并返回个数

     

     

    代码示例

     

    package schedule.timer;

     

    import java.text.SimpleDateFormat;

    import java.util.Calendar;

    import java.util.Timer;

    import java.util.TimerTask;

     

    /**

     * Timer背后是一个单线程,因此Timer存在管理并发任务的缺陷:所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而前一个任务的延迟或者异常会影响到之后的任务。

     * 其次,Timer的一些调度方式还算比较简单,无法适应实际项目中任务定时调度的复杂度。

     *

     *

     */

    public class TimerTest {

        public static void main(String[] args) {

            Timer timer = new Timer();

           

            timer.schedule(new MyTask(), Calendar.getInstance().getTime(), 1000);

        }

    }

     

    class MyTask extends TimerTask{

        @Override

        public void run() {

            System.out.println("start at :"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(this.scheduledExecutionTime()));

           

            try {

                Thread.sleep(2000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

     

        1. ScheduledExecutorService

    介绍

    JDK5之后便提供了基于线程池的定时任务调度:ScheduledExecutorService。

    设计理念:每一个被调度的任务都会被线程池中的一个线程去执行,因此任务可以并发执行,而且相互之间不受影响。

     

    示例

     

    package schedule.scheduledExecutor;

     

    import java.util.Date;

    import java.util.concurrent.Executors;

    import java.util.concurrent.ScheduledExecutorService;

    import java.util.concurrent.TimeUnit;

     

    public class ScheduledExecutorServiceTest {

        public static void main(String[] args) {

            ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);

            scheduledExecutorService.scheduleAtFixedRate(new ExecutorDemo(), 1000, 2000, TimeUnit.MILLISECONDS);

        }

    }

     

    class ExecutorDemo implements Runnable{

        @Override

        public void run() {

            System.out.println("执行"+new Date());

        }

    }

     

     

        1. spring task

    spring @Scheduled注解,一般集成于项目中,小任务很方便。

     

    fixedRate和fixedDelay的区别

    fixedRate :每隔多少毫秒执行一次该方法, 以上一次执行开始时间计算

    fixedDelay:当一次方法执行完毕之后,延迟多少毫秒再执行该方法

     

     

    例子1 注解方式

    package schedule.springTask1;

     

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class SpringTaskAnnotationTest {

        public static void main(String[] args) throws BeansException {

            ApplicationContext ctx = new ClassPathXmlApplicationContext("/schedule/springTask1/spring-mvc.xml");

        }

    }

     

     

    package schedule.springTask1;

     

    import java.util.Date;

     

    import org.springframework.scheduling.annotation.Scheduled;

    import org.springframework.stereotype.Component;

     

    /**

     * 基于注解的定时器

     */

    @Component

    public class SpringTaskAnnotation {

     

        // 定时计算。每一秒执行一次

        @Scheduled(cron = "0/1 * * * * *")

        public void show() {

            System.out.println(new Date() + " : Annotationis show run");

        }

     

        /**

         * 心跳更新。启动时执行一次,之后每隔2秒执行一次

         */

        @Scheduled(fixedRate = 1000 * 2)

        public void print() {

            System.out.println(new Date() + " : Annotationis print run");

        }

     

        // 启动加载缓存, 以上一次执行完为准

        @Scheduled(fixedDelay = 1 * 1000)

        public void init() {

            System.out.println(new Date() + ": Annotationis init run");

        }

    }

     

    <beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:p="http://www.springframework.org/schema/p"

        xmlns:task="http://www.springframework.org/schema/task"

        xmlns:context="http://www.springframework.org/schema/context"

        xmlns:aop="http://www.springframework.org/schema/aop"

        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/task http://www.springframework.org/schema/task/spring-task.xsd">

     

        <!-- 定时器注解开关, 可以配置 scheduler参数 -->

        <task:annotation-driven />

        <!-- bean注解开关 -->

        <context:annotation-config />

        <!-- 自动扫描的包名 -->

        <context:component-scan base-package="schedule.springTask1" />

     

    </beans>   

     

     

    例子2 xml方式

    package schedule.springTask2;

     

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class SpringTaskXmlTest {

     

        public static void main(String[] args) throws BeansException {

            ApplicationContext ctx = new ClassPathXmlApplicationContext("/schedule/springTask2/spring-mvc.xml");

        }

    }

     

     

    package schedule.springTask2;

     

    import java.util.Date;

     

    /**

     * 基于xml的定时器

     */

    public class SpringTaskXml {

     

        public void show() {

            System.out.println(new Date() + " : XMl is show run");

        }

     

        public void print() {

            System.out.println(new Date() + " : XMl print run");

        }

    }

     

     

    <beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:p="http://www.springframework.org/schema/p"

        xmlns:task="http://www.springframework.org/schema/task"

        xmlns:context="http://www.springframework.org/schema/context"

        xmlns:aop="http://www.springframework.org/schema/aop"

        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/task http://www.springframework.org/schema/task/spring-task.xsd">

     

        <bean id="task" class="schedule.springTask2.SpringTaskXml"></bean>

     

        <task:scheduled-tasks>

            <!-- 这里表示的是每隔五秒执行一次 -->

            <task:scheduled ref="task" method="show"

                cron="*/5 * * * * ?" />

            <task:scheduled ref="task" method="print"

                cron="*/10 * * * * ?" />

        </task:scheduled-tasks>

     

    </beans>

     

     

     

     

     

     

     

        1. Spring Quartz

    开源工具 Quartz,分布式集群开源工具,可以说是中小型公司必选,当然也视自身需求而定。

     

    介绍

    https://pic3.zhimg.com/80/v2-4b73fe0a6efe3484883b16a9bb347ab9_hd.jpg

     

    两种方式实现Spirng定时任务:

    1.继承自org.springframework.scheduling.quartz.QuartzJobBean
    2.作业类即普通的java类,不需要继承自任何基类。

     

    定时器任务有两种触发器:

    1.按照一定频度调用任务,在Spring Quartz中对应的触发器为:org.springframework.scheduling.quartz.SimpleTriggerBean
    2.按照指定时间调用任务,在Spring Quartz中对应的调度器为:org.springframework.scheduling.quartz.CronTriggerBean

     

     

    说明:
    1、从代码上来看,有XxxBuilder、XxxFactory,说明Quartz用到了Builder、Factory模式,还有非常易懂的链式编程风格。
    2、Quartz有3个核心概念:调度器(Scheduler)、任务(Job&JobDetail)、触发器(Trigger)。(一个任务可以被多个触发器触发,一个触发器只能触发一个任务)
    3、注意当Scheduler调度Job时,实际上会通过反射newInstance一个新的Job实例(待调度完毕后销毁掉),同时会把JobExecutionContext传递给Job的execute方法,Job实例通过JobExecutionContext访问到Quartz运行时的环境以及Job本身的明细数据。
    4、JobDataMap可以装载任何可以序列化的数据,存取很方便。需要注意的是JobDetail和Trigger都可以各自关联上JobDataMap。JobDataMap除了可以通过上述代码获取外,还可以在YourJob实现类中,添加相应setter方法获取。
    5、Trigger用来告诉Quartz调度程序什么时候执行,常用的触发器有2种:SimpleTrigger(类似于Timer)、CronTrigger(类似于Linux的Crontab)。
    6、实际上,Quartz在进行调度器初始化的时候,会加载quartz.properties文件进行一些属性的设置,比如Quartz后台线程池的属性(threadCount)、作业存储设置等。它会先从工程中找,如果找不到那么就是用quartz.jar中的默认的quartz.properties文件。
    7、Quartz存在监听器的概念,比如任务执行前后、任务的添加等,可以方便实现任务的监控。

     

     

    cronExpression配置说明

    字段

    允许值

    允许的特殊字符

    0-59

    , - * /

    0-59

    , - * /

    小时

    0-23

    , - * /

    日期

    1月31日

    , - * ? / L W C

    月份

    1-12 或者 JAN-DEC

    , - * /

    星期

    1-7 或者 SUN-SAT

    , - * ? / L C #

    年(可选)

    留空, 1970-2099

    , - * /

     

     

    特殊字符说明:

    字符

    意义

    *

    表示所有值;

    ?

    表示未说明的值,即不关心它为何值;

    -

    表示一个指定的范围;

    ,

    表示附加一个可能值;

    /

    符号前表示开始时间,符号后表示每次递增的值;

    L(“last”)

    (“last”) “L” 用在day-of-month字段意思是

    W(“weekday”)

    只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第16 天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在day- of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日。

    #

    只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用”6#3”指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。

    C

    指和calendar联系后计算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天。

     

     

    Cron表达式教程

    这里给出一些常用的示例:
    0 15 10 ? * 每天10点15分触发
    0 15 10 ? 2017 2017年每天10点15分触发
    0 14 * ? 每天下午的 2点到2点59分每分触发
    0 0/5 14 ? 每天下午的 2点到2点59分(整点开始,每隔5分触发)
    0 0/5 14,18 ? 每天下午的 2点到2点59分、18点到18点59分(整点开始,每隔5分触发)
    0 0-5 14 ? 每天下午的 2点到2点05分每分触发
    0 15 10 ? * 6L 每月最后一周的星期五的10点15分触发
    0 15 10 ? * 6#3 每月的第三周的星期五开始触发
    我们可以通过一些Cron在线工具非常方便的生成,比如http://www.pppet.net/等。

     

     

    CronTrigger

    CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表。 CronTrigger,你可以指定触发的时间表如“每星期五中午”,或“每个工作日9:30时”,甚至“每5分钟一班9:00和10:00逢星期一上午,星期三星期五“。 即便如此,SimpleTrigger一样,CronTrigger拥有的startTime指定的时间表时生效,指定的时间表时,应停止(可选)结束时间。

    Cron表达式

    cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:

    1. Seconds

    2. Minutes

    3. Hours

    4. Day-of-Month

    5. Month

    6. Day-of-Week

    7. Year (可选字段)

    例 "0 0 12 ? * WED" 在每星期三下午12:00 执行,

    个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT". “*” 代表整个时间段.

    每一个字段都有一套可以指定有效值,如

    Seconds (秒) :可以用数字0-59 表示,

    Minutes(分) :可以用数字0-59 表示,

    Hours(时) :可以用数字0-23表示,

    Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份

    Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示

    Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

    “/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行

    “?”:表示每月的某一天,或第周的某一天

    “L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”

    “W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”

    ““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or "FRI#3" 则表示“每月第三个星期五”

     

     

    例子 1 cron简单和复杂例子

    可指定执行类和指定方法,可以注入service

     

    package schedule.quartz1;

     

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class SpringTaskAnnotationTest {

        public static void main(String[] args) throws BeansException {

            ApplicationContext ctx = new ClassPathXmlApplicationContext("/schedule/quartz1/spring-mvc.xml");

        }

    }

     

     

    package schedule.quartz1;

     

    public class SimpleJob {

        protected void execute() {

            System.out.println("简单定时任务执行中…");

        }

    }

     

     

    package schedule.quartz1;

     

    import org.quartz.JobExecutionContext;

    import org.quartz.JobExecutionException;

    import org.springframework.scheduling.quartz.QuartzJobBean;

     

    public class ComplexJob extends QuartzJobBean {

     

        private int timeout;

     

        // 调度工厂实例化后,经过timeout时间开始执行调度

        public void setTimeout(int timeout) {

            this.timeout = timeout;

        }

     

        /**

         * 要调度的具体任务

         */

        @Override

        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

            System.out.println("复杂定时任务执行中…");

        }

    }

     

     

     

    <beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:p="http://www.springframework.org/schema/p"

        xmlns:task="http://www.springframework.org/schema/task"

        xmlns:context="http://www.springframework.org/schema/context"

        xmlns:aop="http://www.springframework.org/schema/aop"

        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/task http://www.springframework.org/schema/task/spring-task.xsd">

           

        <bean id="simpleJob" class="schedule.quartz1.SimpleJob"></bean>

       

        <!-- 使用 MethodInvokingJobDetailFactoryBean, 指定特定方法 -->

        <bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">

            <property name="targetObject" ref="simpleJob" />

            <property name="targetMethod" value="execute" />

            <property name="concurrent" value="false" /><!-- 作业不并发调度 -->

        </bean>

       

        <!-- 简单触发器,使用 SimpleTriggerFactoryBean -->

        <bean id="simpleTrigger"  class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">

            <property name="jobDetail" ref="simpleJobDetail" />

            <property name="startDelay" value="1000" /><!-- 调度工厂实例化后,经过1000秒开始执行调度 -->

            <property name="repeatInterval" value="2000" /><!-- 2秒调度一次 -->

        </bean>

     

     

        <!-- 高级设置, 给作业传递数据 -->

        <bean id="complexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

            <property name="jobClass" value="schedule.quartz1.ComplexJob" />

     

            <property name="jobDataMap">

                <map>

                    <entry key="timeout" value="1" />

                </map>

            </property>

     

            <property name="durability" value="true" />

        </bean>

     

        <!-- 计划触发器,使用 CronTriggerFactoryBean -->

        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">

            <property name="jobDetail" ref="complexJobDetail" />

            <!--<property name="cronExpression" value="0/5 * * ? * SAT-SUN" /> -->

            <property name="cronExpression" value="0/5 * * ? * *" />

        </bean>

     

        <!-- 调度器 -->

        <bean

            class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

            <property name="triggers">

                <list>

                    <ref bean="simpleTrigger" />

                    <ref bean="cronTrigger" />

                </list>

            </property>

        </bean>

     

    </beans>

     

     

    例子 2 Scheduler start/stop manager配置方式

    可以指定执行类(继承job),但不能注入service

     

    package schedule.quartz2;

     

    import org.quartz.SchedulerException;

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class SpringTaskAnnotationTest {

        public static void main(String[] args) throws BeansException, InterruptedException, SchedulerException {

            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/schedule/quartz2/spring-mvc.xml");

           

            QuartzManager quartzManager = applicationContext.getBean(QuartzManager.class);

            quartzManager.initJobs();

           

           

            quartzManager.addJob("xxxx", "yyyy", "zzzz", "gggg",MyJob.class, "0/3 * * ? * *");

           

           

            Thread.sleep(2000);

            System.out.println("--change to 2s--");

           

            quartzManager.trigger("xxxxcc", "yyyy", "zzzzx", "ggggx",MyJob2.class, "0/1 * * ? * *");

           

           

            quartzManager.modifyJobTime("xxxx", "yyyy", "zzzz", "gggg", "0/2 * * ? * *");

           

    //      Thread.sleep(20000);

           

            System.out.println("--stop--");

           

    //      quartzManager.shutdownJobs();

            Thread.sleep(20000);

        }

    }

     

     

    package schedule.quartz2;

     

    import java.util.HashSet;

    import java.util.List;

     

    import org.apache.commons.lang3.StringUtils;

    import org.quartz.CronScheduleBuilder;

    import org.quartz.CronTrigger;

    import org.quartz.JobBuilder;

    import org.quartz.JobDetail;

    import org.quartz.JobKey;

    import org.quartz.Scheduler;

    import org.quartz.SchedulerException;

    import org.quartz.Trigger;

    import org.quartz.TriggerBuilder;

    import org.quartz.TriggerKey;

    import org.springframework.beans.factory.annotation.Autowired;

     

    public class QuartzManager {

     

        private Scheduler scheduler;

       

        @Autowired

        private IJobService jobService;

       

        //初始化所有的jobs

        public void initJobs() {

            Long count = jobService.listQuartzEntity(null);

           

            if(0!=count) {

                System.out.println(".....");

            }

        }

     

        /**

         * @Description: 添加一个定时任务

         *

         * @param jobName          任务名

         * @param jobGroupName     任务组名

         * @param triggerName      触发器名

         * @param triggerGroupName 触发器组名

         * @param jobClass         任务

         * @param cron             时间设置,参考quartz说明文档

         */

        @SuppressWarnings({ "unchecked", "rawtypes" })

        public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron) {

            try {

                // 任务名,任务组,任务执行类

                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);

                JobDetail jobDetail = null;

                if(!scheduler.checkExists(jobKey)){

                    jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();

                }else{

                    jobDetail = scheduler.getJobDetail(jobKey);

                }

               

                TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);

                if(!scheduler.checkExists(triggerKey)){

                    // 触发器

                    TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();

                    // 触发器名,触发器组

                    triggerBuilder.withIdentity(triggerName, triggerGroupName);

                    triggerBuilder.startNow();

                    // 触发器时间设定

                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));

                    // 创建Trigger对象

                    CronTrigger trigger = (CronTrigger) triggerBuilder.build();

                   

                    // 调度容器设置JobDetailTrigger

                    scheduler.scheduleJob(jobDetail, trigger);

    //              scheduler.rescheduleJob(triggerKey, trigger);

                   

                    //https://stackoverflow.com/questions/34176482/unable-to-store-job-because-one-already-exists-with-this-identification

                   

                    // 启动

                    if (!scheduler.isShutdown()) {

                        scheduler.start();

                    }

                }

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

       

        public void addJobs(String jobName, String jobGroupName, List<SingleTrigger> triggers, Class jobClass, String cron) {

            try {

                // 任务名,任务组,任务执行类

                JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));

                if(null==jobDetail){

                    jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();

                }

               

                if(null!=triggers && !triggers.isEmpty()){

                    HashSet<Trigger> triggerSet = new HashSet<Trigger>();

                   

                    for (SingleTrigger singleTrigger : triggers) {

                        if(null==scheduler.getTrigger(new TriggerKey(singleTrigger.getTriggerName(), singleTrigger.getTriggerGroup()))){

                            // 触发器

                            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();

                            // 触发器名,触发器组

                            triggerBuilder.withIdentity(singleTrigger.getTriggerName(), singleTrigger.getTriggerGroup());

                            triggerBuilder.startNow();

                            // 触发器时间设定

                            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(singleTrigger.getTriggerCron()));

                            // 创建Trigger对象

                            CronTrigger trigger = (CronTrigger) triggerBuilder.build();

                           

                            triggerSet.add(trigger);

                        }

                    }

                   

                    // 调度容器设置JobDetailTrigger

                    scheduler.scheduleJob(jobDetail, triggerSet, true);

                   

                    // 启动

                    if (!scheduler.isShutdown()) {

                        scheduler.start();

                    }

                }

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

       

       

       

        /**

         * 触发任务

         * @throws SchedulerException

         */

        public void trigger(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron) throws SchedulerException {

            JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));

           

            //没有对应的jobtrigger

            if(null==jobDetail && null==scheduler.getTrigger(new TriggerKey(triggerName, triggerGroupName))) {

                addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);

            }else {

                JobKey key = new JobKey(jobName, jobGroupName);

                scheduler.triggerJob(key);

            }

        }

       

        /**

         * 停止任务

         * @throws SchedulerException

         */

        public void pauseJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron) throws SchedulerException {

            JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));

           

            //没有对应的jobtrigger

            if(null!=jobDetail && null!=scheduler.getTrigger(new TriggerKey(triggerName, triggerGroupName))) {

                JobKey key = new JobKey(jobName, jobGroupName);

                scheduler.pauseJob(key);

            }

        }

       

        /**

         * 恢复任务

         * @throws SchedulerException

         */

        public void resumeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron) throws SchedulerException {

            JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));

           

            //没有对应的jobtrigger

            if(null!=jobDetail && null!=scheduler.getTrigger(new TriggerKey(triggerName, triggerGroupName))) {

                JobKey key = new JobKey(jobName, jobGroupName);

                scheduler.resumeJob(key);

            }

        }  

     

        /**

         * @Description: 修改一个任务的触发时间

         *

         * @param jobName

         * @param jobGroupName

         * @param triggerName      触发器名

         * @param triggerGroupName 触发器组名

         * @param cron             时间设置,参考quartz说明文档

         */

        public void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron) {

            try {

                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);

                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

                if (trigger == null) {

                    return;

                }

     

                String oldTime = trigger.getCronExpression();

                if (!oldTime.equalsIgnoreCase(cron)) {

                    /** 方式一 :调用 rescheduleJob 开始 */

                    // 触发器

                    TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();

                    // 触发器名,触发器组

                    triggerBuilder.withIdentity(triggerName, triggerGroupName);

                    triggerBuilder.startNow();

                    // 触发器时间设定

                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));

                    // 创建Trigger对象

                    trigger = (CronTrigger) triggerBuilder.build();

                    // 方式一 :修改一个任务的触发时间

                    scheduler.rescheduleJob(triggerKey, trigger);

                    /** 方式一 :调用 rescheduleJob 结束 */

     

                    /** 方式二:先删除,然后在创建一个新的Job */

                    // JobDetail jobDetail =

                    // scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));

                    // Class<? extends Job> jobClass = jobDetail.getJobClass();

                    // removeJob(jobName, jobGroupName, triggerName,

                    // triggerGroupName);

                    // addJob(jobName, jobGroupName, triggerName, triggerGroupName,

                    // jobClass, cron);

                    /** 方式二 :先删除,然后在创建一个新的Job */

                }

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

       

       

        /**

         * @Description: 移除一个trigger

         *

         * @param jobName

         * @param jobGroupName

         * @param triggerName

         * @param triggerGroupName

         */

        public void removeTrigger(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {

            try {

                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);

     

                scheduler.pauseTrigger(triggerKey);// 停止触发器

                scheduler.unscheduleJob(triggerKey);// 移除触发器

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

       

     

        /**

         * @Description: 移除一个任务

         *

         * @param jobName

         * @param jobGroupName

         * @param triggerName

         * @param triggerGroupName

         */

        public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {

            try {

                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);

     

                scheduler.pauseTrigger(triggerKey);// 停止触发器

                scheduler.unscheduleJob(triggerKey);// 移除触发器

                scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

     

        /**

         * @Description:启动所有定时任务

         */

        public void startJobs() {

            try {

                scheduler.start();

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

     

        /**

         * @Description:关闭所有定时任务

         */

        public void shutdownJobs() {

            try {

                if (!scheduler.isShutdown()) {

                    scheduler.shutdown();

                }

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        }

     

        public Scheduler getScheduler() {

            return scheduler;

        }

     

        public void setScheduler(Scheduler scheduler) {

            this.scheduler = scheduler;

        }

     

        public String transCron(String time) {

            String seconds = StringUtils.substringAfterLast(time, ":");

            String minute = StringUtils.substringAfter(time, ":").substring(0, 2);

            String hour = StringUtils.substringAfter(time, " ").substring(0, 2);

            String day = StringUtils.substringAfterLast(time, "-").substring(0, 2);

            String month = StringUtils.substringAfter(time, "-").substring(0, 2);

            return seconds + " " + minute + " " + hour + " " + day + " " + month + " ?";

        }

    }

     

     

    package schedule.quartz2;

     

    import lombok.Data;

     

    @Data

    public class QuartzEntity{

        private String jobName;//任务名称

        private String jobGroup;//任务分组

        private String description;//任务描述

        private String jobClassName;//执行类

        private String cronExpression;//执行时间

        private String triggerName;//执行时间

        private String triggerState;//任务状态

       

        private String oldJobName;//任务名称 用于修改

        private String oldJobGroup;//任务分组 用于修改

    }

     

     

    package schedule.quartz2;

     

    import org.quartz.Job;

    import org.quartz.JobExecutionContext;

    import org.quartz.JobExecutionException;

    import org.slf4j.Logger;

    import org.slf4j.LoggerFactory;

     

    public class MyJob implements Job {

     

        private Logger logger = LoggerFactory.getLogger(MyJob.class);

     

        @Override

        public void execute(JobExecutionContext context) throws JobExecutionException {

            try {

                logger.info("test】动态定时调度测试");

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

     

    package schedule.quartz2;

     

    import org.quartz.Job;

    import org.quartz.JobExecutionContext;

    import org.quartz.JobExecutionException;

    import org.slf4j.Logger;

    import org.slf4j.LoggerFactory;

     

    public class MyJob2 implements Job {

     

        private Logger logger = LoggerFactory.getLogger(MyJob2.class);

     

        @Override

        public void execute(JobExecutionContext context) throws JobExecutionException {

            try {

                logger.info("test】动态定时调度测试 ------------2");

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

     

    package schedule.quartz2;

     

    import java.util.List;

     

    public interface IJobService {

        List<QuartzEntity> listQuartzEntity(QuartzEntity quartz,Integer pageNo,Integer pageSize);

        Long listQuartzEntity(QuartzEntity quartz); 

    }

     

     

    package schedule.quartz2;

    import java.util.List;

     

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

    import org.springframework.util.StringUtils;

     

    @Service("jobService")

    public class JobServiceImpl implements IJobService {

     

        @Autowired

        private DynamicQuery dynamicQuery;

     

        @Override

        public List<QuartzEntity> listQuartzEntity(QuartzEntity quartz,

                Integer pageNo, Integer pageSize) {

            StringBuffer nativeSql = new StringBuffer();

            nativeSql.append("SELECT job.JOB_NAME as jobName,job.JOB_GROUP as jobGroup,job.DESCRIPTION as description,job.JOB_CLASS_NAME as jobClassName,");

            nativeSql.append("cron.CRON_EXPRESSION as cronExpression,tri.TRIGGER_NAME as triggerName,tri.TRIGGER_STATE as triggerState,");

            nativeSql.append("job.JOB_NAME as oldJobName,job.JOB_GROUP as oldJobGroup ");

            nativeSql.append("FROM qrtz_job_details AS job LEFT JOIN qrtz_triggers AS tri ON job.JOB_NAME = tri.JOB_NAME ");

            nativeSql.append("LEFT JOIN qrtz_cron_triggers AS cron ON cron.TRIGGER_NAME = tri.TRIGGER_NAME ");

            nativeSql.append("WHERE tri.TRIGGER_TYPE = 'CRON'");

            Object[] params = new  Object[]{};

            if(!StringUtils.isEmpty(quartz.getJobName())){//加入JobName搜索其他条件自行实现

                nativeSql.append(" AND job.JOB_NAME = ?");

                params = new Object[]{quartz.getJobName()};

            }

            return null;

        }

     

        @Override

        public Long listQuartzEntity(QuartzEntity quartz) {

            return 0L;

           

    //      StringBuffer nativeSql = new StringBuffer();

    //      nativeSql.append("SELECT COUNT(*)");

    //      nativeSql.append("FROM qrtz_job_details AS job LEFT JOIN qrtz_triggers AS tri ON job.JOB_NAME = tri.JOB_NAME ");

    //      nativeSql.append("LEFT JOIN qrtz_cron_triggers AS cron ON cron.TRIGGER_NAME = tri.TRIGGER_NAME ");

    //      nativeSql.append("WHERE tri.TRIGGER_TYPE = 'CRON'");

    //      return dynamicQuery.nativeQueryCount(nativeSql.toString(), new Object[]{});

        }

    }

     

     

    package schedule.quartz2;

    import java.util.List;

    /**

     * 扩展SpringDataJpa, 支持动态jpql/nativesql查询并支持分页查询

     * 使用方法:注入ServiceImpl

     */

    public interface DynamicQuery {

       

       

    }

     

     

    package schedule.quartz2;

    import org.springframework.stereotype.Repository;

     

    @Repository

    public class DynamicQueryImpl implements DynamicQuery {

       

       

    }

     

     

    <beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:p="http://www.springframework.org/schema/p"

        xmlns:task="http://www.springframework.org/schema/task"

        xmlns:context="http://www.springframework.org/schema/context"

        xmlns:aop="http://www.springframework.org/schema/aop"

        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/task http://www.springframework.org/schema/task/spring-task.xsd">

        <context:component-scan base-package="schedule.quartz2"></context:component-scan>

     

        <bean id="startQuartz" lazy-init="true" autowire="no"

            class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

            <property name="triggers">

                <list>

                    <!--

                    <ref bean="cronTrigger" />

                     -->

                </list>

            </property>

        </bean>

     

        <bean id="quartzManager" class="schedule.quartz2.QuartzManager" lazy-init="false" init-method="startJobs">

            <!--这个对象一定要注入,这样类才能进行管理,还有在类型要用get set方法,不然会报错。 -->

            <property name="scheduler" ref="startQuartz" />

        </bean>

     

     

        <!-- 高级设置, 给作业传递数据 -->

        <bean id="complexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

            <property name="jobClass" value="schedule.quartz2.MyJob" />

     

            <property name="jobDataMap">

                <map>

                    <entry key="timeout" value="1" />

                </map>

            </property>

     

            <property name="durability" value="true" />

        </bean>

     

        <!-- 计划触发器,使用 CronTriggerFactoryBean -->

        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">

            <property name="jobDetail" ref="complexJobDetail" />

            <!--<property name="cronExpression" value="0/5 * * ? * SAT-SUN" /> -->

            <property name="cronExpression" value="0/5 * * ? * *" />

        </bean>

    </beans>

     

     

     

     

     

     

     

    package schedule.quartz2;

     

    import java.util.ArrayList;

    import java.util.Arrays;

    import java.util.List;

     

    import org.quartz.SchedulerException;

    import org.springframework.beans.BeansException;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class SpringTaskAnnotationTest {

        public static void main(String[] args) throws BeansException, InterruptedException, SchedulerException {

            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/schedule/quartz2/spring-mvc.xml");

           

            QuartzManager quartzManager = applicationContext.getBean(QuartzManager.class);

            quartzManager.initJobs();

           

            List<SingleTrigger> triggers = new ArrayList<SingleTrigger>();

            triggers.add(new SingleTrigger("a1","b1","0/1 * * ? * *"));

            triggers.add(new SingleTrigger("a2","b2","0/2 * * ? * *"));

            triggers.add(new SingleTrigger("a3","b3","0/3 * * ? * *"));

            triggers.add(new SingleTrigger("a4","b4","0/4 * * ? * *"));

           

            quartzManager.addJobs("xxxx", "yyyy", triggers ,MyJob.class, "0/3 * * ? * *");

           

            Thread.sleep(7000);

            System.out.println("--- start to change cron ---");

           

            quartzManager.removeTrigger("xxxx", "yyyy", "a1","b1");

            quartzManager.modifyJobTime("xxxx", "yyyy", "a2","b2", "0/5 * * ? * *");

           

            Thread.sleep(7000);

           

            System.out.println("--- start to replace cron ---");

            triggers = new ArrayList<SingleTrigger>();

            triggers.add(new SingleTrigger("a5","b5","0/1 * * ? * *"));

            quartzManager.addJobs("xxxx", "yyyy", triggers ,MyJob.class, "0/3 * * ? * *");

           

            System.out.println(quartzManager.getScheduler().getTriggerGroupNames());

           

           

            Thread.sleep(200000);

        }

    }

     

     

     

     

     

    例子 3 Scheduler start/stop java方式

    java方式初始化

     

    package schedule.quartz3;

     

    import org.quartz.JobBuilder;

    import org.quartz.JobDetail;

    import org.quartz.Scheduler;

    import org.quartz.SimpleScheduleBuilder;

    import org.quartz.Trigger;

    import org.quartz.TriggerBuilder;

    import org.quartz.impl.StdSchedulerFactory;

     

    public class QuartzTest {

        public static void main(String[] args) throws Exception {

            // 从调度程序工厂获取一个调度程序的实例

            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

     

            // 显示调度程序的名称(这里会展示我们在quartz.properties文件中的名称)

            System.out.println("scheduleName = " + scheduler.getSchedulerName());

     

            /**

             * 重要: 定义一个job,并绑定到我们自定义的HelloJobclass对象

             * 这里并不会马上创建一个HelloJob实例,实例创建是在scheduler安排任务触发执行时创建的 这种机制也为后面使用Spring集成提供了便利

             */

            JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();

     

            // 声明一个触发器,现在就执行(schedule.start()方法开始调用的时候执行);并且每间隔2秒就执行一次

            // 触发器

            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();

            // 触发器名,触发器组

            triggerBuilder.withIdentity("trigger1", "group1");

            triggerBuilder.startNow();

            // 触发器时间设定

    //      triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * ? * *"));

        triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever());

           

           

            Trigger trigger = triggerBuilder.build();

     

            // 告诉quartz使用定义的触发器trigger安排执行任务job

            scheduler.scheduleJob(job, trigger);

     

            // 启动任务调度程序,内部机制是线程的启动

            scheduler.start();

     

            // 关闭任务调度程序,如果不关闭,调度程序schedule会一直运行着

            // scheduler.shutdown();

     

        }

    }

     

    package schedule.quartz2;

     

    import org.quartz.Job;

    import org.quartz.JobExecutionContext;

    import org.quartz.JobExecutionException;

    import org.quartz.impl.triggers.CronTriggerImpl;

    import org.quartz.impl.triggers.SimpleTriggerImpl;

    import org.slf4j.Logger;

    import org.slf4j.LoggerFactory;

     

    public class MyJob implements Job {

        private Logger logger = LoggerFactory.getLogger(MyJob.class);

     

        @Override

        public void execute(JobExecutionContext context) throws JobExecutionException {

            try {

                if(context.getTrigger() instanceof CronTriggerImpl){

                    CronTriggerImpl xxx = ((CronTriggerImpl)context.getTrigger());

                   

                    logger.info("动态定时调度测试 job group:"+xxx.getJobGroup()+", job name:"+xxx.getJobName() +", trigger group:"+xxx.getGroup()+", trigger name:"+xxx.getName()+",  cronExpression "+xxx.getCronExpression());

                }else if(context.getTrigger() instanceof SimpleTriggerImpl){

                    SimpleTriggerImpl xxx = ((SimpleTriggerImpl)context.getTrigger());

                   

                    logger.info("动态定时调度测试 job group:"+xxx.getJobGroup()+", job name:"+xxx.getJobName() +", trigger group:"+xxx.getGroup()+", trigger name:"+xxx.getName()+",  cronExpression "+xxx);

                }

               

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

     

    例子4 注入service

    SchedulerFactoryBean+AdaptableJobFactory+QuartzJobBean

     

     

     

    Caused by: java.lang.NoSuchMethodError: org.springframework.util.ReflectionUtils.accessibleConstructor(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/reflect/Constructor;

     

    一般是引入了两个重复的spring Jar包,如既引入了spring.framework 又引入了spring.core,去掉一个就好

    用tree方式查看

     

     

     

     

     

     

     

     

        1. XXL-JOB

     

    分布式任务 XXL-JOB,是一个轻量级分布式任务调度框架,支持通过 Web 页面对任务进行 CRUD 操作,支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,支持在线配置调度任务入参和在线查看调度结果。

     

    https://github.com/xuxueli/xxl-job

     

    https://www.cnblogs.com/xuxueli/p/5021979.html

     

     

     

     

     

     

     

     

     

     

     

        1. Elastic-Job

    分布式任务 Elastic-Job,是一个分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。定位为轻量级无中心化解决方案,使用 jar 包的形式提供分布式任务的协调服务。支持分布式调度协调、弹性扩容缩容、失效转移、错过执行作业重触发、并行调度、自诊。

     

     

    https://gitee.com/52itstyle/spring-boot-quartz

     

     

  • 相关阅读:
    hyperledger fabric相关记录
    prometheus相关文章
    zookeeper和kafka的使用
    ubuntu1604 golang环境
    haproxy keepalived和nodejsv9的容器镜像所需文件
    图片相似算法
    oracle lpad rpad
    网站资料
    Win7 wifi热点设置
    Oracle存储过程编写经验和优化措施
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710090.html
Copyright © 2011-2022 走看看