zl程序教程

您现在的位置是:首页 >  Python

当前栏目

Spring中的定时器都会了?

2023-02-26 10:20:50 时间

前言

  日常并不是需要所有的服务是都是立即需要返回给客户端的响应的,有一些任务是需要定时定点的去执行,这个时候我们想到的就是定时器的用处了,定时器的编写是很简单的。但是有的时候不了解其中的原理是很容易发生一些小问题(例如他们的线程池共用)。

解析过程

  本地准备了一个小demo。里面有个简单的定时器,要求是每一分钟执行一次。然后启动类上需要加上@EnableScheduling注解信息。

  1. 代码部分

    @Component public class TimeScheduled {     @Scheduled(cron = "* 0/1 * * * ?")     public void test(){         System.out.println("yyy");     } }
  2. 主要注意的是@EnableScheduling注解,里面引入了一个后处理器ScheduledAnnotationBeanPostProcessor。这里就是解析Bean将其任务封装。
    主要方法:

    (福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>

    public Object postProcessAfterInitialization(Object bean, String beanName) {     if (!(bean instanceof AopInfrastructureBean) && !(bean instanceof TaskScheduler) && !(bean instanceof ScheduledExecutorService)) { // 不属于组件bean方可进入         Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean); // 获取最终的bean(可能在此之前被代理了)         if (!this.nonAnnotatedClasses.contains(targetClass)) {         // 获取Scheduled方法集合             Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, (method) -> {                 Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);                 return !scheduledMethods.isEmpty() ? scheduledMethods : null;             });             if (annotatedMethods.isEmpty()) {                 this.nonAnnotatedClasses.add(targetClass);                 if (this.logger.isTraceEnabled()) {                     this.logger.trace("No @Scheduled annotations found on bean class: " + targetClass);                 }             } else {                 // 循环遍历解析表达式  并将定时任务注册到ScheduledTaskRegistrar中                 annotatedMethods.forEach((method, scheduledMethods) -> {                     scheduledMethods.forEach((scheduled) -> {                         this.processScheduled(scheduled, method, bean);                     });                 });                 if (this.logger.isTraceEnabled()) {                     this.logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods);                 }             }         }         return bean;     } else {         return bean;     }
  3. 解析之后会将对应的定时方法根据类型封装到org.springframework.scheduling.config.ScheduledTaskRegistrar中,里面有以下几类任务集合。

    private List<TriggerTask> triggerTasks; // 触发器任务  本次未使用 private List<CronTask> cronTasks; //  含有cron表达式的任务 private List<IntervalTask> fixedRateTasks; // 含有fixedRate的任务 private List<IntervalTask> fixedDelayTasks; // 含有fixedDelay的任务 private final Map<Task, ScheduledTask> unresolvedTasks = new HashMap(16); // 作为全集任务集合,添加完上面的任务之后会往这个集合中丢入 private final Set<ScheduledTask> scheduledTasks = new LinkedHashSet(16); // 执行之后的任务集合
  4. 将任务添加到集合中,那么什么时候会进行任务的执行呢?我们可以看到这个bean后处理器还实现了ApplicationListener接口。然后深入之后发现他调用了ScheduledTaskRegistrarafterPropertiesSet方法,该方法里面调用了对应的执行过程。

    Spring中的定时器都会了?

  5. 之后ScheduledExecutorService再根据org.springframework.scheduling.support.CronTrigger#nextExecutionTime计算出来的下次时间进行任务执行。
    Spring中的定时器都会了?

常见问题

  1. 多个任务定时器有交叉时间,却发现有些任务排队到时间未执行(采用默认线程池配置)

    这块问题跟着源码进去就能发现,在refresh阶段创建taskScheduler这个Bean的时候,org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler里面默认的线程数大小为1,一旦任务执行开始的时候,按照线程池执行过程,剩下的任务就会丢到队列中。

补充疑惑

看了看定时器里面的代码,可能认知不够深,对此还是有些疑问的。

  1. 这里不知道小伙伴有没有疑问(我是有点疑问的)?因为ScheduledTaskRegistrar类实现了InitializingBean接口,那为何不在容器执行该步骤的时候自动调用,还为何还利用上下文事件监听然后再进行方法调用?

    看到框架中该ScheduledTaskRegistrar类不是容器Bean,虽然实现了对应的接口,但是不在Spring启动解析中调用。如果你单独的将该类进行Bean化,那么此时的Bean是容器内部的,而不是与定时相关联的,那么执行的时候因为没有元素而不会进行执行。同时再解析InitializingBean以及执行里面的方法的时候,对应的Bean还未完成初始化操作(一个是finishBeanFactoryInitialization步骤执行,一个是在finishRefresh执行)。(个人观点其实可以直接去掉该InitializingBean实现,毕竟用不到,让该类看起来更专一点)

总结

这段时间看了许多源码,感慨下有些东西还是需要你下去看看的,下面的世界更精彩,或许你都能回答出面试官等等的问题,但是一旦追问,你是否知道底下怎么实现?为何这么设计? 让你设计是如何做? (条条大路通罗马,这是我目前的路~)

Spring中的定时器都会了?


本站部分内容转载自网络,版权属于原作者所有,如有异议请联系QQ153890879修改或删除,谢谢!
转载请注明原文链接:Spring中的定时器都会了?

你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:

1、点击这里立即申请成为腾讯云VIP客户

2、点击这里立即注册成为天翼云VIP客户

3、点击这里立即申请成为华为云VIP客户

4、点击这里立享阿里云产品终身VIP优惠价

喜欢 (0)
[[email protected]]
分享 (0)