Skip to content

动态化开启定时任务

更新: 1/29/2026, 12:37:16 PM   字数: 0 字   时长: 0 分钟

​  在部署多个实例的时候,为了避免多个定时任务同步执行时造成的数据库死锁、数据一致性等问题,可以使用SpringBoot中提供的条件注解@Conditional,来实现虽部署多个负载,但只有单个实例执行定时任务的需求。

参考资料

一、配置说明

1、设置启用条件类

​  首先,需要将启动类上面的 @EnableScheduling 注解需要去掉。

java
@SpringBootApplication
//@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

​  然后,在application.yml中添加是否启用定时任务的属性,其中true表示启用,false表示不启用。

yml
#是否启用定时任务
enable:
  scheduled: false

​  接着,新建ScheduledCondition类,读取enable.scheduled属性值。

java
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.stereotype.Component;

@Component
public class ScheduledCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //读取配置中的属性
        return Boolean.parseBoolean(context.getEnvironment().getProperty("enable.scheduled"));
    }
}

2、配置ScheduleConfig

​  SpringBoot中@Scheduled注解,是被一个叫做 ScheduledAnnotationBeanPostProcessor 的类所拦截的,所以,我们可以通过条件注解@Conditional来判断ScheduledCondition条件是否成立,来决定是否创建这个 bean,如果没有这个 bean@Scheduled 就不会被拦截,那么定时任务肯定不会执行了。

java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;

@Configuration
public class ScheduleConfig {
    @Bean
    @Conditional(ScheduledCondition.class)
    public ScheduledAnnotationBeanPostProcessor processor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }
}

​  至此,对于所有通过@Scheduled实现的定时任务已经可以实现动态控制了。但是,如果定时任务是通过while循环实现的,还需将@Conditional注解置于该定时任务类上才行。

二、测试运行

​  启动项目的时候,可以通过设定enable.scheduled的值,实现对实例中定时任务的开启和关闭进行动态控制,其中,true表示启用,false表示不启用。

shell
docker run -d  -e JAVA_OPTS='-Denable.scheduled=true' projectName

1、@Scheduled定时任务

​  新建@Scheduled注解的定时任务,若该定时任务启用,则会在控制台上打印日志。

java
@Component
@Slf4j
public class Task {
    @Scheduled(cron = "0/2 * * * * ?")
    public void doTask() {
        log.info("@Scheduled定时任务运行");
    }
}

2、while循环定时任务

​  新建while循环实现的定时任务,若该定时任务启用,则会在控制台上打印日志。

java
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@Conditional(ScheduledCondition.class)
public class whileTask implements Runnable, InitializingBean {
	
	@Override
	public void run() {
		while (true) {
			// 间隔10秒扫描一次
			DateTimeHelper.sleep(10);
			try {
				log.info("while定时任务运行");
			}
			catch (Exception e) {
				log.error(e.toString());
				e.printStackTrace();
				//睡眠30s
				DateTimeHelper.sleep(30);
			}
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Thread th = new Thread(this);
		th.start();
	}
}

更新时间:

Released under the MIT License.