Quartz 定时器之----公司内部二次元封装使用框架设计demo

公司内部利用quartz ( 定时器 )开源框架,二次元封装为自己项目使用定时器框架,这里我通过简单的代码来描述  二次元开发的框架结构。下面是我贴出的代码。

设计的几个类名:

     class QuartsMain : 为框架设计的入口点。

   class JobMain implements Job : 为工作的入口点,任何定时任务都要执行的步骤,负责启动任务  实际  job(QuartzEvent  的子类)任务。

      interface QuartzEvent  :  为统一的任务执行事件的接口,该接口中有一execute(ArrayList<? extends Object> params); 方法,共子类实现。该接口的子类就是实际的任务执行逻辑代码。

      class ExcuteEvent implements QuartzEvent : 为QuartzEvent的子类,实现execute方法,执行实际的任务逻辑。

     class TriggerAndJob : 为框架设计的辅助类,主要封装触发器CronTrigger(为Quartz框架中类) 和 JobDetail(为Quartz框架中类)

      quartz_action.xml : 为配置定时任务的文件,内容为标签格式,大概样式为:

                 
 <action class = '这里设置具体的执行类(QuartzEvent  的子类)',executeTime='执行的时间的表达式'>
        <list>   这里的标签数据会对应到QuartzEvent 接口中的execute方法中的参数list,不写list标签数据则list参数中没有数据
             <param typy='Integer'>X属性值</param>  java的普通类型
              <param typy='aaa.bbb.ccc.Test'>                java的引用类型
                     <prop  typy=''></prop>

              </param>

                               该seq 标签为一个序列化标签,

               <seq typy='aaa.bbb.ccc.Good'>这里是序列化对象的二进制文件地址(指定为protostuff工具进行序列化)</seq>  

                                 这里是从spring容器中拿取对象

                                 <springBean typy = 'aaa.bbb.ccc.User' bName = 'user'/>

                  ...  ...  ... ...   ....   ...     ... ...  ..
            </list>   
 </action>)。

QuartzActionParse : 该类为解析quartz_action.xml类,最终返回一个ArrayList<Map<String,?  extends  Object>>  quartzList 中的每一个map元素都为一个具体的执行任务。该类这里不具体提供,本demo中只是模拟了一下,解析出的2条  map数据,

现在整个框架的简单的概述了一下,接下来是我提供的demo代码,主要共读者学习 封装定时框架设计的模式:

 QuartsMain : 代码  

package com.jvm.others.quartz_;


import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;


import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
/**该类为 入口点
 * @author pc
 *
 */
public class QuartsMain {

//创建打印日志的Logger类
static final Logger logger = LoggerFactory.getLogger(JobMain.class);





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


Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //创建一个调度器


   /****
* 这里模拟从quartz_action.xml中读取一个quartz节点,一个quartz节点代表一个定时任务,并把这一节点的信息封装为一个map,
* 这里不具体实现(因为不叫复杂这里说一下实现的结构,
* 首先:规定标签:
* <action class = '这里设置具体的执行类',executeTime='执行的时间的表达式'>
* <list>   这里写参数list
*    <param typy='Integer'>X属性值</param>  这里是list中的元素
*    <param typy='aaa.bbb.ccc.Test'>
*      <prop  typy=''></prop>
*    </param>
*    <seq typy='aaa.bbb.ccc.Good'>这里是序列化对象(指定为protostuff工具进行序列化)</seq>
*     ......
* </list>
* </action>)。
*/
boolean ok = true;
int i = 0;
   
   //此处模拟多个要执行的定时任务
while(ok){
String randomUUID = UUID.randomUUID().toString();

/**
* 这里模拟从 quartz_action.xml(该文件封装了定时任务) 文件中读取数据,一条action标签对应的数据就是一个map,
* 实际框架设计的时候直接全部读取出来返回一个list集合,集合中的每个对象都是一个map
*/
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("Action", "com.jvm.others.quartz_.ExcuteEvent"); //执行事件的类
hashMap.put("executeTime", "0/2 * * * * ?");// 执行的时间
//hashMap.put("Method", "execute");
ArrayList<Object> params = new ArrayList<>();  //执行事件绑定的参数
params.add("this is first demo hello word!  :  "+randomUUID);
hashMap.put("Param", params);


TriggerAndJob trigger_and_job = createTriggerAndJobDetail(hashMap);  //根据quartz_action.xml文件的中的action标签创建对应的触发器和工作
     


CronTrigger trigger = trigger_and_job.getCt(); //拿到触发器

JobDetail jobDetail = trigger_and_job.getJd();  //拿到执行的job

   //注册任务和触发器 
   scheduler.scheduleJob(jobDetail, trigger); // 将jobDetail 和 指定的触发器联系在一起,主要将  jobDetail中的数据  
                                              // 传给 指定trigger中的  JOb类中的 execute方法中的参数
i++;
if(i==2)
break;
}
 
     
   scheduler.start();

   logger.info("任务已经开始调用————"+new Date());

}



 

public static TriggerAndJob createTriggerAndJobDetail(Map<? extends Object, ? extends Object> map){
String randomUUID = UUID.randomUUID().toString();

JobDetail jobDetail = JobBuilder.newJob(JobMain.class)           //创建job描述

         .withDescription("this is quarts test")
         
         .withIdentity("name"+randomUUID,"group"+randomUUID)
         
         .build();
//这里模拟从外部文件中读取到的数据,
jobDetail.getJobDataMap().put("Action", map.get("Action"));  //事件类
//jobDetail.getJobDataMap().put("Method", map.get("Method"));  //要执行的方法
jobDetail.getJobDataMap().put("Param", map.get("Param"));    //参数值
String executeTime = (String)map.get("executeTime");//"0/2 * * * * ?" 获得执行的时间

   long time = System.currentTimeMillis()+3000L;                   //创建开始的时间

   
   Date start_date = new Date(time);                                     //创建执行的时间点
   //  `/` 代表  间隔增加  例如: 0/2  代表 0,2 ,4 ,6 ... , 2/4 代表 2 ,6 , 10 ,14 ... 。 
   // * 代表秒,* * 代表分,* * * 代表时 * * * * 代表天
   // ? 指定规则  一周的一天或则一个月中的一天 
   // , 指定附加时间点,必须是一周里面的一天,如: MON,WED,指的是   周一和周三  开始执行
   // L 英文last的缩写,代表最后一天,使用在week和month 中 ,在月中代表月的最后一天,则在星期中表示 星期6,
   // 也可以这样使用6L 一个星期中的星期五,5L 一个星期中的星期四
   
   
   /**
    *  实际使用的时候参考下面的表达式 
    *  
    *               表示式 说明
    * 
    *                
          0 0 12 * * ?                     每天12点运行
          0 15 10 ? * *                     每天10:15运行
          0 15 10 * * ?                      每天10:15运行
          0 15 10 * * ? *                      每天10:15运行
          0 15 10 * * ? 2008              在2008年的每天10:15运行
          0 * 14 * * ?                      每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。
          0 0/5 14 * * ?                      每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。
          0 0/5 14,18 * * ?              每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。
          0 0-5 14 * * ?                      每天14:00点到14:05,每分钟运行一次。
          0 10,44 14 ? 3 WED       3月每周三的14:10分到14:44,每分钟运行一次。
          0 15 10 ? * MON-FRI               每周一,二,三,四,五的10:15分运行。
          0 15 10 15 * ?                       每月15日10:15分运行。
          0 15 10 L * ?                       每月最后一天10:15分运行。
          0 15 10 ? * 6L                        每月最后一个星期五10:15分运行。
          0 15 10 ? * 6L 2007-2009 在2007,2008,2009年每个月的最后一个星期五的10:15分运行。
          0 15 10 ? * 6#3                        每月第三个星期五的10:15分运行。
    * 
    */
   
   
   
   //CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateBuilder.FRIDAY, 16, 01) 指在星期5 16点1分的时候开始执行
   CronTrigger trigger = TriggerBuilder.newTrigger()
                      .withDescription("this is trigger demo")    //设置描述
                              .withIdentity("triggerName"+randomUUID, "triggerGroup"+randomUUID)//用于辨识唯一的触发器 
                              .startAt(start_date)                        //设值准备开始的时间
                              .withSchedule(CronScheduleBuilder.cronSchedule(executeTime)) //设置轮询(真正事件执行的时间)
                              .build();   
   
   TriggerAndJob triggerAndJob = new TriggerAndJob(trigger, jobDetail); //创建一个封装Trigger和Job的一个对象
   
   return triggerAndJob;//返回出去
   
   
   
}





}


JobMain 代码:

package com.jvm.others.quartz_;


import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;


/**实现Job
 * @author 曹明杰
 *
 */
public class JobMain implements Job{  


@Override
public void execute(JobExecutionContext context) throws JobExecutionException {

JobDetail jobDetail = context.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();

//这里我们提前知道获得值的类型

String Action = (String)jobDataMap.get("Action");      // 拿到执行类,该类实现了QuartzEvent接口,接口中就一个execute方法

String Method = "execute";      // 拿到执行类中要执行的方法,这是固定的规范

Object Param = jobDataMap.get("Param");                // 执行时所需要的参数

try {
Class<?> actionClazz = Class.forName(Action);      //利用反射拿取该对象,在实际开发中不要用JDK反射,很慢,要用reflectASM 库进行反射设计执行。

/***
* 实际开发中,这里应该判断actionClazz的   接口  是哪个QuartzEvent接口(这里的简单demo并没有设计QuartzEvent接口,只是给读者说一下实际开发的设计结构),
* 我们应该设置很多不同的  QuartzEvent  接口,每个接口  代表   一种逻辑操作
*/
java.lang.reflect.Method method_ = actionClazz.getMethod(Method, Param.getClass());  //拿取实际的方法

//执行该方法
method_.invoke(actionClazz.newInstance(), Param); 



} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println("作业已经执行。。。");

}


}


QuartzEvent  :代码


package com.jvm.others.quartz_;


import java.util.ArrayList;




/**此处定义了  定时器执行 的抽象方法,即: 要想定时执行每个任务,则需要实现该接口中的方法,
 * 在该方法中实现具体的业务逻辑,
 * @author 曹明杰
 *
 */
public interface QuartzEvent {


/**
* @param params 存放 方法执行时的 参数值,存放参数有序
*/
void execute(ArrayList<? extends Object> params);
}


ExcuteEvent : 代码

package com.jvm.others.quartz_;


import java.util.ArrayList;




/**  执行事件,实际设计中最好定义指定执行的接口方法,
 * 
 *   这样可以更加灵活的执行具体的事件(针对于  事件带参数 ,不带参数,和带参数的个数)。
 * @author 曹明杰
 *
 */
public class ExcuteEvent implements QuartzEvent {
 

@Override
public void execute(ArrayList<? extends Object> params) {
Object word = params.get(0);
System.out.println("业务正在执行   :"+ word);
}


}


TriggerAndJob  代码:

package com.jvm.others.quartz_;


import org.quartz.CronTrigger;
import org.quartz.JobDetail;


/**该类封住了触发器和触发器对应的执行job
 * @author 曹明杰
 *
 */
public class TriggerAndJob {


private CronTrigger ct;  //触发器

private JobDetail jd;    //工作执行器


public CronTrigger getCt() {
return ct;
}


public void setCt(CronTrigger ct) {
this.ct = ct;
}


public JobDetail getJd() {
return jd;
}


public void setJd(JobDetail jd) {
this.jd = jd;
}


public TriggerAndJob(CronTrigger ct, JobDetail jd) {
super();
this.ct = ct;
this.jd = jd;
}



}

          

总结:刚来进入新公司,每天都有点慌张,现在把项目用到的定时任务封装的二次元框架的设计思想在这里说一下,平复我内心的紧张感。也增加自己的知识面。

                                                           

   





猜你喜欢

转载自blog.csdn.net/qq_29499107/article/details/80392128