Как условно включить или отключить запланированные задания в Spring?
Spring я определяю запланированные задания с помощью шаблонов стилей cron, используя аннотацию @Scheduled
.
Шаблон cron хранится в файле свойств конфигурации. На самом деле есть два файла свойств: один конфиг по умолчанию и один конфиг профиля, который зависит от среды (например, dev, test, prod customer 1, prod customer 2 и т.д.) И переопределяет некоторые из значений по умолчанию.
Я сконфигурировал компонент-заполнитель свойства в моем весеннем контексте, который позволяет мне использовать заполнители стиля ${}
для импорта значений из моих файлов свойств.
Работа bean выглядит следующим образом:
@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
}
}
Соответствующие части моего контекста 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>
Мне действительно это нравится. Это довольно просто и чисто с минимальным XML.
Однако у меня есть еще одно требование: в некоторых случаях некоторые из этих заданий могут быть полностью отключены.
Итак, прежде чем я использовал Spring для управления ими, я создал их вручную, и в конфигурационных файлах есть логический параметр вместе с параметром cron, чтобы указать, должно ли задание быть включено или нет:
jobs.mediafiles.imagesPurgeJob.enable=true or false
jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?
Как я могу использовать этот параметр в Spring для условного создания или просто игнорирования компонента в зависимости от этого параметра конфигурации?
Один очевидный обходной путь - определить шаблон cron, который никогда не будет оцениваться, поэтому задание никогда не выполняется. Но bean-компонент все равно будет создан, а конфигурация будет немного неясной, поэтому я считаю, что должно быть лучшее решение.
Ответы
Ответ 1
@Component
public class ImagesPurgeJob implements Job {
private Logger logger = Logger.getLogger(this.getClass());
@Value("${jobs.mediafiles.imagesPurgeJob.enable}")
private boolean imagesPurgeJobEnable;
@Override
@Transactional(readOnly=true)
@Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
public void execute() {
//Do something
//can use DAO or other autowired beans here
if(imagesPurgeJobEnable){
Do your conditional job here...
}
}
}
Ответ 2
Spring Boot обеспечивает @ConditionalOnProperty, который был бы идеальным, если бы вы использовали Spring Boot. Эта аннотация является специализацией @Conditional, представленной с Spring 4.0.0.
Предполагая, что вы просто используете "обычный" Spring, а не Spring Boot, вы можете создать собственную реализацию условия для использования с @Conditional, которая будет имитировать Spring Boot @ConditionalOnProperty.
Ответ 3
Вы можете группировать методы расписания по условиям в число сервисов и инициализировать их следующим образом:
@Service
@ConditionalOnProperty("yourConditionPropery")
public class SchedulingService {
@Scheduled
public void task1() {...}
@Scheduled
public void task2() {...}
}
Ответ 4
Если вы хотите переключить @EnableScheduling из свойства, вы можете сделать это в Spring Boot, переместив аннотацию @EnableScheduling в класс конфигурации и используя @ConditionalOnProperty следующим образом:
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "com.example.scheduling", name="enabled", havingValue="true", matchIfMissing = true)
public class SchedulingConfiguration {
}
Это отключит планирование для приложения. Это может быть полезно в ситуации, когда вы хотите иметь возможность запускать приложение один раз или по расписанию в зависимости от того, как оно запускается.
От Уилкинсона комментарий здесь: https://github.com/spring-projects/spring-boot/issues/12682
Ответ 5
В вашем вопросе утверждается условие фактического создания bean. Вы можете легко сделать это с помощью параметра @Profile, если используете не менее Spring 3.1.
Смотрите документацию здесь: http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/context/annotation/Profile.html
Ответ 6
@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;
}
}
Ответ 7
Самый эффективный способ отключить @Scheduled spring.
Просто установите выражение кроны как "-". Это отключит @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());
}
Для получения дополнительной информации:
![enter image description here]()
Ответ 8
Я знаю, что мой ответ - это взлом, но предоставление допустимого выражения cron, которое никогда не выполняется, может устранить проблему (в конфигурации, специфичной для среды), Quartz: выражение Cron, которое никогда не будет выполнено
Ответ 9
Вы также можете создать Бин на основе условия, и у Бина может быть запланированный метод.
@Component
@Configuration
@EnableScheduling
public class CustomCronComponent {
@Bean
@ConditionalOnProperty(value = "my.cron.enabled", matchIfMissing = true, havingValue = "true")
public MyCronTask runMyCronTask() {
return new MyCronTask();
}
}
и
@Component
public class MyCronTask {
@Scheduled(cron = "${my.cron.expression}")
public void run() {
String a = "";
}
}