gstackoverflow
gstackoverflow

Reputation: 37014

Is there way to use @Scheduled together with Duration string like 15s and 5m?

I have following annotation in my code

@Scheduled(fixedDelayString = "${app.delay}")

At this case I have to have properties like this

app.delay=10000 #10 sec

Propery file looks unreadable because I have calculate value to miliseconds.

Is there way to pass value like 5m or 30s there ?

Upvotes: 12

Views: 5819

Answers (5)

Dimitri Mestdagh
Dimitri Mestdagh

Reputation: 44757

As far as I know, you can't do it directly. However, Spring boot configuration properties do support automatic conversion of parameters like 15s and 5m to Duration.

This means you could create a @ConfigurationProperties class like this:

@ConfigurationProperties("app")
public class AppProperties {
    private Duration delay;

    // Setter + Getter
}

Additionally, since you can use bean references with Spring's Expression Language within the @Scheduled annotation, you can do something like this:

@Scheduled(fixedDelayString = "#{@'app-com.xyz.my.pkg.AppProperties'.delay}")
public void schedule() {
    log.info("Scheduled");
}

Note: When you use @EnableConfigurationProperties or @ConfigurationPropertiesScan, the configurationproperties beans are registered with the name <prefix>-<fully qualified classname>. So in the example above, I'm assuming that the AppProperties class is located in a package called com.xyz.my.pkg.

If you don't like this, you can also use the @Component("beanName") annotation on top of the AppProperties class to give it a different bean name.


Alternatively, you can programmatically add a task to the TaskScheduler. The benefit of that is that you have more compile-time safety.

@Bean
public ScheduledFuture<?> schedule(TaskScheduler scheduler, AppProperties properties) {
    return scheduler.scheduleWithFixedDelay(() -> log.info("Scheduled"), properties.getDelay());
}

Upvotes: 14

marud
marud

Reputation: 103

I understand this is a fairly old question but maybe it's worth to provide an updated (as of 2023) answer.

There are actually a couple of ways to do this.

I will assume the property is defined as a "natural" time string, i.e. app.delay=20s instead of app.delay=PT20S, but both cases would work.

Plain Properties

If the property app.delay is not part of of @ConfigurationProperties, you can use the following expression:

@Scheduled(fixedDelayString = "#{T(org.springframework.boot.convert.ApplicationConversionService).getSharedInstance().convert('${app.delay}', T(java.time.Duration)).toMillis()}")

Configuration Properties

If you defined the property app.delay as part of "normal" (i.e. not a @Component) @ConfigurationProperties, like so:

@ConfigurationProperties("app")
public class AppProperties {
    private Duration delay;
    // Getters + Setters
}

Then, assuming this class is in package com.package, you can use

@Scheduled(fixedDelayString = "#{@'app-com.package.AppProperties'.getDelay().toMillis()}")

Because this is how naming of the Configuration Properties beans works in Spring Boot (see reference doc).

Configuration Properties (as @Component)

(which is the original answer by @g00glen00b)
If you defined the property app.delay as part of @ConfigurationProperties, which are also a @Component like so:

@Component
@ConfigurationProperties("app")
public class AppProperties {
    private Duration delay;
    // Getters + Setters
}

Then you can refer to the bean name as follows

@Scheduled(fixedDelayString = "#{@appProperties.getDelay().toMillis()}")

Upvotes: 4

userM1433372
userM1433372

Reputation: 5517

I'm using this code and it works fine:

@Scheduled(fixedDelayString = "PT10S")

Upvotes: 4

daniu
daniu

Reputation: 15028

You can just adjust your annotation to use a SpEL multiplication.

@Scheduled(fixedDelayString = "#{${app.delay} * 1000}")

Upvotes: 3

JB Nizet
JB Nizet

Reputation: 692271

Assuming you're using a recent enough version of Spring, you can use any String that can be parsed to a java.time.Duration. In your case:

PT10S

Upvotes: 5

Related Questions