使用Cglib动态代理封装Quartz

一.前言

最近在学习定时任务框架Quartz,怎么说呢,就是感觉Quartz提供的Api使用起来并不是那么方便!一个定时任务的执行至少需要三个组件Job、Trigger、Scheduler!用得不太开心,于是决定将一些简单常用的任务模式封装一下。于是这篇博客诞生了!

二.工具简介

这个小工具封装了以下三种模式的任务
1.Cron表达式模式 --> 按照cron表达式的规则执行任务
2.固定延时模式 --> 等待一个固定时间后再执行该任务
3.循环模式 --> 按照某个固定的时间间隔重复执行一个任务(重复次数可控)

三.下载地址

下载地址:网盘地址
提 取 码:kk2n

四.工具的使用

4.1 定义定时任务组件

定义任务组件十分简单,编写一个普通的类就好了,不用实现接口不用继承其他父类也不用任何注解!
1.任务组件:MyJob.java

import quartz.ann.Job;

public class MyJob {


    public void showTime(String k){
        System.out.println(DateUtils.time()+" ==> showTime("+k+") [每分钟的第30秒开始执行,每3秒执行一次] Running......");
    }

    public void time(){
        System.out.println(DateUtils.time()+" ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......");
    }

    public void fixed(){
        System.out.println(DateUtils.time()+" ==> fixed() [延时7秒执行] Running......");
    }

    public void ttt(){
        System.out.println("kokokok");
    }
}

4.2 使用@Job注解定义触发规则

2.使用@Job定义触发规则:MyJob.java

@Job注解属性描述
cron :使用Cron表达式来描述触发规则
fixedDelay:[固定延时触发]在主动调用该注解标注的方法时,会先延迟fixedDela毫秒后执行一次后结束。单位:ms

performInterval + performCount:[循环触发]
performInterval:任务执行的间隔时间 默认:1秒
performCount:循环执行的次数,值小于1时表示无限循环的执行 默认:-1

import quartz.ann.Job;

public class MyJob {

    //每分钟的第30秒开始执行,每3秒执行一次
    @Job(cron = "30/3 * * * * ?")
    public void showTime(String k){
        System.out.println(DateUtils.time()+" ==> showTime("+k+") [每分钟的第30秒开始执行,每3秒执行一次] Running......");
    }

    //调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒
    @Job(performInterval = 2*1000L,performCount = 4)
    public void time(){
        System.out.println(DateUtils.time()+" ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......");
    }

    //调用后延时7秒执行
    @Job(fixedDelay = 7*1000L)
    public void fixed(){
        System.out.println(DateUtils.time()+" ==> fixed() [延时7秒执行] Running......");
    }

    public void ttt(){
        System.out.println("kokokok");
    }
}

4.3 得到组件代理并执行任务

使用QuartzProxy的getProxy方法工具类得到一个任务组件的代理对象

import org.quartz.SchedulerException;
import quartz.cglib.QuartzProxy;

public class JobTestMain {

    public static void main(String[] args) throws SchedulerException {
    	//得到任务组件的代理对象
        MyJob job = QuartzProxy.getProxy(MyJob.class);
        //执行定时任务
        job.time();
        job.showTime("FK");
        job.showTime("JACK");
        job.ttt();
        job.fixed();
    }


}

控制台:

kokokok
2020-07-25 21:41:27 ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......
2020-07-25 21:41:29 ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......
2020-07-25 21:41:30 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:30 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:31 ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......
2020-07-25 21:41:33 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:33 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:33 ==> time() [调用时立即执行,重复执行4次后结束,执行的时间间隔为2秒] Running......
2020-07-25 21:41:34 ==> fixed() [延时7秒执行] Running......
2020-07-25 21:41:36 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:36 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:39 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:39 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:42 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:42 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:45 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:45 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:48 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:48 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:51 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:51 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:54 ==> showTime(JACK) [每分钟的第30秒开始执行,每3秒执行一次] Running......
2020-07-25 21:41:54 ==> showTime(FK) [每分钟的第30秒开始执行,每3秒执行一次] Running......

五.工具源码分析

5.1 Cglib代理器

CglibProxg.java

package quartz.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

/**
 * Cglib动态代理
 */
public abstract class CglibProxy {

    public static <T> T getCglibProxyObject(Class<T> clazz, MethodInterceptor methodInterceptor){
        final Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(methodInterceptor);
        return (T) enhancer.create();
    }
}


5.2 代理逻辑封装器

QuartzMethodInterceptor.java


import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import quartz.TargetJobRun;
import quartz.ann.Job;
import quartz.job.LuckyJob;

import java.lang.reflect.Method;
import java.util.UUID;

import static org.quartz.DateBuilder.futureDate;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static quartz.constant.Constant.LUCKY_JOB;
import static quartz.constant.Constant.LUCKY_JOB_GROUP;

public class QuartzMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object targetObj, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        if(method.isAnnotationPresent(Job.class)){
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            String jtname= UUID.randomUUID().toString();
            Job quartzJob = method.getAnnotation(Job.class);
            //封装任务逻辑
            TargetJobRun targetJobRun=new TargetJobRun(targetObj,methodProxy,params);
            JobDetail jobDetail = JobBuilder.newJob(LuckyJob.class)
                    .withIdentity(jtname, LUCKY_JOB_GROUP)
                    .build();
            //将任务逻辑put到上下文中
            jobDetail.getJobDataMap().put(LUCKY_JOB,targetJobRun);
            Trigger trigger =getTrigger(quartzJob,jtname);
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start();
            return null;
        }
        return methodProxy.invokeSuper(targetObj,params);
    }

    //根据@Job注解的属性构造相应的Trigger
    private Trigger getTrigger(Job job,String triggerName){
        final String cron = job.cron();
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerName, LUCKY_JOB_GROUP);

        //Cron表达式构建Trigger
        if(!"".equals(cron)){
            Trigger trigger = triggerBuilder.startNow()
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            return trigger;
        }
        long fixedDelay = job.fixedDelay();
        int count = job.performCount();
        long interval = job.performInterval();

        //构建一个固定延时且只会执行一次的Trigger
        if(fixedDelay!=-1L){
            Trigger trigger =triggerBuilder
                    .startAt(futureDate((int) fixedDelay, DateBuilder.IntervalUnit.MILLISECOND))
                    .build();
            return trigger;
        }

        //构建一个相隔固定时间一次执行的Trigger(永不结束)
        if(count<1){
            Trigger trigger =triggerBuilder
                    .withSchedule(simpleSchedule()
                            .withIntervalInMilliseconds(interval)
                            .repeatForever())
                    .build();
            return trigger;
        }

        //构建一个相隔固定时间一次执行,且执行count次后会结束的Trigger
        Trigger trigger = triggerBuilder
                .withSchedule(simpleSchedule().withIntervalInMilliseconds(interval).withRepeatCount(count-1))
                .build();
        return trigger;

    }
}

5.3 任务逻辑包装器

TargetJobRun.java


import net.sf.cglib.proxy.MethodProxy;

public class TargetJobRun {

    private Object job;

    private MethodProxy jobMethodProxy;

    private Object[] jobParams;

    public TargetJobRun(Object job, MethodProxy jobMethodProxy, Object[] jobParams) {
        this.job = job;
        this.jobMethodProxy = jobMethodProxy;
        this.jobParams = jobParams;
    }

    public Object getJob() {
        return job;
    }

    public void setJob(Object job) {
        this.job = job;
    }

    public MethodProxy getJobMethodProxy() {
        return jobMethodProxy;
    }

    public void setJobMethodProxy(MethodProxy jobMethodProxy) {
        this.jobMethodProxy = jobMethodProxy;
    }

    public Object[] getJobParams() {
        return jobParams;
    }

    public void setJobParams(Object[] jobParams) {
        this.jobParams = jobParams;
    }

    public void run(){
        try {
            jobMethodProxy.invokeSuper(job,jobParams);
        } catch (Throwable e) {
           throw new RuntimeException(e);
        }
    }
}

5.4 Quartz Job

LuckyJob.java

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import quartz.TargetJobRun;

import static quartz.constant.Constant.LUCKY_JOB;

public class LuckyJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        TargetJobRun targetJobRun = (TargetJobRun) context.getJobDetail().getJobDataMap().get(LUCKY_JOB);
        targetJobRun.run();
    }
}

5.5 常量

Constant.java

public class Constant {

    public final static String LUCKY_JOB="501205ffeaa16b4fc18957c81d2eb283";

    public final static String LUCKY_JOB_GROUP="LuckyJG";

}

六.原理

在代理方法中编写Quartz的模版代码,并将原方法的执行逻辑封装成一个TargetJobRun对象,然后将这个对象通过JobDetail对象put到JobExecutionContext上下文对象中,Quartz在运行LuckyJob的execute方法时会将这个TargetJobRun对象从上下文中取出并执行,这样就达到了业务逻辑与QuartzJob分离的目的!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucky:)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值