发布时间:2022-12-04 文章分类:编程知识 投稿人:王小丽 字号: 默认 | | 超大 打印

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;
	}
}