Friday 5 May 2017

Spring Scheduling

I had the need to implement a periodic process where the period between runs was configurable from a properties file. I am using Spring with XML descriptors so this is a brief how-to on getting this working.

Scheduler

Spring implements a task scheduler and a task executor. My understanding is you need both to run a scheduled task. To add one of these to your spring application you have to add the task schema to your descriptor like this:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd>

Then you add these lines to configure a scheduler and a executor. In my case I only wanted this to be executed in one thread.

        <task:annotation-driven executor="scheduleExecutor" scheduler="scanScheduler"/>
        <task:executor id="scheduleExecutor" pool-size="1"/>
        <task:scheduler id="scanScheduler" pool-size="1"/>

Scheduled Code

The code to be scheduled was created using an annotation. The class was annotated as a component and the method to be called was annotated with the @Scheduled annotation so spring picked it up.

The documentation describes how to use the fixedDelay, cron etc parameters to control how frequently the scheduled operation runs but I needed this to be controlled from a properties file. I found that I could use a property-placeholder to load a properties file and use this in the @Scheduled annotation.

First add the place holder in your XML above the component scan

    <context:property-placeholder location="WEB-INF/tuning.properties"/>
    <context:component-scan base-package="com.somecompany.myproject"/>

Then you can use the fixedDelayString argument to the @Scheduled annotation to access a property (called transactionScanTime in the tuning.properties file)

@Component
public class TransactionScanner
{
    @Scheduled(fixedDelayString="${transactionScanTime}")
    public void scanTransactions()
    {
        // ...
    }
}