Getting Started with Spring Boot - Advanced (3) - Scheduled Tasks (@Scheduled)

Mainly used for regular mailing, automatic maintenance at night, etc.

(1) Turn on the scheduled task function
@Configuration
@EnableScheduling
public class SpringTaskScheduleConfig {
    @Bean
    public TaskScheduler poolScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("poolScheduler");
        scheduler.setPoolSize(10);
        return scheduler;
    }
}

*** Spring4 only allows to define one TaskScheduler.

(2) Define timed tasks

1) @Scheduled annotation
@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomeTask(){
}

@Scheduled(fixedDelay = 2000)
public void fixedDelayJob() {
}

@Scheduled(fixedRate = 2000)
public void fixedRateJob() {
}

  • Cron – Free time to specify
  • FixedRate – time after start
  • FixedDelay - timed when done

2) Implement 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) Rules are defined to the configuration file

application.properties
quote
cron.expression=0 0 0/1 * * ?
task.exec.time.delayed=5000

@Scheduled(cron = "${cron.expression}")
public void demoServiceMethod() {
}

@Scheduled(fixedDelayString = "${task.exec.time.delayed}")
public void autoProcess() {
}


(4) Scheduled tasks under the cluster

1) When multiple servers are started by intercepting the limited scheduled tasks through AOP
, not all servers can execute scheduled tasks at the same time. The easiest way is to only allow special services to execute scheduled tasks.

application.properties
quote
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) Integrate Quartz Scheduler
Quartz's cluster solution is database-based and seamlessly connects with Spring.

a) import the 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) Import the table schema required by Quartz into the database
After downloading quartz-2.2.3-distribution.tar.gz from http://www.quartz-scheduler.org/downloads/, quartz-2.2.3-distribution.tar. There are table structure definition DDL in gz\quartz-2.2.3\docs\dbTables\, about 11 tables.

c) Configure 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
quote
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

application.properties
quote
cron.job1.expression=0 0/3 * * * ?
cron.job2.expression=0 0/5 * * * ?


c) Define Job

based on 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. ");
	}

}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326684538&siteId=291194637