头图

1、普通关闭:

eg1.正常情况下,只要注释掉@EnableScheduling注解即可,原理就是:

  • 注释掉@EnableScheduling就不会@Import(SchedulingConfiguration.class)
  • 就不会注入ScheduledAnnotationBeanPostProcessor这个后置处理器
  • 这个后置处理器就是用来注册执行@Scheduled定时任务的

eg2.注释掉@EnableScheduling无效,还会执行@Scheduled定时任务?

  • 检查是否项目除启动类还有其它配置类用了@EnableScheduling注解
  • 检查有没有引入spring-session-data-redis依赖,RedisHttpSessionConfiguration内部bean使用了@EnableScheduling
  • 据说spring-boot-starter-actuator依赖也会有,但是我没找到

2、移除定时(推荐)

  • 在容器启动后,获取收集的的定时任务Set<ScheduledTask>
  • 通过后置处理器的postProcessBeforeDestruction来移除任务,这样就不会执行了
@Component
public class ApplicationListenerImpl implements ApplicationListener<ApplicationReadyEvent> {

    @Autowired
    private ScheduledAnnotationBeanPostProcessor beanPostProcessor;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 拿到所有的task(带包装)
        Set<ScheduledTask> tasks = beanPostProcessor.getScheduledTasks();
        Set<Object> rawTasks = new HashSet<>(tasks.size());
        for (ScheduledTask task : tasks) {
            Task t = task.getTask();
            Runnable runnableTemp = t.getRunnable();
            ScheduledMethodRunnable runnable = null;
            if (runnableTemp instanceof ScheduledMethodRunnable) {
                runnable = (ScheduledMethodRunnable) runnableTemp;
            }
            if (runnable == null) {
                continue;
            }

            Object taskObject = runnable.getTarget();
            // 将task所关联的对象放到Set中(就是带@Scheduled方法的类)
            rawTasks.add(taskObject);
        }
        // 调用postProcessBeforeDestruction()方法,将task移除并cancel
        for (Object obj : rawTasks) {
            beanPostProcessor.postProcessBeforeDestruction(obj, "scheduledTasks");
        }
        System.out.println("listener");
    }
}

也可以通过实现ApplicationRunner的方式

区别在于:ApplicationRunnerApplicationListener区别

3、开关控制

配置文件中配置一个 boolean 属性,如果是 true 的话,就开启定时任务,否则不开启。
#application.yml中的配置
scheduled:
  enable: true
其实 @Scheduled 注解,是被一个叫做 ScheduledAnnotationBeanPostProcessor 的类所拦截的,所以我们可以根据配置,决定是否创建这个 bean,如果没有这个 bean,@Scheduled 就不会被拦截,那么定时任务肯定不会执行了,有了这个思路,实现起来就很简单了。需要注意的是:这种方式,启动类上面的 @EnableScheduling 需要去掉。

然后创建一个 ScheduledCondtion 类,内容如下:

public class ScheduledCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //读取配置中的属性
        return Boolean.valueOf(context.getEnvironment().getProperty("scheduled.enable"));
    }
}
这个类的功能很简单,就是去读取配置,然后返回一个 boolean 值。

然后创建一个配置类 ScheduledConfig ,内容如下:

@Configuration
public class ScheduledConfig {
    @Conditional(ScheduledCondition.class)
    @Bean
    public ScheduledAnnotationBeanPostProcessor processor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }
}
这个配置就是以 ScheduledCondtion 为条件,决定是否创建 bean。然后,启动项目,定时任务就会执行,如果我们将配置修改为 false,则不会执行

蚕1蚕2
1 声望0 粉丝