1.基本用法
定时任务很简单,指定多长时间执行一个任务。
(1) 在main类上添加注解@EnableScheduling
(2) 在@Component组件类中添加@Scheduled注解
1 2 3 4 5 6 7 8 9 10 11
| @Component public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 5000) public void reportCurrentTime() { System.out.println("现在时间:" + dateFormat.format(new Date())); }
}
|
SpringBoot Quartz 无法使用@Autowired注入
今天给实习生解决一个问题,就是使用使用Quartz进行定时任务时,总是无法使用@Autowired注入service,包空指针错误(吐槽下自己的技术,确实没有练到家啊,实习生来问我问题,我确实连解决的思路都没有,惭愧啊,惭愧)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @DisallowConcurrentExecution public class LogJob implements Job {
private Logger log = LoggerFactory.getLogger(LogJob.class); @Autowired private DDlogInfoService dDlogInfoService;
@Override public void execute(JobExecutionContext jobExecutionContext) { try { for (int i = 0; i < 100; i++) { log.error("DDlogInfoService:"+dDlogInfoService); log.error("DDlogInfoService: two",dDlogInfoService); dDlogInfoService.logTomyServer(userlogs); } }catch (Exception e){ e.printStackTrace(); } }
|
经过查阅资料,确实有很多的人遇到了这个问题。在使用Spring自带的定时任务注解@Scheduled时,同样在任务执行类中使用了Service,好像并没有出现这个问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
@Component public class ClickhouseImport { private final static Logger logger= LoggerFactory.getLogger(ClickhouseImport.class); @Resource private RealTimeMapper realTimeMapper;
@Autowired private ClickhouseDbUtil clickhouseDbUtil;
public void insertClickhouse(String startdate,String enddate){ try { List<RealTime> result=realTimeMapper.selectBetweenDate(startdate,enddate); }catch (Exception e){ logger.error("getBetween",e); } } }
@Component public class ScheduledTasks { private final static Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);
@Autowired private ClickhouseImport clickhouseImport;
@Scheduled(fixedDelay = 50*1000) public void timingImportData() { try { clickhouseImport.insertClickhouse("startdate","enddate");
}catch (Exception e){ logger.error("",e); }
} }
|
(3) 我依次实现了QuartzSchedule和AdaptableJobFactory,依然还是不行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class MyJobFactory extends AdaptableJobFactory{ @Autowired private AutowireCapableBeanFactory capableBeanFactory;
@Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object jobInstance = super.createJobInstance(bundle); capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Configuration @EnableScheduling public class QuartzSchedule {
@Autowired private MyJobFactory myJobFactory;
@Bean public SchedulerFactoryBean schedulerFactoryBean() throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); System.out.println("dsf"); factory.setOverwriteExistingJobs(true);
factory.setStartupDelay(20);
factory.setJobFactory(myJobFactory);
return factory; } }
|
我又回到了最初的代码,在CommandLineRunner实现类中,直接调用注入DDlogInfoService,是可以的,但是在任务类LogJob中,却出现了空指针的异常。会不会是CommandLineRunner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Component public class MyCommandLineRunner implements CommandLineRunner { private final Logger log = LogManager.getLogger(MyCommandLineRunner.class); @Autowired private DDlogInfoService dDlogInfoService;
@Override public void run(String... args) { try{ log.error("s",dDlogInfoService); SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); JobDetail build = JobBuilder.newJob(LogJob.class).withIdentity("job1", "group1").build(); Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1") .withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? ")).build(); scheduler.scheduleJob(build,trigger); scheduler.start();
}catch (Exception e){ e.printStackTrace(); }
}
}
|
(4) 经过多方探索和尝试,最终找到了正确的使用方法。
1.pom.xml中引入插件
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
|
2.编写任务类
编写任务类,定时执行代码,扩展QuartzJobBean,调用@Autowired注入服务层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @DisallowConcurrentExecution @Component public class LogJob extends QuartzJobBean {
private Logger log = LoggerFactory.getLogger(LogJob.class);
@Autowired private DDlogInfoService dDlogInfoService;
@Override public void executeInternal(JobExecutionContext jobExecutionContext) { try { log.error("",dDlogInfoService); }catch (Exception e){ e.printStackTrace(); } }
}
|
3.编写配置类
编写配置类,注入任务Bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Configuration @EnableScheduling public class QuartzSchedule {
@Bean public JobDetail quartzTaskServiceJobDetail() { return JobBuilder.newJob(LogJob.class).withIdentity("quartzTaskService").storeDurably().build(); }
@Bean public Trigger quartzTaskServiceTrigger() { CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("* * * * * ?"); return TriggerBuilder.newTrigger().forJob(quartzTaskServiceJobDetail()) .withIdentity("quartzTaskService") .withSchedule(scheduleBuilder) .build(); } }
|
这样就可以正常的通过@Autowired注入服务层的内容了。
至于为何通过Job接口并且结合AdaptableJobFactory无法实现的问题,还有待进一步探讨
4.动态配置
动态配置定时任务,就是说以前的定时任务都是代码中写死的,如何实现通过代码的方式动态修改定时任务呢?本来要一天执行一次的,现在一个小时执行一次。