spring task 通过@EnableScheduling启动流程简析

版权声明:欢迎交流、沟通 QQ:983433479 微信:wj983433479 ;努力学习~赚钱养家不是梦。 https://blog.csdn.net/u012881904/article/details/79996826

spring task

无意间看到这个博客 Spring定时器Scheduled分布式/集群插件,支持数据库、redis缓存等,所以想写点spring -task相关的处理过程的,加深自己对于spring 处理流程的理解。

从@EnableScheduling注解说起

官方的代码上的注释,简单的说就是task 命名空间和这样的注解的使用是一个效果
Enables Spring’s scheduled task execution capability, similar to functionality found in Spring’s task XML namespace. To be used on @{@link Configuration} classes。
下面这两个是配置使用教程
Spring任务调度task scheduled-tasks
spring 定时任务@Scheduled
在我们项目中使用的是如下的方式通过命令空间,但是我个人觉得还是使用@EnableScheduling的方式更加方便我们对于整个项目的处理流程的理解。

<beans>
<task:annotation-driven scheduler="taskScheduler"/>
<task:scheduler id="taskScheduler" pool-size="42"/>
<task:scheduled-tasks scheduler="taskScheduler">
<task:scheduled ref="myTask" method="work" fixed-rate="1000"/>
</task:scheduled-tasks>
<bean id="myTask" class="com.foo.MyTask"/>
</beans>

Spring4.x高级话题(六):@Enable*注解的工作原理
从spring 的Javadoc中可以看到,使用@EnableScheduling通过实现接口SchedulingConfigurer实现对于spring task 中ScheduledExecutorService 的定制,以及可以通过手动添加任务信息。@EnableScheduling 需要配合@Configuration注解使用,在添加这个注解的时候自动导入SchedulingConfiguration进行加载配置信息

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {

}

这里写图片描述

SchedulingConfiguration,registers a ScheduledAnnotationBeanPostProcessor bean capable of processing Spring’s @Scheduled annotation. 对于BeanPostProcessor 我们需要敏感,在BeanFactory.getBean()时候获取Bean的前后对于Bean进行某些逻辑性的扩展加强,可以参考这篇文章讲解得还算不错的。
[spring源码学习]五-BeanPostProcessor的使用
Spring开闭原则的表现-BeanPostProcessor扩展点-1
Spring开闭原则的表现-BeanPostProcessor扩展点-2

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
    @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }
}

ScheduledAnnotationBeanPostProcessor 这个BeanPostProcessor时处理@Scheduled 重要的处理类,有了这个才能好好的处理通过注解放置在方法上执行的task任务。

这篇是阿里的一个小哥,描述spring加载过程中常见的扩展清单,对于spring扩展有详细的描述,这个小哥写的博客的质量不错,推荐常用开源框架扩展清单之原理
这里写图片描述
这里写图片描述
这里写图片描述
此类的作用:
1、Bean post-processor that registers methods annotated with @Scheduled
2、to be invoked by a org.springframework.scheduling.TaskScheduler的实现类
3、This post-processor is automatically registered by Spring’s < task:annotation-driven> or @EnableScheduling annotation.
4、自动指定任何 schedulingconfigurer 实例在容器中,允许定制或使用细粒度的调度器,或者手动注册任务,这个就是之前说的那个接口,可以定制。
如上所述,这个类就是可以运行定制执行类.TaskScheduler 的相关的配置信息,自动的去发现类中含有的@Scheduled这个注解,添加到任务中去。

处理流程

1、根据BeanPostProcessor处于的作用,在Bean创建的时候去查找当前类中所有包含的@Scheduled注解,当然这里做了很多的工作,比如不是从代理类中获取,获取方法上的注解。
2、将这里获取到的注解的方法保存在ScheduledTaskRegistrar List triggerTask List cronTasks List fixedRateTasks List fixedDelayTasks等中缓存启动等待启动的时候一起通过调度类进行调度。
3、无论是通过xml注册的,还是通过注解处理的类,最终都放置在了ScheduledTaskRegistrar中保存等待启动。启动非常的简单,利用spring事件机制,当容器启动完成之后,通过调度器逐条的启动所有的各种类型的任务。关于spring 事件请参考 Spring 事件驱动在项目中的应用

ScheduledAnnotationBeanPostProcessor 实现的各种接口的意义

这里写图片描述

Ordered 当前BeanPostProcessor处理的顺序

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }

EmbeddedValueResolverAware

Spring EmbeddedValueResolverAware 接口获取properties文件属性 主要是为了解析${jmq.address} 类似这样的值的信息定义在注解表达式中的

/**
 * Interface to be implemented by any object that wishes to be notified of a
 * <b>StringValueResolver</b> for the <b> resolution of embedded definition values.
 *
 * <p>This is an alternative to a full ConfigurableBeanFactory dependency via the
 * ApplicationContextAware/BeanFactoryAware interfaces.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 3.0.3
 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#resolveEmbeddedValue(String)
 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanExpressionResolver()
 * @see org.springframework.beans.factory.config.EmbeddedValueResolver
 */
public interface EmbeddedValueResolverAware extends Aware {

    /**
     * Set the StringValueResolver to use for resolving embedded definition values.
     */
    void setEmbeddedValueResolver(StringValueResolver resolver);

}

DestructionAwareBeanPostProcessor

Subinterface of {@link BeanPostProcessor} that adds a before-destruction callback.处理销毁前的回调,典型的用法是调用自定义回调在特定bean破坏类型,匹配相应的初始化回调。
这里的处理主要是处理当某个类销毁掉之后,处理当前类中的所有的@Scheduled 注解对应的所有的线程任务的关闭

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 处理回调的逻辑
     * Apply this BeanPostProcessor to the given bean instance before
     * its destruction. Can invoke custom destruction callbacks.
     * <p>Like DisposableBean's {@code destroy} and a custom destroy method,
     * this callback just applies to singleton beans in the factory (including
     * inner beans).
     * @param bean the bean instance to be destroyed
     * @param beanName the name of the bean
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.DisposableBean
     * @see org.springframework.beans.factory.support.AbstractBeanDefinition#setDestroyMethodName
     */
    void postProcessBeforeDestruction(Object bean, String beanName) 

    /**
     * 是否支持销毁回调
     * Determine whether the given bean instance requires destruction by this
     * post-processor.
     * <p><b>NOTE:</b> Even as a late addition, this method has been introduced on
     * {@code DestructionAwareBeanPostProcessor} itself instead of on a SmartDABPP
     * subinterface. This allows existing {@code DestructionAwareBeanPostProcessor}
     * implementations to easily provide {@code requiresDestruction} logic while
     * retaining compatibility with Spring <4.3, and it is also an easier onramp to
     * declaring {@code requiresDestruction} as a Java 8 default method in Spring 5.
     * <p>If an implementation of {@code DestructionAwareBeanPostProcessor} does
     * not provide a concrete implementation of this method, Spring's invocation
     * mechanism silently assumes a method returning {@code true} (the effective
     * default before 4.3, and the to-be-default in the Java 8 method in Spring 5).
     * @param bean the bean instance to check
     * @return {@code true} if {@link #postProcessBeforeDestruction} is supposed to
     * be called for this bean instance eventually, or {@code false} if not needed
     * @since 4.3
     */
    boolean requiresDestruction(Object bean);

}

ApplicationListener

spring启动事件监听,启动后通过TaskScheduler执行任务进行启动,将ScheduledTaskRegistrar配置的任务启动进行执行。

DisposableBean

当前Bean销毁的时候处理逻辑,关闭所有注解类中关联任务的线程。

MergedBeanDefinitionPostProcessor实现BeanPostProcessor

主要的处理逻辑,加载当前加载Bean中的@Scheduled注解,然后添加到配置类ScheduledTaskRegistrar中去处理,最后通过事件机制,启动所有的线程

Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException

ScheduledTask

ScheduledTask 是对于ScheduledFuture封装

/**
 * A representation of a scheduled task,
 * used as a return value for scheduling methods.
 *
 * @author Juergen Hoeller
 * @since 4.3
 * @see ScheduledTaskRegistrar#scheduleTriggerTask
 * @see ScheduledTaskRegistrar#scheduleFixedRateTask
 */
public final class ScheduledTask {

    volatile ScheduledFuture<?> future;


    ScheduledTask() {
    }


    /**
     * Trigger cancellation of this scheduled task.
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }

}


package java.util.concurrent;
/**
 * A delayed result-bearing action that can be cancelled.
 * Usually a scheduled future is the result of scheduling
 * a task with a {@link ScheduledExecutorService}.
 *
 * @since 1.5
 * @author Doug Lea
 * @param <V> The result type returned by this Future
 */
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}

断点跟踪

设置一个环境

这里写图片描述

ScheduledAnnotationBeanPostProcessor#postProcessAfterInitialization添加条件断点

拦截掉Work…Action中设置的定时任务,通过idea的条件拦截进行设置
这里写图片描述

查找@Scheduled注解

这里写图片描述

处理class bean方法上找到的@Scheduled进行注册Task

这里写图片描述

将方法上的任务注册到ScheduledTaskRegistrar

这里写图片描述
比如下面的这些方法

Set<ScheduledTask> tasks = new LinkedHashSet<ScheduledTask>(4);
tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));

管理当前Bean中所有注册了任务返回值ScheduledTask关联到当前Bean中

方便Bean销毁的时候,取消所有的任务的信息

    private final Map<Object, Set<ScheduledTask>> scheduledTasks =
            new IdentityHashMap<Object, Set<ScheduledTask>>(16);

这里写图片描述

ScheduledAnnotationBeanPostProcessor#onApplicationEvent(ContextRefreshedEvent event)

处理spring事件,spring启动完成后对于任务的初始化工作处理,以及配置ScheduledTaskRegistrar中执行器,在@EnableScheduling中可以通过动态配置实现了这个接口SchedulingConfigurer,调整ScheduledTaskRegistrar中的相关参数
这里写图片描述
通过当前方法启动ScheduledTaskRegistrar,由于当前已经配置了执行器,所以所有的任务都可以进行执行啦
这里写图片描述

ScheduledTaskRegistrar#afterPropertiesSet

将缓存的任务进行启动,如下为主要的数据结构
这里写图片描述

afterPropertiesSet方法

这里写图片描述
这里写图片描述

销毁

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u012881904/article/details/79996826