'Spring Boot @EnableScheduling conditionally
Is there a way to make @EnableScheduling conditional based on an application property? also is it possible to disable controllers based on properties too?
What I'm trying to achieve is to have the same spring boot application used to serve web requests (but not run scheduled tasks on the same machine), and also install the same app on backend servers to run only scheduled tasks.
My app looks like this
@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
And a sample scheduled job looks like this
@Component
public class MyTask {
@Scheduled(fixedRate = 60000)
public void doSomeBackendJob() {
/* job implementation here */
}
}
Solution 1:[1]
I Solved this, here is what I did for future reference:
- Removed @EnableScheduling annotation from my app
- Added a new configuration class and conditional to enable/disable scheduling based on an application property
-
@Configuration
public class Scheduler {
@Conditional(SchedulerCondition.class)
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
And the conditional class
public class SchedulerCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return Boolean.valueOf(context.getEnvironment().getProperty("com.myapp.config.scheduler.enabled"));
}
}
Also, to disable web server on the backend server, just add the following to the application.properties file:
spring.main.web_environment=false
Solution 2:[2]
You can annotate a bean injection like this:
@Bean
@ConditionalOnProperty(prefix = "your.property", name = "yes", matchIfMissing = true)
public void doSomeBackendJob() {
/* job implementation here */
}
Bonus: Since you want to run different things in different machines, i.e., you will deploy the same app with different configurations, you could use spring profiles, if that's the case you can annotate a class or method like this:
@Component
@Profile({ Constants.SPRING_PROFILE_PRODUCTION, Constants.SPRING_PROFILE_TEST })
public class TheClass{...}
Solution 3:[3]
I ended up creating a separate @Configuration class for scheduling and used the @ConditionalOnProperty annotation to toggle scheduling
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "scheduling", name="enabled", havingValue="true", matchIfMissing = true)
public class SchedulerConfig {
}
in my application.yml file I then added
scheduling:
enabled: true
Solution 4:[4]
- I think scheduler is not configuration.
- No need to set
prefix
in@ConditionalOnProperty
- No need to create scheduler over
@Bean
in configuration class.
My variant:
@Component
@EnableScheduling
@ConditionalOnProperty(value = "scheduler.enabled", havingValue = "true")
public class MyScheduler {
@Scheduled(...)
public void doWork() {
...
}
}
Solution 5:[5]
Instead of using @ConditionalOnProperty
you could also use spring profiles to conditionally turn scheduling on or off.
First you need to define the spring profile that will activate your scheduling component. You can define an active spring profile by adding the property spring.profiles.active
to your application.properties
file. In my example i'll name the profile cron
.
spring.profiles.active=cron
Next we annotate the scheduling component with @Profile("cron")
.
@Service
@EnableScheduling
@Profile("cron")
public class ScheduleService {
@Scheduled(...)
public void cronJob() {
...
}
}
The @Profile
annotation guarantees that the ScheduleService
class will only be active when the cron
profile is set. If it is not set both the class and the @EnableScheduling
annotation will be ignored by spring
.
You can also combine the cron
profile with another spring profile. For example: Lets say you only want the cron jobs to be active when the application is running in production mode. In this case you could define another spring profile (for instance prod
) and use it as a second condition in the @Profile
annotation. First you add the prod
profile to the spring property.
spring.profiles.active=prod,cron
Next you change the condition in @Profile
to:
@Profile("prod & cron")
Now the ScheduleService
is only active when both the prod
and cron
profiles are active.
More information on how to define advanced @Profile
conditions can be found here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | ashario |
Solution 4 | |
Solution 5 |