Spring Configuring TaskScheduler Examples

0

A trigger determines the next execution time of a task. Triggers are based on fixed delay, fixed rating or cron expression. When a task is scheduled it can be based on on of these triggers or a custom implementation of Trigger interface. Spring abstracts the scheduling of a task using TaskScheduler interface.

In this article, we will see several ways of injecting TaskScheuler implementation. If none is set then the default implementation that gets configured is ThreadPoolTaskScheduler which in turn delegates to a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically.

Configuring TaskScheduler using a bean

By default spring delegates the task scheduling to ScheduledThreadPoolExecutor implementation with pool size one. In this example we will override the default single sized thread pool executor with the a thread pool executor of size ten. We just need to include a bean of class ThreadPoolTaskScheduler. Method poolScheduler() is a @Bean annotated method that returns an instance of ThreadPoolTaskScheduler. The pool size is set to ten and we also have given a name to the scheduler.

The class is annotated with @EnableScheduling so that the spring scheduler is configured. We also have a @Scheduled annotated method that is configured to run every two seconds.

SpringTaskScheduleBeanExample:

package com.javarticles.spring;

import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
@EnableScheduling
public class SpringTaskScheduleBeanExample {

    private AtomicInteger counter = new AtomicInteger(0);
    
    @Scheduled(fixedRate = 2000)
    public void fixedRateJob() {
        int jobId = counter.incrementAndGet();
        System.out.println("Job @ fixed rate " + new Date() + ", jobId: " + jobId);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Job " + jobId + " done");
    }

    @Bean
    public TaskScheduler poolScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("poolScheduler");
        scheduler.setPoolSize(10);
        return scheduler;
    }
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                SpringTaskScheduleBeanExample.class);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            context.close();
        }
    }
}

You can see from the output poolScheduler is started. Next the scheduler runs the task configured and in the end shuts down the scheduler.

Output:

May 16, 2016 5:19:43 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.spring[email protected]49097b5d: startup date [Mon May 16 17:19:43 IST 2016]; root of context hierarchy
May 16, 2016 5:19:43 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler initialize
INFO: Initializing ExecutorService  'poolScheduler'
Job @ fixed rate Mon May 16 17:19:43 IST 2016, jobId: 1
Job 1 done
Job @ fixed rate Mon May 16 17:19:45 IST 2016, jobId: 2
Job 2 done
Job @ fixed rate Mon May 16 17:19:47 IST 2016, jobId: 3
May 16, 2016 5:19:48 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.spring[email protected]49097b5d: startup date [Mon May 16 17:19:43 IST 2016]; root of context hierarchy
Job 3 done
May 16, 2016 5:19:48 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler shutdown
INFO: Shutting down ExecutorService 'poolScheduler'

Configuring TaskScheduler using SchedulingConfigurer

Another way of injecting TaskScheduler bean is by making a @Configuration annotated class implement SchedulingConfigurer interface. This gives a more programmatic control for setting a specific TaskSchedule bean. One can also configure custom triggers. See method configureTasks() where we not only set a scheduler but also add a new trigger.

SpringSchedulingConfigurerBeanExample:

package com.javarticles.spring;

import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@Configuration
@EnableScheduling
public class SpringSchedulingConfigurerBeanExample {

    private AtomicInteger counter = new AtomicInteger(0);
    
    @Scheduled(fixedRate = 2000)
    public void fixedRateJob() {
        int jobId = counter.incrementAndGet();
        System.out.println("Job @ fixed rate " + new Date() + ", jobId: " + jobId);
    }
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                SpringSchedulingConfigurerBeanExample.class);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            context.close();
        }
    }
    
    @Configuration
    static class RegisterTaskSchedulerViaSchedulingConfigurer implements SchedulingConfigurer {

        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.setTaskScheduler(poolScheduler());
            
            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;
        }
    }
}

Output:

May 16, 2016 5:37:35 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.spring[email protected]4783da3f: startup date [Mon May 16 17:37:35 IST 2016]; root of context hierarchy
May 16, 2016 5:37:35 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler initialize
INFO: Initializing ExecutorService  'poolScheduler'
Job @ fixed rate Mon May 16 17:37:35 IST 2016, jobId: 1
Job @ fixed rate Mon May 16 17:37:35 IST 2016, Thread name is poolScheduler2
Job @ fixed rate Mon May 16 17:37:36 IST 2016, Thread name is poolScheduler1
Job @ fixed rate Mon May 16 17:37:37 IST 2016, Thread name is poolScheduler3
Job @ fixed rate Mon May 16 17:37:37 IST 2016, jobId: 2
Job @ fixed rate Mon May 16 17:37:38 IST 2016, Thread name is poolScheduler4
Job @ fixed rate Mon May 16 17:37:39 IST 2016, jobId: 3
Job @ fixed rate Mon May 16 17:37:39 IST 2016, Thread name is poolScheduler5
May 16, 2016 5:37:40 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.spring[email protected]4783da3f: startup date [Mon May 16 17:37:35 IST 2016]; root of context hierarchy
May 16, 2016 5:37:40 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler shutdown
INFO: Shutting down ExecutorService 'poolScheduler'

Configuring scheduler via XML

In our last example, we use task namespace based XML tags to configure a scheduler. <task:annotation-driven/> will configure the task scheduler bean processor. We can create a task scheduler bean and specify the task scheduler bean name in attribute scheduler.

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd">

	<task:annotation-driven scheduler="poolScheduler"/>
	<task:scheduler id="poolScheduler" pool-size="10"/>
	<bean class="com.javarticles.spring.SpringTaskScheduleViaXMLExample" />
</beans>

SpringTaskScheduleViaXMLExample:

package com.javarticles.spring;

import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;

public class SpringTaskScheduleViaXMLExample {

    private AtomicInteger counter = new AtomicInteger(0);
    
    @Scheduled(fixedRate = 2000)
    public void fixedRateJob() {
        int jobId = counter.incrementAndGet();
        System.out.println("Job @ fixed rate " + new Date() + ", jobId: " + jobId);
    }

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            context.close();
        }
    }
}

Output:

May 16, 2016 5:48:05 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org[email protected]1f17ae12: startup date [Mon May 16 17:48:05 IST 2016]; root of context hierarchy
May 16, 2016 5:48:05 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
May 16, 2016 5:48:05 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler initialize
INFO: Initializing ExecutorService  'poolScheduler'
May 16, 2016 5:48:05 PM org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'poolScheduler' of type [class org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler]is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Job @ fixed rate Mon May 16 17:48:05 IST 2016, jobId: 1
Job @ fixed rate Mon May 16 17:48:07 IST 2016, jobId: 2
Job @ fixed rate Mon May 16 17:48:09 IST 2016, jobId: 3
May 16, 2016 5:48:10 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org[email protected]1f17ae12: startup date [Mon May 16 17:48:05 IST 2016]; root of context hierarchy
May 16, 2016 5:48:10 PM org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler shutdown
INFO: Shutting down ExecutorService 'poolScheduler'

Download the source code

This was an example about the various ways of configuring spring task scheduler.

You can download the source code here: springTaskScheduerExample.zip

About Author

Ram's expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring. You can reach him at [email protected]

Comments are closed.