我使用@Scheduled
注释在Spring中定义具有cron样式模式的预定作业。
cron模式存储在配置属性文件中。实际上有两个属性文件:一个默认配置,一个依赖于环境的配置文件配置(例如dev,test,prod customer 1,prod customer 2等)并覆盖一些默认值。
我在spring上下文中配置了一个属性占位符bean,这允许我使用${}
样式占位符从我的属性文件中导入值。
作业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中使用此参数来有条件地创建或明显忽略bean,具体取决于此配置参数?
一个明显的解决方法是定义永远不会评估的cron模式,因此永远不会执行作业。但是仍然会创建bean并且配置会有点模糊,所以我觉得必须有更好的解决方案。
@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...
}
}
}
Spring Boot提供了@ConditionalOnProperty,如果你使用的是Spring Boot,那将是完美的。这个注释是@Conditional的一个特化,在Spring 4.0.0中引入。
假设您只使用“常规”弹簧而不是Spring Boot,您可以创建自己的Condition实现,以便与模仿Spring Boot的@ConditionalOnProperty的@Conditional一起使用。
您可以按条件将计划方法分组为多个服务,并按如下方式初始化它们:
@Service
@ConditionalOnProperty("yourConditionPropery")
public class SchedulingService {
@Scheduled
public void task1() {...}
@Scheduled
public void task2() {...}
}
如果您希望从属性切换@EnableScheduling,可以在Spring Boot中将@EnableScheduling注释移动到配置类并使用@ConditionalOnProperty,如下所示:
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "com.example.scheduling", name="enabled", havingValue="true", matchIfMissing = true)
public class SchedulingConfiguration {
}
这将禁用应用程序的计划。在您希望能够运行应用程序一次或根据其启动方式安排应用程序的情况下,这可能很有用。
来自wilkinsona的评论:https://github.com/spring-projects/spring-boot/issues/12682
你的问题陈述了条件实际创建bean。如果您至少使用Spring 3.1,则可以使用@Profile使用此参数轻松完成此操作。
@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;
}
}
我知道我的答案是一个黑客,但给出一个永远不会执行的有效cron表达式可能会解决问题(在特定于环境的配置中),Quartz: Cron expression that will never execute
您还可以根据条件创建Bean,并且Bean可以具有Scheduled方法。
@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 = "";
}
}