zoukankan      html  css  js  c++  java
  • java学习心得——Quartz 自定义定时器的操作

    最近在邮件提醒的业务里,需要根据后台每个项目的配置定时的向项目联系人推送邮件提醒,这时我明白需要定时任务了,作为java小白,我向同事做了咨询,推荐我使用Quartz,以下便是我在项目里的学习心得。

    首先配置文件:

    依赖的jar包

            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>1.8.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>3.2.17.RELEASE</version>
            </dependency>

    配置文件:

    <bean id="taskExecutor"
              class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
            <property name="corePoolSize" value="1"/>
            <property name="maxPoolSize" value="20"/>
            <property name="queueCapacity" value="100"/>
            <property name="keepAliveSeconds" value="2000"/>
            <property name="rejectedExecutionHandler">
                <bean class="java.util.concurrent.ThreadPoolExecutor$AbortPolicy"/>
            </property>
        </bean>
    
        <bean id="quartzManager" class="com.imaster.admin.web.schemajob.QuartzManager">
            <property name="scheduler" ref="schedulerManager"/>
        </bean>
        <bean id="quartzManagerJobDetail"
              class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
            <property name="targetObject" ref="quartzManager"/>
             <!--自定义定时管理类的的执行方法, -->

    <property name="targetMethod" value="reScheduleJob"/>
            <property name="concurrent" value="false"/>
        </bean>
        <bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
            <property name="jobDetail" ref="quartzManagerJobDetail"/>
            <!-- 延时0秒 执行任务 -->
            <property name="startDelay" value="0"/>
            <!-- 任务执行周期 1min 是自定义定时任务管理类的执行间隔,以毫秒为单位-->
            <property name="repeatInterval" value="60000"/>
        </bean>
        <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->
        <bean id="schedulerManager" lazy-init="false" autowire="no"
              class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="cronTriggerBean"/>
                </list>
            </property>
            <property name="jobFactory" ref="jobFactory"></property>
            <property name="taskExecutor" ref="taskExecutor"/>
        </bean>
        <!--注意标记有背景色的这两行很重要是为了在执行方法中能够注入到需要的service-->
        <bean id="jobFactory" class="com.imaster.admin.web.schemajob.JobAdapter"></bean>
    quartzManager定义自己的的定时器管理类
    1.读取数据库的定时任务的设置数据
    2.添加新的定时任务
    3.删除已取消的定时任务
    4.更新已有的定时任务
    
    
    package com.imaster.admin.web.schemajob;
    
    import com.imaster.admin.model.vo.TaskVo;
    import com.imaster.admin.shared.service.version2.ExhibitorReserveExhibitionService;
    import com.imaster.constant.ApplicationConfig;
    import com.imaster.shared.enums.TaskTypeEnum;
    import com.imaster.shared.model.ExhibitorReserveExhibition;
    import org.quartz.JobDataMap;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.slf4j.Logger;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.CronTriggerBean;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author wanghh
     * 2020/5/9 11:45
     */
    public class QuartzManager implements BeanFactoryAware {
    
        private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ApplicationConfig.SERVER_NAME);
    
        private Scheduler scheduler;
    
        private static BeanFactory beanFactory;
        @Autowired
        ExhibitorReserveExhibitionService reserveExhibitionService;
    
    
        /**
         * 定时要执行的方法类。
         */
        public void reScheduleJob() {
            // 1.读取数据库中的任务列表。
    
            //获取短信定时任务
            List<ExhibitorReserveExhibition> list = reserveExhibitionService.selectList(null);
            for (ExhibitorReserveExhibition item : list
            ) {
                TaskVo taskVo = new TaskVo();
                taskVo.setTaskId(item.getId());
                taskVo.setTaskType(TaskTypeEnum.EXHIBITOR_RESERVE.getCode());
                taskVo.setCronExpression(String.format("0 %s %s * * ? ",item.getAcceptEmailMinute(),item.getAcceptEmailHour()));
                if (item.getDeleted() == 1 || item.getEnabled() == 0||item.getAcceptEmailRuleTime()==0) {
                    //去掉过时的任务
                    removeExpireTasks(taskVo);
                } else {
                    configSchedul(taskVo);
                }
            }
        }
    
        /**
         * 移除过期任务
         *
         * @param bo
         */
        private void removeExpireTasks(TaskVo bo) {
            try {
                CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP);
                if (trigger != null) {
                    logger.info("==移除任务==" + bo.getTaskId() + "name" + bo.getTaskType());
                    scheduler.pauseTrigger(trigger.getName(), trigger.getGroup());// 停止触发器
                    scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());// 移除触发器
                    scheduler.deleteJob(trigger.getJobName(), trigger.getJobGroup());// 删除任务
                }
            } catch (SchedulerException e) {
                logger.error("移除任务失败...");
                e.printStackTrace();
            }
        }
    
        /**
         * 配置任务列表
         *
         * @param bo
         */
        private void configSchedul(TaskVo bo) {
            try {
                CronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP);
                if (trigger == null) {//说明schedule中不存在该定时任务
                    createTriggerTask(bo);
                } else {
                    updateTriggerTask(bo, trigger);
                }
            } catch (SchedulerException e) {
                logger.error("获取触发器trigger失败...");
                e.printStackTrace();
            }
        }
    
    
        /**
         * 更新任务列表
         *
         * @param bo
         */
        private void updateTriggerTask(TaskVo bo, CronTriggerBean trigger) {
    
            try {
                // 判断从DB中取得的任务时间和现在的quartz线程中的任务时间是否相等
                // 如果相等,则表示用户并没有重新设定数据库中的任务时间,这种情况不需要重新rescheduleJob
                if (trigger.getCronExpression() != null &&
                        !trigger.getCronExpression().equalsIgnoreCase(bo.getCronExpression())) {
                    logger.info("=真正更新方法:=" + bo.getTaskId() + "name" + bo.getTaskType());
                    trigger.setCronExpression(bo.getCronExpression());
                    scheduler.rescheduleJob(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP, trigger);
                    logger.info("更新任务时间失败...");
                }
            } catch (Exception e) {
                logger.error("更新任务时间失败...");
                e.printStackTrace();
            }
        }
    
    
    
        /**
         * 创建任务列表
         *
         * @param bo
         */
        private void createTriggerTask(TaskVo bo) {
    
            logger.info("=创建:=" + bo.getTaskId() + "name" + bo.getTaskType());
    
            try {
                Class clazz = QuartzJobFactory.class;//执行计划任务的类
                JobDetail jobDetail = new JobDetail(bo.getTaskId() + "", clazz);
                Map map = new HashMap();
                map.put("task", bo);
                jobDetail.setJobDataMap(new JobDataMap(map));
                jobDetail.setName(bo.getTaskId() + "name" + bo.getTaskType());
                scheduler.addJob(jobDetail, true); // 将Job添加到管理类
    
                // 新一个基于Spring的时间类
                CronTriggerBean c = new CronTriggerBean();
                c.setCronExpression(bo.getCronExpression());// 设置时间表达式
                c.setName(bo.getTaskId() + "name" + bo.getTaskType());// 设置名称
                c.setJobDetail(jobDetail);// 注入Job
                c.setJobName(bo.getTaskId() + "name" + bo.getTaskType());// 设置Job名称
                scheduler.scheduleJob(c);// 注入到管理类
                scheduler.rescheduleJob(bo.getTaskId() + "name" + bo.getTaskType(), Scheduler.DEFAULT_GROUP, c);// 刷新管理类
            } catch (Exception e) {
                logger.error("创建" + bo.getTaskId() + "name" + bo.getTaskType() + "任务失败...");
                e.printStackTrace();
            }
        }
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            QuartzManager.beanFactory = beanFactory;
    
        }
    
        public Scheduler getScheduler() {
            return scheduler;
        }
    
        public QuartzManager setScheduler(Scheduler scheduler) {
            this.scheduler = scheduler;
            return this;
        }
    
        public static BeanFactory getBeanFactory() {
            return beanFactory;
        }
    }
    QuartzManager
    QuartzJobFactory 定义了具体定时任务的执行管理
    所有的定时任务都会在时间点执行这个类的execute(),然后我们根据定时任务的TaskType来确定具体的任务,另外注意我这边是直接将我的参数作为taskId了,所有我传入的参数是taskId,如果可以根据自己的业务需要在TaskVO中补充自己的参数
    package com.imaster.admin.web.schemajob;
    
    import com.alibaba.fastjson.JSON;
    import com.imaster.admin.model.vo.TaskVo;
    import com.imaster.admin.web.biz.ExhibitorReserveBiz;
    import com.imaster.constant.ApplicationConfig;
    import com.imaster.shared.enums.TaskTypeEnum;
    import org.quartz.Job;
    import org.quartz.JobDataMap;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.slf4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /**
     * @Author wanghh
     * 2020/5/9 12:07
     */
    public class QuartzJobFactory implements Job {
        private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ApplicationConfig.SERVER_NAME);
    
        @Autowired
        private ExhibitorReserveBiz exhibitorReserveBiz;
    
    
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            TaskVo taskVo = (TaskVo) jobDataMap.get("task");
            logger.info("定时任务开始执行。。。。。。。。。。。" + JSON.toJSONString(taskVo));
            if (TaskTypeEnum.EXHIBITOR_RESERVE.getCode().equals(taskVo.getTaskType())) {
                logger.info("zhangshangbaoming job=======" + taskVo.getTaskId());
                 exhibitorReserveBiz.sendAcceptTimeEmail(taskVo.getTaskId());
                //msgSendSchemaService.sendSchemaMsg(taskVo.getTaskId());
            }
    
        }
    }
    QuartzJobFactory
    JobAdapter 这个类其实我没有明白,只能邯郸学步,请见谅,看别人的注释吧。
    package com.imaster.admin.web.schemajob;
    
    import org.quartz.spi.TriggerFiredBundle;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    import org.springframework.scheduling.quartz.AdaptableJobFactory;
    
    /**
     * @Author wanghh
     * 2020/5/11 10:17
     */
    public class JobAdapter extends AdaptableJobFactory {
        @Autowired
        private AutowireCapableBeanFactory capableBeanFactory;
    
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            //调用父类的方法
            Object jobInstance = super.createJobInstance(bundle);
            //进行注入
            capableBeanFactory.autowireBean(jobInstance);
            return jobInstance;
        }
    }
    TaskVo 实体类
    package com.imaster.admin.model.vo;
    
    import lombok.Data;
    
    /**
     * @Author wanghh
     * 2020/5/9 11:50
     */
    @Data
    public class TaskVo {
        public String taskId;
    
        public String taskType;
    
        public String cronExpression;
    
        public String state;
    }
    TaskVo

    以上就是我本次需求的处理,说实话,我只是在照葫芦画瓢,以后的项目之余我会逐步的去补充。

    另外我和原创都是单台的服务器,所以没有考虑到集群的情况下。

    原创地址:https://www.cnblogs.com/likun10579/p/10896831.html

    谢谢挖坑大王的分享。@挖坑大王

  • 相关阅读:
    HDU 4539郑厂长系列故事――排兵布阵(状压DP)
    HDU 2196Computer(树形DP)
    HDU 4284Travel(状压DP)
    HDU 1520Anniversary party(树型DP)
    HDU 3920Clear All of Them I(状压DP)
    HDU 3853LOOPS(简单概率DP)
    UVA 11983 Weird Advertisement(线段树求矩形并的面积)
    POJ 2886Who Gets the Most Candies?(线段树)
    POJ 2828Buy Tickets
    HDU 1394Minimum Inversion Number(线段树)
  • 原文地址:https://www.cnblogs.com/qzzy/p/12926439.html
Copyright © 2011-2022 走看看