Quartz 学习笔记

例子1:java例子

Job是Quartz中的一个接口,接口下只有execute方法,在这个方法中编写业务逻辑。

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("任务"+ DateUtil.now());
    }
}

每隔两秒调度执行例子

public class MyScheduler {
    public static void main(String[] args) throws Exception {
         // 创建一个JobDetail实例,将该实例与MyJob Class绑定
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group").build();
        //构建Trigger实例,每隔2s执行一次
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ? ")).build();
        //从调度程序工厂获取一个调度程序的实例
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        //告诉quartz使用定义的触发器trigger安排执行任务job
        scheduler.scheduleJob(jobDetail, cronTrigger);
        //启动任务调度程序,内部机制是线程的启动
        scheduler.start();
    }
}

结果

任务2020-11-28 15:26:14
任务2020-11-28 15:26:16
任务2020-11-28 15:26:18
任务2020-11-28 15:26:20
任务2020-11-28 15:26:22
......

结论

JobDetail用来绑定Job,为Job实例提供许多属性:

        JobDetail绑定指定的Job,每次Scheduler调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。

为什么设计成JobDetail + Job,不直接使用Job

        JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

Trigger是Quartz的触发器,会去通知Scheduler何时去执行对应Job。

例子2:传参 JobExecutionContext和JobDataMap

在创建JobDetail和Trigger时可以给JobExecutionContext传入以下几个类型参数,让定时任务拿到这些参数
String,Integer,Long,Float,Double,Boolean,JobDataMap(Map实现类)

public class MyScheduler {
    public static void main(String[] args) throws Exception {
        // 创建一个JobDetail实例,将该实例与MyJob Class绑定
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group")
                //传入自定义参数
                .usingJobData("float",1f)
                .usingJobData("String","字符串1")
                .build();
        //构建Trigger实例,每隔2s执行一次
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ? "))
                //传入自定义参数
                .usingJobData("float",2f)
                .usingJobData("String","字符串2")
                .build();
        //从调度程序工厂获取一个调度程序的实例
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        //告诉quartz使用定义的触发器trigger安排执行任务job
        scheduler.scheduleJob(jobDetail, cronTrigger);
        //启动任务调度程序,内部机制是线程的启动
        scheduler.start();
    }
}
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //获取合并后的JobDataMap,但是相同key的value会被trigger覆盖
        //可以用context.getJobDetail()/context.getTrigger()来分别获取key/value
        JobDataMap map = context.getMergedJobDataMap();
        String[] keys = map.getKeys();
        for (String key : keys) {
            System.out.println(key+map.get(key));
        }
        System.out.println("任务"+ DateUtil.now());
    }
}

结论

JobExecutionContext是什么

  • 当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
  • Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。

JobDataMap是什么?

  1. 在进行任务调度时JobDataMap存储在JobExecutionContext中,非常方便获取
  2. JobDataMap可以用来装载任何可以序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它
  3. JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法用来存取数据基本数据类型。

例子3:Spring整合Quartz

@Component("myWork")
public class MyWork {
    public void add(){
        System.out.println("add"+ DateUtil.now());
    }
}
    <!-- 自定义任务 -->
    <bean id="myDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!--定时任务目标类-->
        <property name="targetObject" ref="myWork"></property>
        <!--要定时的方法-->
        <property name="targetMethod" value="add"></property>
        <property name="concurrent" value="false"/>
    </bean>
    
    <!-- 调度工厂 -->
    <bean id="scheduler" lazy-init="true" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobDetails">
            <list>
                <ref bean="myDetail"/>
            </list>
        </property>
        <property name="triggers">
            <list>
                <ref bean="myTrigger"/>
            </list>
        </property>
    </bean>

    <!-- 定义触发时间 -->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="myDetail"></property>
        <property name="cronExpression">
        	<!-- 每两秒执行 -->
            <value>0/2 * * * * ?</value>
        </property>
    </bean>

启动tomcat

add2020-11-28 19:40:36
add2020-11-28 19:40:38
add2020-11-28 19:40:40
add2020-11-28 19:40:42
......

结论

Spring创建JobDetail的两种方式

配置Spring的任务调度抽象层简化了任务调度,在Quartz的基础上提供了更好的调度对象。Spring使用Quartz框架来完成任务调度,创建Quartz的作业Bean(JobDetail),有以下两种方法:

  1. 利用JobDetailBean包装QuartzJobBean子类(即Job类)的实例。
  2. 利用MethodInvokingJobDetailFactoryBean工厂Bean包装普通的Java对象(即Job类)。

说明

        采用第一种方法 创建job类,一定要继承QuartzJobBean ,实现 executeInternal(JobExecutionContext jobexecutioncontext)方法,此方法就是被调度任务的执行体,然后将此Job类的实例直接配置到JobDetailBean中即可。这种方法和在普通的Quartz编程中是一样的。

        采用第二种方法 创建Job类,无须继承父类,直接配置MethodInvokingJobDetailFactoryBean即可。但需要指定一下两个属性:

  • targetObject:指定包含任务执行体的Bean实例。
  • targetMethod:指定将指定Bean实例的该方法包装成任务的执行体。
  • concurrent:是否并发进行,false,表示不可以并发,其他任务将在当前任务完成后在调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值