河曲智叟 发表于 2022-12-4 16:46:02

Quartz使用监听器插入定时任务执行日志

Quartz使用监听器插入定时任务执行日志

使用springboot,将监听器交给spring容器管理,并像其中注入日志服务类,环境准备工作实现任务调度需要导入两个quartz的maven依赖
<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
</dependency>
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
            <version>2.7.3</version>
            <exclusions>
                <exclusion>
                  <artifactId>slf4j-api</artifactId>
                  <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
</dependency>      
      创建一个监听器类,实现JobListener接口。
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Component;

import java.util.Date;

@Slf4j
@Component
public class QuartzJobListener implements JobListener {

        private final QuartzRunningLogService logService;

        private static ThreadLocal<QuartzRunningLog> logThreadLocal = ThreadLocal.withInitial(QuartzRunningLog::new);

        public QuartzJobListener(QuartzRunningLogService logService) {
                this.logService = logService;
        }

        @Override
        public String getName() {
                return "jobLogListener";
        }
        /**
        *
        *Scheduler在JobDetail将要被执行时调用这个方法
        **/
        @Override
        public void jobToBeExecuted(JobExecutionContext context) {
                QuartzRunningLog quartzRunningLog = QuartzRunningLog
                                .builder()
                                .startTime(new Date())
                                .build();
                logThreadLocal.set(quartzRunningLog);
        }
        /**
        *
        *Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法
        **/
        @Override
        public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {

        }
        /**
        *
        *Scheduler在JobDetail被执行之后调用这个方法
        **/
        @Override
        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
                JobKey jobKey = context.getJobDetail().getKey();
                TriggerKey triggerKey = context.getTrigger().getKey();
                Date fireTime = context.getFireTime();
                Class jobClass = context.getJobDetail().getJobClass();
                JobDataMap dataMap = context.getMergedJobDataMap();
                String taskName = (String) dataMap.get(CommonConst.TASK_NAME);
                String cronExpression = (String) dataMap.get(CommonConst.CRON_EXPRESSION);
                String jobName = (String) dataMap.get(CommonConst.JOB_NAME);
                log.info("JobClass:{},Job:{},Trigger:{},FireTime:{}", jobClass, jobKey, triggerKey, DateUtil.formatDateTime(fireTime));
                if (null != jobException) {
                        //保存错误记录
                        QuartzRunningLog runningLog = logThreadLocal.get();
                        runningLog.setJobName(jobName);
                        runningLog.setCronExpression(cronExpression);
                        runningLog.setEndTime(new Date());
                        runningLog.setStatus("FAIL");
                        runningLog.setTaskId(Long.valueOf(jobKey.getName()));
                        runningLog.setTaskName(taskName);
                        runningLog.setFailReason(jobException.getMessage());
                        logService.save(runningLog);
                        logThreadLocal.remove();
                        return;
                }
                //保存执行记录
                QuartzRunningLog runningLog = logThreadLocal.get();
                runningLog.setJobName(jobName);
                runningLog.setCronExpression(cronExpression);
                runningLog.setEndTime(new Date());
                runningLog.setStatus("SUCESS");
                runningLog.setTaskId(Long.valueOf(jobKey.getName()));
                runningLog.setTaskName(taskName);
                logService.save(runningLog);
                logThreadLocal.remove();
        }
}quartzconfig配置类
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {

        @Autowired
        private ApplicationContext applicationContext;

        /**
       * Create the job factory bean
       *
       * @return Job factory bean
       */
        @Bean
        public JobFactory jobFactory() {
                ApplicationContextHolder jobFactory = new ApplicationContextHolder();
                jobFactory.setApplicationContext(applicationContext);
                return jobFactory;
        }

        /**
       * Create the Scheduler Factory bean
       *
       * @return scheduler factory object
       */
        @Bean
        public SchedulerFactoryBean schedulerFactory() {
                SchedulerFactoryBean factory = new SchedulerFactoryBean();
                factory.setAutoStartup(true);
                factory.setSchedulerName("Scheduler");
                factory.setOverwriteExistingJobs(true);
                factory.setJobFactory(jobFactory());
                return factory;
        }

        /**
       * Create the Scheduler bean
       *
       * @param logService
       * @return Scheduler
       * @throws SchedulerException
       */
        @Bean
        public Scheduler scheduler(@Autowired QuartzRunningLogService logService) throws SchedulerException {
      //在这里注入日志服务类且激活监听器,如果直接在监听器类里面使用@Autowired会出现注入为null
                schedulerFactory().getScheduler().getListenerManager().addJobListener(new QuartzJobListener(logService));
                return schedulerFactory().getScheduler();
        }

}容器工具类
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextHolder extends SpringBeanJobFactory
                implements ApplicationContextAware {
        private static ApplicationContext context;
        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(final ApplicationContext context) {
                beanFactory = context.getAutowireCapableBeanFactory();
                ApplicationContextHolder.context = context;
        }

        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
                final Object job = super.createJobInstance(bundle);
                beanFactory.autowireBean(job);
                return job;
        }

        public static ApplicationContext getContext() {
                return context;
        }
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Quartz使用监听器插入定时任务执行日志