Spring中的@Scheduled | 8lovelife's life
0%

Spring中的@Scheduled

WHAT

@Scheduled 由Spring定义,用于将方法设置为调度任务。如:方法每隔十秒钟被执行、方法在固定时间点被执行等

  1. @Scheduled(fixedDelay = 1000)
    上一个任务结束到下一个任务开始的时间间隔为固定的1秒,任务的执行总是要先等到上一个任务的执行结束

  2. @Scheduled(fixedRate = 1000)
    每间隔1秒钟就会执行任务(如果任务执行的时间超过1秒,则下一个任务在上一个任务结束之后立即执行)

  3. @Scheduled(fixedDelay = 1000, initialDelay = 2000)
    第一次执行的任务将会延迟2秒钟后才会启动

  4. @Scheduled(cron = “0 15 10 15 * ?”)
    Cron表达式,每个月的15号上午10点15开始执行任务

  5. 在配置文件中配置任务调度的参数

    @Scheduled(fixedDelayString = “${fixedDelay.in.milliseconds}”)
    @Scheduled(fixedRateString = “${fixedRate.in.milliseconds}”)
    @Scheduled(cron = “${cron.expression}”)

WHY

@Scheduled使用方便,不需要自己去写复杂的任务调度。注解的方式非常灵活,只需要在方法上添加@Scheduled注解就能定义调度的任务,任何无参的方法都可以瞬间成为供调度的任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 关闭线程池中超过空闲时间的线程
* @param poolingConnectionManager
* @return
*/
@Bean
public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager poolingConnectionManager) {
return new Runnable() {
@Override
@Scheduled(fixedDelay = 10000, initialDelay = 1000)
public void run() {
try {
if (poolingConnectionManager != null) {
log.info("run IdleConnectionMonitor - Closing expired and idle connections...");
poolingConnectionManager.closeExpiredConnections();
poolingConnectionManager.closeIdleConnections(properties.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS);
} else {
log.info("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
}
} catch (Exception e) {
log.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e);
}
}
};
}

HOW

Spring是如何实现如此简洁的任务调度定义的?怎么使用@Scheduled?

  • Requirements
  1. Spring容器中需要创建 Bean: ScheduledAnnotationBeanPostProcessor
  2. Spring容器中需要有TaskScheduler实现类的实例
  3. 无参方法添加@Scheduled注解

扩展

扩展有两种方式

  • 实现SchedulingConfigurer接口
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
        // 优先级高
    @Configuration
    public class SchedulerConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.setTaskScheduler(threadPoolTaskScheduler());
    }

    @Bean(destroyMethod = "shutdown")
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setThreadNamePrefix("poolmary&mark");
    scheduler.setPoolSize(50);
    return scheduler;
    }

    }
  • 创建TaskScheduler的实现Bean
    1
    2
    3
    4
    5
    6
    7
    8
    // 相对实现SchedulingConfigurer接口的方式,优先级低
    @Bean
    public TaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setThreadNamePrefix("poolScheduler");
    scheduler.setPoolSize(50);
    return scheduler;
    }

原理

  1. ScheduledAnnotationBeanPostProcessorpostProcessAfterInitialization方法将@Scheduled的方法包装为指定的task添加到ScheduledTaskRegistrar
  2. ScheduledAnnotationBeanPostProcessor会监听Spring的容器初始化事件,在Spring容器初始化完成后进行TaskScheduler实现类实例的查找,若发现有SchedulingConfigurer的实现类实例,则跳过3
  3. 查找TaskScheduler的实现类实例默认是通过类型查找,若有多个实现则会查找名字为”taskScheduler”的实现Bean,若没有找到则在 ScheduledTaskRegistrar调度任务的时候会创建一个newSingleThreadScheduledExecutor,将TaskScheduler的实现类实例设置到ScheduledTaskRegistrar属性中
  4. ScheduledTaskRegistrarscheduleTasks方法触发任务调度
  5. 真正调度任务的类是TaskScheduler实现类中的ScheduledExecutorService,由J.U.C提供

事例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@EnableScheduling
public class SchedulerConfigDemo {

private final static SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");

private final static Logger log = LoggerFactory.getLogger(SchedulerConfigDemo.class);

@Scheduled(fixedRate = 2000, initialDelay = 1000)
public void testScheduler() {
log.info("start {}", sdf.format(new Date()));
}

@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("poolScheduler");
scheduler.setPoolSize(10);
return scheduler;
}
}

Music is the strongest form of magic. - 1900

La leggenda del pianista sull’oceano