zoukankan      html  css  js  c++  java
  • SSM后台调度Quartz定时任务动态管理

    之前线上部署几个定时任务,有时候遇到定时任务修改时间的时候都需要更新代码重启服务器,

    有时候需要某个月暂停定时任务,也需要重新部署,所以我乘着空闲时间,给公司做了后台

    调度管理,很简单的功能,借鉴了git上相关开源项目,推荐star:https://github.com/elunez/eladmin,

    https://gitee.com/renrenio/renren-security
    因为公司框架比较老,用的ssm,所以仅供该框架参考,springboot直接参考上面的项目。
    效果图:(easyui--效果就这样了-- )

     

    好了,上代码:pom.xml----也可以直接拉到最底下上github下载下来运行一下就哦了。

     <!-- 定时器 -->
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>2.2.1</version>
            </dependency>

    job的实现类ExecutionJoblei,用于执行任务
    package com.zhx.quartz.utils;
    
    import com.zhx.quartz.domain.QuartzJob;
    import com.zhx.quartz.domain.QuartzLog;
    import com.zhx.quartz.service.QuartzJobService;
    import org.quartz.JobExecutionContext;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    
    import java.util.concurrent.Future;
    import java.util.concurrent.ThreadPoolExecutor;
    
    /**
     * 参考人人开源,https://gitee.com/renrenio/renren-security
     *
     * @author /
     * @date 2019-01-07
     */
    @Async
    public class ExecutionJob extends QuartzJobBean {
        @Autowired
        private QuartzJobService quartzJobService;
        private Logger logger = LoggerFactory.getLogger(this.getClass());
        /**
         * 该处仅供参考
         */
        private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
        
        @Override
        @SuppressWarnings("unchecked")
        protected void executeInternal(JobExecutionContext context) {
            QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
            // 获取spring bean
            QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class);
            QuartzLog log = new QuartzLog();
            log.setJobName(quartzJob.getJobName());
            log.setBeanName(quartzJob.getBeanName());
            log.setMethodName(quartzJob.getMethodName());
            log.setParams(quartzJob.getParams());
            long startTime = System.currentTimeMillis();
            log.setCronExpression(quartzJob.getCronExpression());
            try {
                // 执行任务
                logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
                QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
                        quartzJob.getParams());
                Future<?> future = EXECUTOR.submit(task);
                future.get();
                long times = System.currentTimeMillis() - startTime;
                log.setTime(times);
                // 任务状态
                log.setIsSuccess(true);
                logger.info("任务执行完毕,任务名称:{} 总共耗时:{} 毫秒", quartzJob.getJobName(), times);
            } catch (Exception e) {
                logger.error("任务执行失败,任务名称:{}" + quartzJob.getJobName(), e);
                long times = System.currentTimeMillis() - startTime;
                log.setTime(times);
                // 任务状态 0:成功 1:失败
                log.setIsSuccess(false);
                log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
                quartzJob.setIsPause(false);
                //更新状态
                quartzJobService.updateIsPause(quartzJob.getId());
            } finally {
                logger.info("------------记录 调度 日志--------");
                quartzJobService.inserLog(log);
            }
        }
    }
    QuartzManage类用于管理任务的执行,暂停,添加,删除
    package com.zhx.quartz.utils;
    
    import com.zhx.quartz.domain.QuartzJob;
    import org.quartz.*;
    import org.quartz.impl.triggers.CronTriggerImpl;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.Date;
    
    import static org.quartz.TriggerBuilder.newTrigger;
    
    /**
     * @author Zheng Jie
     * @date 2019-01-07
     */
    @Component
    public class QuartzManage {
        private static final Logger log = LoggerFactory.getLogger(QuartzManage.class);
        private static final String JOB_NAME = "TASK_";
        @Resource(name = "scheduler")
        private Scheduler scheduler;
        
        public void addJob(QuartzJob quartzJob) {
            try {
                // 构建job信息
                JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
                        withIdentity(JOB_NAME + quartzJob.getId()).build();
                //通过触发器名和cron 表达式创建 Trigger
                Trigger cronTrigger = newTrigger()
                        .withIdentity(JOB_NAME + quartzJob.getId())
                        .startNow()
                        .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
                        .build();
                cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
                //重置启动时间
                ((CronTriggerImpl) cronTrigger).setStartTime(new Date());
                //执行定时任务
                scheduler.scheduleJob(jobDetail, cronTrigger);
                // 如果任务是暂停的,就停止
                if (quartzJob.getIsPause()) {
                    pauseJob(quartzJob);
                }
            } catch (Exception e) {
                log.error("创建定时任务失败", e);
            }
        }
        
        /**
         * 更新job cron表达式
         *
         * @param quartzJob /
         */
        public void updateJobCron(QuartzJob quartzJob) {
            try {
                TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                // 如果不存在则创建一个定时任务
                if (trigger == null) {
                    addJob(quartzJob);
                    trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                }
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                //重置启动时间
                ((CronTriggerImpl) trigger).setStartTime(new Date());
                trigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
                scheduler.rescheduleJob(triggerKey, trigger);
                // 暂停任务
                if (quartzJob.getIsPause()) {
                    pauseJob(quartzJob);
                }
            } catch (Exception e) {
                log.error("更新定时任务失败", e);
            }
        }
        
        /**
         * 删除一个job
         *
         * @param quartzJob /
         */
        public void deleteJob(QuartzJob quartzJob) {
            try {
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.pauseJob(jobKey);
                scheduler.deleteJob(jobKey);
            } catch (Exception e) {
                log.error("删除定时任务失败", e);
            }
        }
        
        /**
         * 恢复一个job
         *
         * @param quartzJob /
         */
        public void resumeJob(QuartzJob quartzJob) {
            try {
                TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                // 如果不存在则创建一个定时任务
                if (trigger == null) {
                    addJob(quartzJob);
                }
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.resumeJob(jobKey);
            } catch (Exception e) {
                log.error("恢复定时任务失败", e);
            }
        }
        
        /**
         * 立即执行job
         *
         * @param quartzJob /
         */
        public void runJobNow(QuartzJob quartzJob) {
            try {
                TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                // 如果不存在则创建一个定时任务
                if (trigger == null) {
                    addJob(quartzJob);
                }
                JobDataMap dataMap = new JobDataMap();
                dataMap.put(QuartzJob.JOB_KEY, quartzJob);
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.triggerJob(jobKey, dataMap);
            } catch (Exception e) {
                log.error("定时任务执行失败", e);
            }
        }
        
        /**
         * 暂停一个job
         *
         * @param quartzJob /
         */
        public void pauseJob(QuartzJob quartzJob) {
            try {
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.pauseJob(jobKey);
            } catch (Exception e) {
                log.error("定时任务暂停失败", e);
            }
        }
    }
    package com.zhx.quartz.utils;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.util.ReflectionUtils;
    
    import java.lang.reflect.Method;
    import java.util.concurrent.Callable;
    
    /**
     * 执行定时任务
     *
     * @author /
     */
    public class QuartzRunnable implements Callable {
        private static final Logger log = LoggerFactory.getLogger(QuartzRunnable.class);
        private Object target;
        private Method method;
        private String params;
        
        QuartzRunnable(String beanName, String methodName, String params)
                throws NoSuchMethodException, SecurityException {
            this.target = SpringContextHolder.getBean(beanName);
            this.params = params;
            if (StringUtils.isNotBlank(params)) {
                this.method = target.getClass().getDeclaredMethod(methodName, String.class);
            } else {
                this.method = target.getClass().getDeclaredMethod(methodName);
            }
        }
        
        @Override
        public Object call() throws Exception {
            ReflectionUtils.makeAccessible(method);
            if (StringUtils.isNotBlank(params)) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
            return null;
        }
    }
    InitQuartzJob类用于初始化执行库里存在且未暂停的job
    package com.zhx.quartz.utils;
    
    import com.zhx.quartz.domain.QuartzJob;
    import com.zhx.quartz.mapper.QuartzJobMapper;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author: SimonHu
     * @Date: 2020/5/14 8:49
     * @Description:
     */
    @Component
    public class InitQuartzJob {
        private static final Logger logger = LoggerFactory.getLogger(InitQuartzJob.class);
        @Autowired
        private QuartzManage quartzManage;
        @Autowired
        private QuartzJobMapper quartzJobMapper;
        
        /**
         * @return void
         * @Description:初始化定时任务 @PostConstruct注解启动时执行该方法
         * @Author:SimonHu
         * @Date: 2020/5/14 8:59
         */
        @PostConstruct
        public void init() {
            // 这里从数据库中获取任务信息数据
            Map map = new HashMap(16);
            //获取未暂停的任务
            map.put("isPause","0");
            List<QuartzJob> quartzJobs = quartzJobMapper.queryJob(map);
            for (QuartzJob job : quartzJobs) {
                logger.info("-----init job----" + job.getJobName());
                quartzManage.addJob(job);
            }
        }
    }
    SpringContextHolder用于静态类中获取spring中管理的bean
    package com.zhx.quartz.utils;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    /**
     * @Author: SimonHu
     * @Date: 2020/5/13 16:07
     * @Description:
     */
    @Component
    public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
        private static final Logger log = LoggerFactory.getLogger(SpringContextHolder.class);
        private static ApplicationContext applicationContext = null;
        
        /**
         * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
         */
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String name) {
            assertContextInjected();
            return (T) applicationContext.getBean(name);
        }
        
        /**
         * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
         */
        public static <T> T getBean(Class<T> requiredType) {
            assertContextInjected();
            return applicationContext.getBean(requiredType);
        }
        
        /**
         * 检查ApplicationContext不为空.
         */
        private static void assertContextInjected() {
            if (applicationContext == null) {
                throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
                        ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
            }
        }
        
        /**
         * 清除SpringContextHolder中的ApplicationContext为Null.
         */
        private static void clearHolder() {
            log.debug("清除SpringContextHolder中的ApplicationContext:"
                    + applicationContext);
            applicationContext = null;
        }
        
        @Override
        public void destroy() {
            SpringContextHolder.clearHolder();
        }
        
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (SpringContextHolder.applicationContext != null) {
                log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
            }
            SpringContextHolder.applicationContext = applicationContext;
        }
    }
    TheadFactoryName自定义线程名
    package com.zhx.quartz.utils;
    
    import org.springframework.stereotype.Component;
    
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * 自定义线程名称
     *
     * @author Zheng Jie
     * @date 2019年10月31日17:49:55
     */
    @Component
    public class TheadFactoryName implements ThreadFactory {
        private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        
        public TheadFactoryName() {
            this("el-pool");
        }
        
        private TheadFactoryName(String name) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            //此时namePrefix就是 name + 第几个用这个工厂创建线程池的
            this.namePrefix = name +
                    POOL_NUMBER.getAndIncrement();
        }
        
        @Override
        public Thread newThread(Runnable r) {
            //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
            Thread t = new Thread(group, r,
                    namePrefix + "-thread-" + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon()) {
                t.setDaemon(false);
            }
            if (t.getPriority() != Thread.NORM_PRIORITY) {
                t.setPriority(Thread.NORM_PRIORITY);
            }
            return t;
        }
    }
    package com.zhx.quartz.utils;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 用于获取自定义线程池
     *
     * @author Zheng Jie
     * @date 2019年10月31日18:16:47
     */
    public class ThreadPoolExecutorUtil {
        public static ThreadPoolExecutor getPoll() {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    20,
                    100,
                    300,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(50),
                    new TheadFactoryName()
            );
            return threadPoolExecutor;
        }
    }
    package com.zhx.quartz.utils;
    
    import java.io.PrintWriter;
    import java.io.StringWriter;
    
    /**
     * 异常工具 2019-01-06
     *
     * @author Zheng Jie
     */
    public class ThrowableUtil {
        /**
         * 获取堆栈信息--分行显示
         */
        public static String getStackTrace(Throwable throwable) {
            StringWriter sw = new StringWriter();
            try (PrintWriter pw = new PrintWriter(sw)) {
                throwable.printStackTrace(pw);
                return sw.toString();
            }
        }
        /**
          * @Description:获取堆栈信息--单行显示
          * @Author:SimonHu
          * @Date: 2020/5/14 15:59
          * @param throwable
          * @return java.lang.String
          */
        public static String getStackTrace2(Throwable throwable) {
            StringWriter sw = new StringWriter();
            StackTraceElement[] error = throwable.getStackTrace();
            for (StackTraceElement stackTraceElement : error) {
                sw.append(stackTraceElement.toString());
            }
            return sw.toString();
        }
    }
    package com.zhx.quartz.config;
    
    import org.quartz.Scheduler;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    
    /**
     * 定时任务配置
     *
     * @author /
     * @date 2019-01-07
     */
    @Configuration
    public class QuartzConfig {
        /**
         * 注入scheduler到spring
         *
         * @param quartzJobFactory /
         * @return Scheduler
         * @throws /
         */
        @Bean(name = "scheduler")
        public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
            SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
            factoryBean.setJobFactory(quartzJobFactory);
            factoryBean.afterPropertiesSet();
            Scheduler scheduler = factoryBean.getScheduler();
            scheduler.start();
            return scheduler;
        }
    }
    package com.zhx.quartz.config;
    /**
     * @Author: SimonHu
     * @Date: 2020/5/13 16:47
     * @Description:
     */
    
    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;
    
    /**
     * 解决Job中注入Spring Bean为null的问题
     */
    public class QuartzJobFactory extends AdaptableJobFactory {
        @Autowired
        private AutowireCapableBeanFactory capableBeanFactory;
        
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            //调用父类的方法
            Object jobInstance = super.createJobInstance(bundle);
            capableBeanFactory.autowireBean(jobInstance);
            return jobInstance;
        }
    }

    最后就是配置文件applicationContext.xml

     <!--初始化 SpringContextHolder-->
        <bean id="SpringContextHolder" class="com.zhx.quartz.utils.SpringContextHolder"/>
    <!-- Dispatcher-Servlet.xml配置 -->
    <!--初始化Scheduler-->
    <bean id="quartzJobFactory" class="com.zhx.quartz.config.QuartzJobFactory"></bean> <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobFactory" ref="quartzJobFactory"></property> </bean>

    配置文件放到bean最后

    完整代码我就放在github上了,可以的话给个star= =(csdn上那些坑分的→_→)
    https://github.com/SimonHu1993/QuartzDemo
  • 相关阅读:
    Two strings CodeForces
    Dasha and Photos CodeForces
    Largest Beautiful Number CodeForces
    Timetable CodeForces
    Financiers Game CodeForces
    AC日记——整理药名 openjudge 1.7 15
    AC日记——大小写字母互换 openjudge 1.7 14
    AC日记——将字符串中的小写字母换成大写字母 openjudge 1.7 13
    AC日记——加密的病历单 openjudge 1.7 12
    AC日记——潜伏着 openjudge 1.7 11
  • 原文地址:https://www.cnblogs.com/SimonHu1993/p/12891479.html
Copyright © 2011-2022 走看看