How to conditionally enable or disable scheduled jobs in Spring?

前端 未结 11 1342
轻奢々
轻奢々 2020-11-28 07:26

I am defining scheduled jobs with cron style patterns in Spring, using the @Scheduled annotation.

The cron pattern is stored in a config properties file

相关标签:
11条回答
  • 2020-11-28 07:41

    We can disable the bean creation of the class having that scheduled methods using @Conditional annotation. This is very similar to @ConditionalOnProperty. This is used to conditionally spin up a bean on to the spring context. If we set the value to false, then the bean will not be spun up and loaded to spring. Below is the code.

    application.properties:

    com.boot.enable.scheduling=enable
    

    Condition:

    public class ConditionalBeans implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return "enabled".equalsIgnoreCase(context.getEnvironment().getProperty("com.boot.enable.scheduling"));
        }
    }
    

    My schedule class

    @Service
    @Conditional(ConditionalSchedules.class)
    public class PrintPeriodicallyService {
    
        @Scheduled(fixedRate = 3000)
        public void runEvery3Seconds() {
            System.out.println("Current time : " + new Date().getTime());
        }
    }
    

    This approach has a lot of flexibility where the condition generation is totally under our control.

    0 讨论(0)
  • 2020-11-28 07:46

    You can also create a Bean based on condition and that Bean can have a Scheduled method.

    @Component
    @Configuration
    @EnableScheduling
    public class CustomCronComponent {
        @Bean
        @ConditionalOnProperty(value = "my.cron.enabled", matchIfMissing = true, havingValue = "true")
        public MyCronTask runMyCronTask() {
            return new MyCronTask();
        }
    }
    

    and

    @Component
    public class MyCronTask {
        @Scheduled(cron = "${my.cron.expression}")
        public void run() {
            String a = "";
        }
    }
    
    0 讨论(0)
  • 2020-11-28 07:48

    Spring Boot provides @ConditionalOnProperty, which would be perfect if you were using Spring Boot. This annotation is a specialization of @Conditional, introduced with Spring 4.0.0.

    Assuming you're just using "regular" spring and not Spring Boot, you could create your own Condition implementation for use with @Conditional that would mimic Spring Boot's @ConditionalOnProperty.

    0 讨论(0)
  • 2020-11-28 07:49
    @Component
    public class CurrencySyncServiceImpl implements CurrencySyncService {
    
        private static Boolean isEnableSync;
        /**
         * Currency Sync FixedDelay in minutes
         */
        private static Integer fixedDelay;
    
        @Transactional
        @Override
        @Scheduled(fixedDelayString = "#{${currency.sync.fixedDelay}*60*1000}")
        public void sync() {
            if(CurrencySyncServiceImpl.isEnableSync) {
                //Do something
                //you can use DAO or other autowired beans here.
            }
        }
    
        @Value("${currency.sync.fixedDelay}")
        public void setFixedDelay(Integer fixedDelay) {
            CurrencySyncServiceImpl.fixedDelay = fixedDelay;
        }
    
        @Value("${currency.sync.isEnable}")
        public void setIsEnableSync(Boolean isEnableSync) {
            CurrencySyncServiceImpl.isEnableSync = isEnableSync;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 07:49

    Please see my answer in another question. I think this is the best way to solve it. How to stop a scheduled task that was started using @Scheduled annotation?

    Define a custom annotation like below.

    @Documented
    @Retention (RUNTIME)
    @Target(ElementType.TYPE)
    public @interface ScheduledSwitch {
        // do nothing
    }
    

    Define a class implements org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.

    public class ScheduledAnnotationBeanPostProcessorCustom 
        extends ScheduledAnnotationBeanPostProcessor {
    
        @Value(value = "${prevent.scheduled.tasks:false}")
        private boolean preventScheduledTasks;
    
        private Map<Object, String> beans = new HashMap<>();
    
        private final ReentrantLock lock = new ReentrantLock(true);
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            ScheduledSwitch switch = AopProxyUtils.ultimateTargetClass(bean)
                .getAnnotation(ScheduledSwitch.class);
            if (null != switch) {
                beans.put(bean, beanName);
                if (preventScheduledTasks) {
                    return bean;
                }
            }
            return super.postProcessAfterInitialization(bean, beanName);
        }
    
        public void stop() {
            lock.lock();
            try {
                for (Map.Entry<Object, String> entry : beans.entrySet()) {
                    postProcessBeforeDestruction(entry.getKey(), entry.getValue());
                }
            } finally {
                lock.unlock();
            }
        }
    
        public void start() {
            lock.lock();
            try {
                for (Map.Entry<Object, String> entry : beans.entrySet()) {
                    if (!requiresDestruction(entry.getKey())) {
                        super.postProcessAfterInitialization(
                            entry.getKey(), entry.getValue());
                    }
                }
            } finally {
                lock.unlock();
            }
        }
    
    }
    

    Replace ScheduledAnnotationBeanPostProcessor bean by the custom bean in configuration.

    @Configuration
    public class ScheduledConfig {
    
        @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
            return new ScheduledAnnotationBeanPostProcessorCustom();
        }
    
    }
    

    Add @ScheduledSwitch annotation to the beans that you want to prevent or stop @Scheduled tasks.

    0 讨论(0)
  • 2020-11-28 07:50

    The most efficient way to disable @Scheduled in Spring. Just set crone expression like "-". It will disable the @Scheduled.

    @Scheduled(cron = "-")
    public void autoEvictAllCache() {
        LOGGER.info("Refresing the Cache Start :: " + new Date());
        activeMQUtility.sendToTopicCacheEviction("ALL");
        LOGGER.info("Refresing the Cache Complete :: " + new Date());
    }
    

    For more info:

    0 讨论(0)
提交回复
热议问题