定时任务方案 三种
1,spring Scheduled
2,Quartz
3,Timer定时器
一种Scheduled
spring-boot-starter-web 里面的
最简单demo
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
/**
*
* 最简单的方式
*
*/
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class SaticScheduleTask {
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() {
System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
}
}
这样是写死的。。
对于数据库里面操作使用了cron 属性来自定义操作了
cron 操作和处理
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
@Configuration // 1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
/**
* 执行定时任务.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期
// String cron = cronMapper.getCron();
/*我这里直接写死了 测试用的*/
String cron = "0/5 * * * * ?";
//2.2 合法性校验.
if (StringUtils.isEmpty(cron)) {
// Omitted Code ..
}
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
这样就是简单的使用了。有时候从数据库里面可以多数据操作,可能会有循环进行了
不能不用runnable接口 来实现它,总体的核心方法就是上面
案例一种
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
@Autowired
private ApplicationContext context;
@Autowired
private SpringScheduledCronRepository cronRepository;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
for (SpringScheduledCron springScheduledCron : cronRepository.findAll()) {
Class> clazz;
Object task;
try {
clazz = Class.forName(springScheduledCron.getCronKey());
task = context.getBean(clazz);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("spring_scheduled_cron表数据" + springScheduledCron.getCronKey() + "有误", e);
} catch (BeansException e) {
throw new IllegalArgumentException(springScheduledCron.getCronKey() + "未纳入到spring管理", e);
}
Assert.isAssignable(ScheduledOfTask.class, task.getClass(), "定时任务类必须实现ScheduledOfTask接口");
// 可以通过改变数据库数据进而实现动态改变执行周期
taskRegistrar.addTriggerTask(((Runnable) task),
triggerContext -> {
String cronExpression = cronRepository.findByCronKey(springScheduledCron.getCronKey()).getCronExpression();
return new CronTrigger(cronExpression).nextExecutionTime(triggerContext);
}
);
}
}
@Bean
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
以为这样简单的就开始了结束了。不是。
下面是开始多线程的使用
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
//@Component注解用于对那些比较中立的类进行注释;
//相对与在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释
@Component
@EnableScheduling // 1.开启定时任务
@EnableAsync // 2.开启多线程
public class MultithreadScheduleTask {
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
}
}
第二种Quartz
为什么要使用Quartz
多任务情况下,quartz更容易管理,可以实现动态配置
简单demo 情况
引入
org.springframework.boot
spring-boot-starter-quartz
1,QuartzJobBean 的实现
public class SampleJob extends QuartzJobBean {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Quartz ----> Hello, " + this.name + "\n time=" + LocalDateTime.now());
}
}
开始配置和使用
@Configuration
public class SampleScheduler {
@Bean
public JobDetail sampleJobDetail() {
// 链式编程,可以携带多个参数,在Job类中声明属性 + setter方法
return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob")
.usingJobData("name", "World").storeDurably().build();
}
@Bean
public Trigger sampleJobTrigger() {
// 每隔两秒执行一次
SimpleScheduleBuilder scheduleBuilder =
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
return TriggerBuilder.newTrigger().forJob(sampleJobDetail()).withIdentity("sampleTrigger")
.withSchedule(scheduleBuilder).build();
}
}
结束
2,cron 的使用
配置多个job
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
@Component
public class CronSchedulerJob {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
private void scheduleJob1(Scheduler scheduler) throws SchedulerException {
JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class) .withIdentity("job1", "group1").build();
// 6的倍数秒执行 也就是 6 12 18 24 30 36 42 ....
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/6 * * * * ?");
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.usingJobData("name","王智1").withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
private void scheduleJob2(Scheduler scheduler) throws SchedulerException{
JobDetail jobDetail = JobBuilder.newJob(ScheduledJob2.class) .withIdentity("job2", "group2").build();
// 12秒的倍数执行 12 24 36 48 60
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/12 * * * * ?");
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group2")
.usingJobData("name","王智2").withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
/**
* @Author Smith
* @Description 同时启动两个定时任务
* @Date 16:31 2019/1/24
* @Param
* @return void
**/
public void scheduleJobs() throws SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduleJob1(scheduler);
scheduleJob2(scheduler);
}
}
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ScheduledJob implements Job {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
System.out.println("CRON ----> schedule job1 is running ... + " + name + " ----> " + dateFormat.format(new Date()));
}
}
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ScheduledJob2 implements Job {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
System.out.println("CRON ----> schedule job2 is running ... + " + name + " ----> " + dateFormat.format(new Date()));
}
}
多个job 开始启动。。。
一种是
使用CommandLineRunner
@Component
public class MyStartupRunner implements CommandLineRunner {
@Autowired
public CronSchedulerJob scheduleJobs;
@Override
public void run(String... args) throws Exception {
scheduleJobs.scheduleJobs();
System.out.println(">>>>>>>>>>>>>>>定时任务开始执行<<<<<<<<<<<<<");
}
}
两一种
@Configuration
@EnableScheduling
@Component
public class SchedulerListener {
@Autowired
public CronSchedulerJob scheduleJobs;
private String cron = "0/5 * * * * ?";
// @Scheduled(cron="0 47 16 24 1 ?")
@Scheduled(cron = "0/5 * * * * ?")
public void schedule() throws SchedulerException {
scheduleJobs.scheduleJobs();
System.out.println(">>>>>>>>>>>>>>>定时任务开始执行<<<<<<<<<<<<<");
}
}
这个已发生已经启动了,在启动一次会报错。
timer 使用
@Configuration
public class MyTimer {
@Bean
public void testQuartzTrigger1() {
//1.创建一个timer实例
Timer timer = new Timer();
//2.创建一个MyTimerTask实例
MyTimeTask myTimeTask = new MyTimeTask("No.1");
//3.通过timer定时定频率调用myTimerTask的业务逻辑
// 即 第一次执行是在当前时间的两秒之后,之后每隔一秒钟执行一次\
timer.schedule(myTimeTask,2000L,1000L);
}
}
执行
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.TimerTask;
/**
* @ClassName MyTimeTask
* @Description TODO
* @Author wushaopei
* @Date 2019/7/26 15:55
* @Version 1.0
*/
public class MyTimeTask extends TimerTask{
private static Logger logger = LoggerFactory.getLogger(MyTimeTask.class);
private String name;
public MyTimeTask(String inputName){
name = inputName;
}
@Override
public void run() {
//打印当前name 的内容
System.out.println("Current exec name is " + name);
logger.info(System.currentTimeMillis()+"111");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Quartz 集群配置
以及调度容器 和Calendar的使用,暂时没有写,太难了。
其他ScheduledExecutor 方面的测试。