Quartz使用監聽器插入定時任務執行日誌
阿新 • • 發佈: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;
}
}