111 votes

Comment activer ou désactiver de manière conditionnelle les tâches planifiées dans Spring ?

Je suis en train de définir des tâches planifiées avec des modèles de style cron dans Spring, en utilisant la fonction @Scheduled annotation.

Le modèle de cron est stocké dans un fichier de propriétés de configuration. En fait, il y a deux fichiers de propriétés : une configuration par défaut et une configuration de profil qui dépend de l'environnement (par exemple dev, test, prod client 1, prod client 2, etc.) et qui remplace certaines des valeurs par défaut.

J'ai configuré un bean placeholder de propriété dans mon contexte de printemps qui me permet d'utiliser ${} pour importer les valeurs de mes fichiers de propriétés.

Le travail des haricots ressemble à ceci :

@Component
public class ImagesPurgeJob implements Job {

    private Logger logger = Logger.getLogger(this.getClass());

    @Override
    @Transactional(readOnly=true)
    @Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
    public void execute() {
        //Do something
            //can use DAO or other autowired beans here
    }
}

Parties pertinentes de mon contexte XML :

<!-- Enable configuration of scheduled tasks via annotations -->
    <task:annotation-driven/>

<!-- Load configuration files and allow '${}' style placeholders -->
    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:config/default-config.properties</value>
                <value>classpath:config/environment-config.properties</value>
            </list>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="ignoreResourceNotFound" value="false"/>
    </bean>

J'aime vraiment ça. C'est assez simple et propre avec un minimum de XML.

J'ai toutefois une autre exigence : certains de ces emplois peuvent être totalement handicapés dans certains cas.

Donc, avant d'utiliser Spring pour les gérer, je les créais manuellement et il y a un paramètre booléen avec le paramètre cron dans les fichiers de configuration, pour spécifier si le travail doit être activé ou non :

jobs.mediafiles.imagesPurgeJob.enable=true or false
jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?

Comment puis-je utiliser ce paramètre dans Spring pour créer conditionnellement ou tout simplement ignorer le bean, en fonction de ce paramètre de configuration ?

Une solution de contournement évidente serait de définir un modèle cron qui ne serait jamais évalué, de sorte que le travail ne soit jamais exécuté. Mais le bean serait quand même créé et la configuration serait un peu obscure, donc je pense qu'il doit y avoir une meilleure solution.

4voto

aweigold Points 1803

Votre question demande de conditionner la création effective du haricot. Vous pouvez le faire facilement avec ce paramètre en utilisant @Profile si vous utilisez au moins Spring 3.1.

Voir la documentation ici : http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/context/annotation/Profile.html

3voto

labm0nkey Points 157

Vous pouvez également créer un Bean basé sur une condition et ce Bean peut avoir une méthode programmée.

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

y

@Component
public class MyCronTask {
    @Scheduled(cron = "${my.cron.expression}")
    public void run() {
        String a = "";
    }
}

2voto

Vinit Solanki Points 527
@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;
    }
}

2voto

Bin Points 51

Veuillez consulter ma réponse dans une autre question. Je pense que c'est la meilleure façon de résoudre le problème. Comment arrêter une tâche planifiée qui a été lancée à l'aide de l'annotation @Scheduled ?

Définissez une annotation personnalisée comme ci-dessous.

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

Définir une classe qui implémente 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();
        }
    }

}

Remplacer le bean ScheduledAnnotationBeanPostProcessor par le bean personnalisé dans la configuration.

@Configuration
public class ScheduledConfig {

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

}

Ajoutez l'annotation @ScheduledSwitch aux beans que vous voulez empêcher ou arrêter les tâches @Scheduled.

0voto

Suraj Points 105

Je sais que ma réponse est un hack, mais donner une expression cron valide qui ne s'exécute jamais peut résoudre le problème (dans la configuration spécifique de l'environnement), Quartz : Une expression Cron qui ne s'exécutera jamais

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X