在春季引导集成测试中禁用@Schedule

如何在Spring Boot IntegrationTest上禁用计划自动启动?

谢谢。


答案 1

请注意,外部组件可能会自动启用调度(请参阅来自 Spring Framework 的 HystrixStreamAutoConfigurationMetricExportAutoConfiguration)。因此,如果您尝试在指定 的类上使用 或,则由于外部组件,调度仍将启用。@ConditionalOnProperty@Profile@Configuration@EnableScheduling

一个解决方案

有一个类支持通过 进行调度,但随后将计划的作业放在单独的类中,每个类都用于启用/禁用包含@Scheduled任务的类。@Configuration@EnableScheduling@ConditionalOnProperty

不要在同一类中拥有 和,否则您将遇到外部组件无论如何都要启用它的问题,因此将被忽略。@Scheduled@EnableScheduling@ConditionalOnProperty

例如:

@Configuration
@EnableScheduling
public class MyApplicationSchedulingConfiguration {
}

然后在单独的类中

@Named
@ConditionalOnProperty(value = "scheduling.enabled", havingValue = "true", matchIfMissing = false)
public class MyApplicationScheduledTasks {

  @Scheduled(fixedRate = 60 * 60 * 1000)
  public void runSomeTaskHourly() {
    doStuff();
  }
}

此解决方案的问题在于,每个计划的作业都需要位于其自己的类中,并指定。如果错过了该注释,则作业将运行。@ConditionalOnProperty

另一种解决方案

扩展 和 重写这些方法。在这些方法中,您可以执行检查以查看作业是否应运行。ThreadPoolTaskSchedulerTaskScheduler

然后,在使用@EnableScheduling的 @Configuration 类中,还可以创建一个名为 taskScheduler 的@Bean,它返回自定义线程池任务计划程序)。

例如:

public class ConditionalThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {

  @Inject
  private Environment environment;

  // Override the TaskScheduler methods
  @Override
  public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
    if (!canRun()) {
      return null;
    }
    return super.schedule(task, trigger);
  }

  @Override
  public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
    if (!canRun()) {
      return null;
    }
    return super.schedule(task, startTime);
  }

  @Override
  public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
    if (!canRun()) {
      return null;
    }
    return super.scheduleAtFixedRate(task, startTime, period);
  }

  @Override
  public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
    if (!canRun()) {
      return null;
    }
    return super.scheduleAtFixedRate(task, period);
  }

  @Override
  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
    if (!canRun()) {
      return null;
    }
    return super.scheduleWithFixedDelay(task, startTime, delay);
  }

  @Override
  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
    if (!canRun()) {
      return null;
    }
    return super.scheduleWithFixedDelay(task, delay);
  }

  private boolean canRun() {
    if (environment == null) {
      return false;
    }

    if (!Boolean.valueOf(environment.getProperty("scheduling.enabled"))) {
      return false;
    }

    return true;
  }
}

使用我们的自定义调度程序创建任务调度程序 Bean 并启用调度的配置类

@Configuration
@EnableScheduling
public class MyApplicationSchedulingConfiguration {

  @Bean
  public TaskScheduler taskScheduler() {
    return new ConditionalThreadPoolTaskScheduler();
  }
}

上述内容的潜在问题是,您已经创建了对内部Spring类的依赖项,因此,如果将来有更改,则必须修复兼容性。


答案 2

我遇到了同样的问题。尝试了Spring的属性与我的调度Bean,但调度仍然在测试中被激活。@ConditionalOnProperty

我发现的唯一好的解决方法是覆盖 Test 类中的调度属性,以便作业没有真正的运行机会。

如果实际作业使用属性每 5 分钟运行一次my.cron=0 0/5 * * * *

public class MyJob {

    @Scheduled(cron = "${my.cron}")
    public void execute() {
        // do something
    }
} 

然后在测试类中,您可以将其配置为:

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"my.cron=0 0 0 29 2 ?"}) // Configured as 29 Feb ;-)
public class MyApplicationTests {

    @Test
    public void contextLoads() {
    }

}

因此,即使您的作业被激活,它也只会在2月29日的第0个小时运行,每4年发生一次。所以你有一个非常渺茫的机会来运行它。

您可以提出更多花哨的cron设置来满足您的要求。


推荐