SpringBoot + Quartz定时任务踩过的坑

  1. SchedulerConfig.java定时任务Job中service注入NullPointerException
    [原因]:trigger没有注册,很诡异?没设置时间也运行?
  2. 定时任务Job中service注入NullPointerException
    [原因]:创建的Service是Quartz管理的,不是Spring,无法注入
    Job 是通过反射出来的实例,不受spring的管理
@Autowired
private ApplicationContext applicationContext;

@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactoryBean(Trigger trigger) {
    SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
    // 用于quartz集群,QuartzScheduler启动时更新已存在的job
    factoryBean.setOverwriteExistingJobs(true);
    // 延时启动,应用启动1秒后
    factoryBean.setStartupDelay(1);
    // 注册触发器
    factoryBean.setTriggers(trigger);
    // Spring依赖注入为null
    SpringQuartzJobFactory jobFactory = new SpringQuartzJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    factoryBean.setJobFactory(jobFactory);
    return factoryBean;
}
  • 多个任务怎么办?

解决@Autowired空指针Null问题,即依赖注入的属性为null

  • 创建SpringQuartzJobFactory.java
  • 期间用到 applicationContext
@Component("springQuartzJobFactory")
public class SpringQuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    @Autowired
    private AutowireCapableBeanFactory beanFactory;

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

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

/*
主要思路是通过新建一个AutowiringSpringBeanJobFactory 实现 quartz 的SpringBeanJobFactory(job生产工厂类)
通过实现ApplicationContextAware接口 set ApplicationContextAware(上下文)到该新建job工厂类。
然后通过super.createJobInstance(bundle) 创建 job, beanFactory来autowired job实例
*/


参考资料

  • spring boot quartz scheduler example code using maven
  • Quartz (2.1.6) java config with spring (3.2.1). Using a SpringBeanJobFactory to automatically autowire quartz classes.
  • 《SpringBoot整合Quartz实现定时任务》
  • 定时任务quartz的job中注入spring bean时null的问题 / zhongruitech.com
  • springboot整合quartz配置多任务 - 未完成的空间 - CSDN博客
  • quartz里job不执行的解决方案(并发量太低原因) - 一名普通码农的菜地 - CSDN博客


SpringBoot + Quartz

@Bean(name = "psBnAbsNoticeJobDetail")
public JobDetailFactoryBean psBnAbsNoticeJobDetail() 
{
    JobDetailFactoryBean psBnAbsNoticeFactory = new JobDetailFactoryBean();
    psBnAbsNoticeFactory.setJobClass(PsBnAbsNoticeTask.class);
    psBnAbsNoticeFactory.setName("PsBnAbsNoticeTask");
    psBnAbsNoticeFactory.setDescription("push abnormal attendance notice");
    psBnAbsNoticeFactory.setDurability(true);
    return psBnAbsNoticeFactory;
}

/**
 * 每天早上5点推送异常打卡记录(秒 分 时 日 月 星期几)
 * jobDtail和trigger是一一对应
 */
@Bean(name = "psBnAbsNoticeJobTrigger")
public CronTriggerFactoryBean psBnAbsNoticeJobTrigger(@Qualifier("psBnAbsNoticeJobDetail") JobDetail job) 
{
    CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
    trigger.setJobDetail(job);
    trigger.setCronExpression("0 */1 * * * ?");
    return trigger;
}
  • 定时任务
/*
 * 异常打卡记录推送
 */
@PersistJobDataAfterExecution
public class PsBnAbsNoticeTask extends QuartzJobBean {

    private static final Logger logger = LoggerFactory.getLogger(PsBnAbsNoticeTask.class);

    @Autowired
    PsBnAbsDetailedService psbnAbsDetailedService;

    @Autowired
    HrConfig hrConfig;

    @Override
    protected void executeInternal(JobExecutionContext context) {
        logger.info("开始定时任务 --- PsBnAbsNoticeTask --- " + new Date());

        // 凌晨推送,获取昨天日期
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,-1);
        Date time = calendar.getTime();
        String yesterday = new SimpleDateFormat("yyyy-MM-dd").format(time);
        List entityList = psbnAbsDetailedService.getPsBnAbsNoticeDetailed(yesterday);

        for (PsBnAbsDetailedEntity entity: entityList) {
            if (entity.getEmpLid()== null) {
                continue;
            }
            pushPsBnAbsNotice(entity);
        }

        logger.info("结束定时任务 --- PsBnAbsNoticeTask --- " + new Date());
    }


    private void pushPsBnAbsNotice(PsBnAbsDetailedEntity entity) {

        Map param = new HashMap<>();
        param.put("from", "考勤异常");
        param.put("to", entity.getEmpLid());
        param.put("type", 80);
        param.put("source", "bpm");

        Map content = new HashMap<>();

        String detail = "";
        if (entity.getBnAmAbstype().equals("2")) {
            detail += "早班卡:未打卡\n";
        }
        if (entity.getBnNmAbstype().equals("2")) {
            detail += "中班卡:未打卡\n";
        }
        if (entity.getBnPmAbstype().equals("2")) {
            detail += "下班卡:未打卡\n";
        }

        String qhAbsDate = DateUtil.toStandardDateStr(entity.getQhAbsDate());

        content.put("title", "考勤异常提醒("+qhAbsDate+")");
        String substance = "您的考勤存在异常,请及时处理!\n打卡号:"+entity.getEmpLid()+"\n"+detail+"打卡日期:"+qhAbsDate;
        content.put("substance", substance);
        param.put("content", content);

        // 推送公众号消息
        String reqStr = JSONObject.toJSONString(param);
        String url = hrConfig.getMoaApiSendMsg();
        doPostJson(url, reqStr);
    }
}

你可能感兴趣的:(SpringBoot + Quartz定时任务踩过的坑)