一、定时任务spring schedule和quartz
spring 在3.0自己提供了定时活动schdule,配置简单,可以帮我们实现简单的定时任务功能。而quartz是强大的定时任务插件,适合复杂一点的任务。
二、spring shcedule使用方式(使用spirngboot项目作为演示)
1、导入下列依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2、在java配置类上添加@EnableSchedule开启对任务计划的支持。
3、然后在spring管理的bean当中是用@Schedule注解来规定任务怎样执行。
@Scheduled(fixedRate = 5000) : fixRate的计时是相对于系统时间的,也就是一定相隔会固定时间执行。
@Scheduled(fixDelay = 2000) :
相对于上一次调用的时间,受其他程序调用的影响。如果该函数在其他地方被手动调用,那么这个计时器就会重新计时。
@Scheduled(corn = "0 28 11 ? * *") : cron表达式
三、使用quartz,使用springboot作为演示。
1、最简单的使用方法
首先,配置一个quartzConfig配置类
@Configuration
public class QuartzConfig {
// 配置定时任务firstJob
@Bean
public MethodInvokingJobDetailFactoryBean jobDetail(FirstJob firstJob) {
MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
// 是否设置并发执行
jobDetailFactoryBean.setConcurrent(false);
jobDetailFactoryBean.setTargetObject(firstJob);
jobDetailFactoryBean.setTargetMethod("print");
return jobDetailFactoryBean;
}
// 配置触发器,这里触发器使用的是cronTrigger,没有使用simpleTrigger,
@Bean
public CronTriggerFactoryBean cornTriggerFacrotyBean(JobDetail jobDetail) {
CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
triggerFactoryBean.setCronExpression("1 * * * * ? ");
triggerFactoryBean.setJobDetail(jobDetail);
return triggerFactoryBean;
}
// 配置调度器
@Bean
public SchedulerFactoryBean schedulerFactoryBean(Trigger cornTriggerFacrotyBean) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setSchedulerName("QUARTZ");
bean.setTriggers(cornTriggerFacrotyBean);
bean.setStartupDelay(1);
return bean;
}
}
然后,FirstJob类。
@Service
public class FirstJob {
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
public void print () {
System.out.println("ForstJob ====> print()方法" + fdf.format(new Date()));
}
}
2、比较复杂的使用,quartz使用灵活。
配置ScheduleConfig,配置类,使用了ConfigurationProperties(prefix = "quartz"),把一些东西放到springboot的配置文件中。注意写任务类的bean名称首字母小写,因为在spring容器中就是存储的小写开头的bean。
quartz.scheduler-name=QUARTZ
quartz.thread-count=10
quartz.thread-name-prefix=quartz_worker
quartz.tasks=\printTask: 1 * * * * ?
把对应的任务bean和cron表达式,放到配置文件中,方便维护和测试。ScheduleConfig配置java类如下所示。
@Configuration
@ConfigurationProperties(prefix = "quartz")
@Getter
@Setter
public class ScheduleConfig {
private String schedulerName;
private String tasks;
private String threadCount;
private String threadNamePrefix;
private final ApplicationContext context;
@Autowired
public ScheduleConfig(ApplicationContext context) {
this.context = context;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// 设置调度器名称
schedulerFactoryBean.setSchedulerName(schedulerName);
Properties properties = new Properties();
properties.setProperty("org.quartz.threadPool.threadCount", threadCount);
properties.setProperty("org.quartz.threadPool.threadNamePrefix", threadNamePrefix);
schedulerFactoryBean.setQuartzProperties(properties);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler() throws Exception {
Scheduler scheduler = schedulerFactoryBean().getObject();
scheduler.scheduleJobs(createJobDetailAndTriggerMap(), true);
return scheduler;
}
private Map<JobDetail, Set<? extends Trigger>> createJobDetailAndTriggerMap() throws NoSuchMethodException, ClassNotFoundException, ParseException {
Set<String> tasks = StringUtils.commaDelimitedListToSet(this.tasks);
HashMap<JobDetail, Set<? extends Trigger>> map = new HashMap<>();
for (String task : tasks) {
String[] nameAndCron = task.split(":");
String name = nameAndCron[0];
String cron = nameAndCron[1];
// 根据name获取这个jobDetail
MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
jobDetailFactoryBean.setTargetObject(context.getBean(name));
jobDetailFactoryBean.setTargetMethod("exec");
jobDetailFactoryBean.setName("quartz");
jobDetailFactoryBean.afterPropertiesSet();
// 根据cron配置触发器trigger
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setCronExpression(cron);
cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
cronTriggerFactoryBean.setName("quartz");
cronTriggerFactoryBean.afterPropertiesSet();
CronTrigger cronTrigger = cronTriggerFactoryBean.getObject();
Set<CronTrigger> triggers = new HashSet<>();
triggers.add(cronTrigger);
map.put(jobDetailFactoryBean.getObject(),triggers);
}
return map;
}
}
要注意一定要在jobDetail和触发器cornTrigger设置完要记得afterPropertiesSet();意思就是说把一些其余的配置要自动配置之后,才能使用。不然会报错的。 提供一个jobDetail的案例。因为上面执行的方法都是exec,所以定义一个接口,规范一下所有的任务类。
ITask接口
public interface ITask {
void exec();
}
PrintTask 任务类
@Component
public class PrintTask implement ITask {
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
public static Integer count = 0;
public void exec() {
System.out.println("quartz很爽\t" + count++ + "\t" + fdf.format(new Date()));
}
}