2019独角兽企业重金招聘Python工程师标准>>> hot3.png

我们跑定时的时候,代码的结构大致是这个样子的。

@Scheduled(cron="0 0 4 * * ?")
public void taskCycle() {Calendar  cal  =  Calendar.getInstance();cal.add(Calendar.DATE, -1);yesterday = new SimpleDateFormat( "yyyyMMdd").format(cal.getTime());//默认5000int height = Integer.valueOf("5000");//主页heatMapDto = createZy("zhuye",height);createHotMap(heatMapDto);//我的账户heatMapDto = createZy("myacount",height);createHotMap(heatMapDto);LOGGER.info("今执行了热力图定时任务" + yesterday);
}

那么,这个Scheduled(cron="0 0 4 * * ?")是如何被系统识别并且去跑定时任务呢?@Scheduled的解析器是ScheduledAnnotationBeanPostProcessor 该类实现了类BeanPostProcessor,这样在容器启动的时候会在refresh()的时候调用到所有实现了BeanPostProcessor接口的类。如下:

AbstractBeanFactory (方法:createBean(beanName, mbd, args))--->AbstractAutowireCapableBeanFactory
(方法:createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)) ---》AbstractAutowireCapableBeanFactory  (方法:protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd))--》

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {//执行BeanPostProcessor的applyBeanPostProcessorsBeforeInstantiation接口bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);if (bean != null) {//执行BeanPostProcessor的applyBeanPostProcessorsBeforeInstantiation接口bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}mbd.beforeInstantiationResolved = (bean != null);}return bean;
}
---》AbstractAutowireCapableBeanFactory
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {//bean会走下每一个配置到系统中实现了接口BeanPostProcessor的类的postProcessAfterIn//itialization方法result = beanProcessor.postProcessAfterInitialization(result, beanName);if (result == null) {return result;}}return result;
}

到此我们知道了接口实现类的实现时机。那么@Scheduled的解析器是ScheduledAnnotationBeanPostProcessor在执行的时候又做了什么呢?让我们来看看ScheduledAnnotationBeanPostProcessor的postProcessAfterInitialization方法是实现了什么。

public Object postProcessAfterInitialization(final Object bean, String beanName) {
//获取目标类final Class<?> targetClass = AopUtils.getTargetClass(bean);//利用类反射为目标类方法做回调函数ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {//首先判断是否有@Scheduled标签Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class);//如果有标签if (annotation != null) {try {//判断返回类型是否为空  (Scheduled表示不允许有返回值)Assert.isTrue(void.class.equals(method.getReturnType()),"Only void-returning methods may be annotated with @Scheduled");//Scheduled方法不允许有参数Assert.isTrue(method.getParameterTypes().length == 0,"Only no-arg methods may be annotated with @Scheduled");//判断目标类是否是jdk代理类if (AopUtils.isJdkDynamicProxy(bean)) {try {// found a @Scheduled method on the target class for this JDK proxy -> is it// also present on the proxy itself?method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());}catch (SecurityException ex) {ReflectionUtils.handleReflectionException(ex);}catch (NoSuchMethodException ex) {throw new IllegalStateException(String.format("@Scheduled method '%s' found on bean target class '%s', " +"but not found in any interface(s) for bean JDK proxy. Either " +"pull the method up to an interface or switch to subclass (CGLIB) " +"proxies by setting proxy-target-class/proxyTargetClass " +"attribute to 'true'", method.getName(), targetClass.getSimpleName()));}}//生成一个定时器任务Runnable runnable = new ScheduledMethodRunnable(bean, method);boolean processedSchedule = false;String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";// Determine initial delay//首先实例化一个定时器延时时间 initialDelay =-1long initialDelay = annotation.initialDelay();//initialDelayString =""String initialDelayString = annotation.initialDelayString();if (!"".equals(initialDelayString)) {Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");if (embeddedValueResolver != null) {initialDelayString = embeddedValueResolver.resolveStringValue(initialDelayString);}try {initialDelay = Integer.parseInt(initialDelayString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into integer");}}//获取cron表达式0 * * * * *String cron = annotation.cron();//检查cron表达式非空if (!"".equals(cron)) {Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");processedSchedule = true;if (embeddedValueResolver != null) {//解析cron表达式cron = embeddedValueResolver.resolveStringValue(cron);}//注册定时任务registrar.addCronTask(new CronTask(runnable, cron));}// At this point we don't need to differentiate between initial delay set or not anymoreif (initialDelay < 0) {initialDelay = 0;}// Check fixed delay fixedDelay =-1long fixedDelay = annotation.fixedDelay();if (fixedDelay >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));}String fixedDelayString = annotation.fixedDelayString();if (!"".equals(fixedDelayString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;if (embeddedValueResolver != null) {fixedDelayString = embeddedValueResolver.resolveStringValue(fixedDelayString);}try {fixedDelay = Integer.parseInt(fixedDelayString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into integer");}registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));}// Check fixed ratelong fixedRate = annotation.fixedRate();if (fixedRate >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));}String fixedRateString = annotation.fixedRateString();if (!"".equals(fixedRateString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;if (embeddedValueResolver != null) {fixedRateString = embeddedValueResolver.resolveStringValue(fixedRateString);}try {fixedRate = Integer.parseInt(fixedRateString);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into integer");}registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));}// Check whether we had any attribute setAssert.isTrue(processedSchedule, errorMessage);}catch (IllegalArgumentException ex) {throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage());}}}});return bean;
}

到此我们把定时任务注册到了定时列表中了。那么定时列表是如何启动的呢?

ScheduledTaskRegistrar类实现了InitializingBean接口,在容器启动的时候实现了该方法

public void afterPropertiesSet() {
//定时任务启动   scheduleTasks();
}

定时任务都放到了List<ScheduledFuture>.该接口扩展了延时队列接口Delayed和异步接口Future。我们看一个ScheduledFuture的实现类。周期性的队列其实就是在再延时队列基础上的。我们知道延时队列能够实现在任务执行时间到了的时候去执行一次任务。而周期性队列的任务就是将延时队列的务执行之后把它按照周期时间继续放入到延时队列中,等待下一个执行时间到了继续该循环操作。

转载于:https://my.oschina.net/zjItLife/blog/533088

注解 @Scheduled相关推荐

  1. Spring定时任务注解@Scheduled+@EnableAsync用法详解(简单说明+应用场景+demo源代码+执行过程分析)

    @Scheduled 由Spring定义,用于将方法设置为调度任务,可实现方法的周期或定时执行.想单独使用Scheduling,需引入spring-context这个依赖.spring-boot-st ...

  2. Java定时注解@Scheduled的使用,fixedDelay,fixedRate,cron的使用

    Java定时注解@Scheduled的使用,fixedDelay,fixedRate,cron的使用 问题背景 参数简介 项目创建 测试结果 心得 Lyric:咸咸的汗水 问题背景 项目中经常使用定时 ...

  3. spring注解 @Scheduled(cron = 0 0 1 * * *)的使用来实现定时的执行任务

    <span style="font-size:14px;">初次接触定时类的小程序,还是走了很多的弯路,如今终于搞定了,总结如下:</span> <s ...

  4. spring使用注解@Scheduled执行定时任务

    =最近做的项目中遇到了用spring中@Schedule注解执行定时任务的功能,这里简单记录一下. 首先在applicationContext.xml中进行配置: xmlns 加下面的内容 xsi:s ...

  5. java 注解scheduler_JAVA注解@Scheduled 不执行

    spring boot项目需要在启动类加上注解 @EnableScheduling 定义一个接口 StockTask.java 1 public interfaceStockTask {2 publi ...

  6. 注解 @Scheduled配置参数详解,定时任务使用

    @Scheduled注解的使用这里不详细说明,直接对8个参数进行讲解. 参数详解 1.cron 该参数接收一个cron表达式,cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个域,每 ...

  7. Spring : @EnableScheduling注解 @Scheduled

    文章目录 1.美图 2.概述 3.案例 4.@Scheduled 5.源码 6.抽取代码 1.美图 2.概述 @EnableScheduling注释,它可以初始化一个调度器. 3.案例 Spring ...

  8. SpringBoot定时任务注解@Scheduled中fixedRate和fixedDelay

    @Scheduled(fixedRate = 2000)public void myJob1(){System.out.println(LocalDateTime.now()+"定时任务O( ...

  9. @scheduled 执行一次_springboot 定时任务Scheduled(注解方式实现)参数 说明

    spring boot 实现定时任务首先需要在配置类注解 @enablescheduling 来开启定时任务的支持,然后在要执行定时任务的方法上注解 @scheduled ,声明这是一个定时任务 实现 ...

最新文章

  1. 职场笔记[0702]:用户体验和创业
  2. Evince中文乱码
  3. OpenCV实现幻灯片模糊slides blur的实例(附完整代码)
  4. c语言怎么输出线性表里元素,C语言的世界-线性表
  5. Spring学习(一)初识Spring
  6. 一步步编写操作系统 43 汇编语言和c语言的理解
  7. Mysql for Linux安装配置之——二进制安装
  8. 华为荣耀20s云服务_华为荣耀20和20s的区别
  9. PHPCMS之 列表和内容页
  10. mysql 5.6 emoji_让MySQL 5.6支持Emoji表情
  11. 软件测试岗位工作,到底可以做多久?
  12. paip.软件版本完善计划VC423
  13. nvidia控制面板只有3d设置?
  14. 数据挖掘-目录-impurity
  15. 小程序:canvas绘制网络图片
  16. [ArcGIS] 空间分析(三)栅格数据
  17. ssh: Could not resolve hostname f: Name or service not known的解决
  18. ICCV2021 | 医学影像等小数据集的非自然图像领域能否用transformer?
  19. 使用Mysql Navcat导出查询数据excel时出现数据丢失
  20. JavaScript面向对象

热门文章

  1. 2019全新学习路线图发布
  2. 在Linux上安装Python 3
  3. C#最受欢迎功能 -- C#1至C#7
  4. ASP.NET MVC 5 入门指南汇总
  5. HBase HFile与Prefix Compression内部实现全解–KeyValue格式
  6. 用Memcache守护程序把数据缓存到内存二
  7. 学网络好帮手:路由器模拟软件RouteSim3.31
  8. 笔试总结2(整理 觉得比较好的)
  9. Django 框架入门篇(安装与创建项目)
  10. Collection接口的常用方法