(1)开启定时任务功能
@Configuration @EnableScheduling public class SpringTaskScheduleConfig { @Bean public TaskScheduler poolScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setThreadNamePrefix("poolScheduler"); scheduler.setPoolSize(10); return scheduler; } }
*** Spring4只允许定义一个TaskScheduler。
(2)定义定时任务
1)@Scheduled注解
@Scheduled(cron="*/5 * * * * MON-FRI") public void doSomeTask(){ }
@Scheduled(fixedDelay = 2000) public void fixedDelayJob() { }
@Scheduled(fixedRate = 2000) public void fixedRateJob() { }
- Cron – 自由指定时间
- FixedRate – 开始后计时
- FixedDelay – 完成后计时
2)实现SchedulingConfigurer
@Configuration public class MySchedulingConfigurer implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setTaskScheduler(poolScheduler()); // add job taskRegistrar.addFixedRateTask(new IntervalTask( new Runnable() { @Override public void run() { System.out.println("Job @ fixed rate " + new Date() + ", Thread name is " + Thread.currentThread().getName()); } }, 1000, 0)); } @Bean public TaskScheduler poolScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setThreadNamePrefix("poolScheduler"); scheduler.setPoolSize(10); return scheduler; } }
3)动态定义
TaskScheduler(ThreadPoolTaskScheduler)、Trigger(CronTrigger、PeriodicTrigger)。
ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler) appContext.getBean("scheduler"); CronTrigger trigger = new CronTrigger("0 0/5 * * * ?"); // Every 5 minutes ScheduledFuture<Object> scedulefuture = scheduler.schedule(taskObject, trigger);
(3)规则定义到配置文件
application.properties
引用
cron.expression=0 0 0/1 * * ?
task.exec.time.delayed=5000
task.exec.time.delayed=5000
@Scheduled(cron = "${cron.expression}") public void demoServiceMethod() { } @Scheduled(fixedDelayString = "${task.exec.time.delayed}") public void autoProcess() { }
(4)集群下的定时任务
1)通过AOP拦截限定定时任务的启动
多服务器的时候,不能所有服务器都同时执行定时任务,最简单的方法是只让特殊的服务才执行执行定时任务。
application.properties
引用
batch.exec.host=192.168.1.100
@Aspect @Component public class TaskInterceptor { @Value(“${batch.exec.host}”) String batchExecHost; @Around("execution(* com.rensanning.task..*.*(..)) && @annotation(org.springframework.scheduling.annotation.Scheduled)") public Object around(ProceedingJoinPoint pjp) throws Throwable { String methodName = pjp.getSignature().getName(); String currentThread = Thread.currentThread().getName(); if (!allowedBatchExec()) { log.info("Skip batch ({}): {}", currentThread, methodName); return null; } log.info("Begin batch ({}): {}", currentThread, methodName); Stopwatch stopWatch = Stopwatch.createStarted(); try { return pjp.proceed(); } catch (Exception e) { log.error("batch error: {}", methodName, e); return null; } finally { log.info("End batch ({}): {}, elapsed = {} (ms)", currentThread, methodName, stopWatch.elapsed(TimeUnit.MILLISECONDS)); } } private boolean allowedBatchExec() { if (getHostName().equals(batchExecHost)) { return true; } return false; } }
2)集成Quartz Scheduler
Quartz的集群方案是基于数据库的,与Spring无缝对接。
a)导入jar
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.3</version> </dependency>
b)将Quartz所需的表Schema导入数据库
从 http://www.quartz-scheduler.org/downloads/ 下载quartz-2.2.3-distribution.tar.gz后,quartz-2.2.3-distribution.tar.gz\quartz-2.2.3\docs\dbTables\ 里边有表结构定义DDL,大概11个表。
c)配置Quartz
@Configuration public class ConfigureQuartz { @Bean public SpringBeanJobFactory jobFactory(ApplicationContext applicationContext) { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, @Qualifier("sampleJob1Trigger") Trigger trigger1, @Qualifier("sampleJob2Trigger") Trigger trigger2) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setOverwriteExistingJobs(true); factory.setAutoStartup(true); factory.setStartupDelay(20); factory.setJobFactory(jobFactory); factory.setQuartzProperties(quartzProperties()); factory.setTriggers(trigger1, trigger2); return factory; } @Bean(name = "sampleJob1Detail") public JobDetailFactoryBean sampleJob1Detail() { return createJobDetail(SampleJob1.class); } @Bean(name = "sampleJob2Detail") public JobDetailFactoryBean sampleJob2Detail() { return createJobDetail(SampleJob2.class); } @Bean(name = "sampleJob1Trigger") public CronTriggerFactoryBean sampleJob1Trigger(@Qualifier("sampleJob1Detail") JobDetail jobDetail, @Value("${cron.job1.expression}") String job1CronExp) { return createCronTrigger(jobDetail, job1CronExp); } @Bean(name = "sampleJob2Trigger") public CronTriggerFactoryBean sampleJob2Trigger(@Qualifier("sampleJob2Detail") JobDetail jobDetail, @Value("${cron.job2.expression}") String job2CronExp) { return createCronTrigger(jobDetail, job2CronExp); } @Bean public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } private JobDetailFactoryBean createJobDetail(Class<?> jobClass) { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(jobClass); factoryBean.setDurability(true); return factoryBean; } private CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) { CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setCronExpression(cronExpression); factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); return factoryBean; } }
public class AutoWiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
quartz properties
引用
org.quartz.scheduler.instanceName=ClusteredScheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon=true
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.makeThreadsDaemons=true
org.quartz.threadPool.threadCount=20
org.quartz.threadPool.threadPriority=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.misfireThreshold=25000
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
org.quartz.dataSource.myDS.driver=org.postgresql.Driver
org.quartz.dataSource.myDS.URL=jdbc:postgresql://localhost:5432/test
org.quartz.dataSource.myDS.user=postgres
org.quartz.dataSource.myDS.password=postgres
org.quartz.dataSource.myDS.maxConnections=5
org.quartz.dataSource.myDS.validationQuery=select 1
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon=true
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.makeThreadsDaemons=true
org.quartz.threadPool.threadCount=20
org.quartz.threadPool.threadPriority=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.misfireThreshold=25000
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
org.quartz.dataSource.myDS.driver=org.postgresql.Driver
org.quartz.dataSource.myDS.URL=jdbc:postgresql://localhost:5432/test
org.quartz.dataSource.myDS.user=postgres
org.quartz.dataSource.myDS.password=postgres
org.quartz.dataSource.myDS.maxConnections=5
org.quartz.dataSource.myDS.validationQuery=select 1
application.properties
引用
cron.job1.expression=0 0/3 * * * ?
cron.job2.expression=0 0/5 * * * ?
cron.job2.expression=0 0/5 * * * ?
c)定义Job
基于org.quartz.Job
@Component @DisallowConcurrentExecution public class SampleJob1 implements Job { @Autowired private SampleJobService jobService; public void execute(JobExecutionContext context) throws JobExecutionException { jobService.executeSampleJob1(); } }
基于org.springframework.scheduling.quartz.QuartzJobBean
@Component @DisallowConcurrentExecution public class SampleJob2 extends QuartzJobBean { @Autowired private SampleJobService jobService; @Override protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { jobService.executeSampleJob2(); } }
@Service public class SampleJobService { public void executeSampleJob1() { System.out.println(" hello job 1. "); } public void executeSampleJob2() { System.out.println(" hello job 2. "); } }