博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring 定时器的使用---Xml、Annotation、自定义
阅读量:6577 次
发布时间:2019-06-24

本文共 8213 字,大约阅读时间需要 27 分钟。

日常系统开发中定时任务用的非常地普遍,比如我们可能想做个定时器去查询某笔交易的状态并进行汇总,又或者我们想在凌晨4点清楚数据库的相关数据、又或者我们想在每月月底0点定时去开启一个事务对当月、季度的数据做统计做成报表,灰常多呀!我也说不完啦!

有一点小编对于定时任务的理解,那就是:定时任务只是告诉系统在某个时刻执行某个任务,而至于该任务什么时候执行完成,这不是定时任务要关心的范围,定时任务只需要保证某个时刻发出调用某个任务的指令即可。

在Java领域定时任务实现的佼佼者就是quartz了,quartz框架在spring 3.0之前用的很广泛,当然现在也是,quartz支持数据持久化以及相应的集群方式部署,spring 3.0 之后的spring版本自己实现了一套定时任务框架,我们可以把看做是quartz的低配版本,它没有提供对集群的支持,不过其他功能已经灰常强大啦!

跟随spring传统,spring自己实现的定时任务框架spring-task同时支持xml和注解方式配置定时任务,当然小编还会讲解我们如何自定义定时任务。翻开spring源码包我们可以发现,其实spring除了自家的spring-task,同时还提供了quartz的集成,关于spring如何集成quartz,请阅读小编之前写的一篇文章

下面我将分别从xml、注解、自定义3个方面讲解如何使用spring-task.

一、基于xml配置实现spring定时任务

定时任务组件分为三个:调度器、任务以及执行时间点。我们需要引入beancontextcore三个spring包。

application.xml

复制代码

XmlTask.java

package wokao666.club.spring_task.tasks;import java.text.SimpleDateFormat;import wokao666.club.spring_task.util.DateFormatter;/** * 基于XML的spring定时任务 */public class XmlTask {    public void say() {        SimpleDateFormat format = DateFormatter.getDateFormatter();        System.err.println(format.format(System.currentTimeMillis()) + " I am spring xml-based task!");    }}复制代码

DateFormatter.java

package wokao666.club.spring_task.util;import java.text.SimpleDateFormat;/** * 日期格式 * @author hjw * */public class DateFormatter {    private static volatile SimpleDateFormat formater = null;    private DateFormatter() {}    public static SimpleDateFormat getDateFormatter() {        if(null == formater) {            synchronized (DateFormatter.class) {                if(null == formater) {                    formater = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");                }            }        }    return formater;    }}复制代码

App.java

package wokao666.club.spring_task;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Hello world! * */public class App {    private static ClassPathXmlApplicationContext ctx;    public static void main( String[] args ) {            ctx = new ClassPathXmlApplicationContext("applicationContext.xml");    }}复制代码

程序输出:

六月 10, 2018 10:47:11 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 22:47:11 CST 2018]; root of context hierarchy六月 10, 2018 10:47:11 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [applicationContext.xml]六月 10, 2018 10:47:12 下午 org.springframework.scheduling.concurrent.ExecutorConfigurationSupport initialize信息: Initializing ExecutorService  'schedualer'2018-06-10 10:47:14 I am spring xml-based task!2018-06-10 10:47:16 I am spring xml-based task!2018-06-10 10:47:18 I am spring xml-based task!复制代码

二、基于注解的spring-task

applicationContext.xml

复制代码

AnnotationTask.java

package wokao666.club.spring_task.tasks;import java.text.SimpleDateFormat;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Service;import wokao666.club.spring_task.util.DateFormatter;/** * 测试基于注解的定时任务 * @author hjw */@Servicepublic class AnnotationTask {    @Scheduled(cron="0/2 * * * * ?")    public void say() {        SimpleDateFormat format = DateFormatter.getDateFormatter();        System.err.println(format.format(System.currentTimeMillis()) + " good morning");    }}复制代码

App.javaDateFormatter.java和上面一样,程序输出如下:

六月 10, 2018 10:53:45 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 22:53:45 CST 2018]; root of context hierarchy六月 10, 2018 10:53:45 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [applicationContext.xml]六月 10, 2018 10:53:46 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition信息: Overriding bean definition for bean 'org.springframework.context.annotation.internalScheduledAnnotationProcessor' with a different definition: replacing [Generic bean: class [org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.scheduling.annotation.SchedulingConfiguration; factoryMethodName=scheduledAnnotationProcessor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/scheduling/annotation/SchedulingConfiguration.class]]六月 10, 2018 10:53:46 下午 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration信息: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing2018-06-10 10:53:48 good morning2018-06-10 10:53:50 good morning2018-06-10 10:53:52 good morning2018-06-10 10:53:54 good morning复制代码

注意到上面输出No TaskScheduler/ScheduledExecutorService bean found for scheduled processing这句话,因为你可以传入一个java.util.Executor线程池对象来实现对异步任务的调用,如果你指定了executor属性,则spring会默认创建一个SimpleAsyncTaskExecutor对象去执行,executor属性指定定时任务执行的线程池,强调执行,而scheduler属性表示任务调度的线程池,因为spring默认是单线程串行调度,如果想允许多线程并发调度,则需要配置scheduler属性,配置示例如下:

复制代码

(此处还需另行深入学习spring异步任务相关知识原理,异步执行使用@Async标注方法)

三、自定义定时任务

实现自定义定时任务,或者说我们可以更改相关的cron表达式,这看起来是很不可思议的,但确实可以做到,小编推荐一篇例文

CustomSchedual.java

package wokao666.club.spring_task.tasks;import org.springframework.scheduling.Trigger;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.config.ScheduledTaskRegistrar;import org.springframework.scheduling.support.CronTrigger;import org.springframework.stereotype.Component;import wokao666.club.spring_task.util.DateFormatter;/** * 演示自定义定时器 */@EnableScheduling@Componentpublic class CustomSchedual implements SchedulingConfigurer{        private static String cron = "0/2 * * * * ?";        private CustomSchedual() {        new Thread(()->{            try {                Thread.sleep(16000);            } catch (InterruptedException e) {}            cron = "0/10 * * * * ?";            System.err.println("change")        }).start();    }    public void configureTasks(ScheduledTaskRegistrar arg0) {        arg0.addTriggerTask(()->{            System.err.println(DateFormatter.getDateFormatter().format(System.currentTimeMillis()) + " good night!");        },(triggerContext)->{        CronTrigger trigger = new CronTrigger(cron);        return trigger.nextExecutionTime(triggerContext);        });    }}复制代码

程序输出如下,可以看到,程序过来16秒之后,执行频率从2秒/次变为10秒/次:

六月 10, 2018 11:49:13 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2328c243: startup date [Sun Jun 10 23:49:13 CST 2018]; root of context hierarchy六月 10, 2018 11:49:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [applicationContext.xml]六月 10, 2018 11:49:14 下午 org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration信息: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing2018-06-10 11:49:16 good night!2018-06-10 11:49:18 good night!2018-06-10 11:49:20 good night!2018-06-10 11:49:22 good night!2018-06-10 11:49:24 good night!2018-06-10 11:49:26 good night!2018-06-10 11:49:28 good night!2018-06-10 11:49:30 good night!change2018-06-10 11:49:32 good night!2018-06-10 11:49:40 good night!2018-06-10 11:49:50 good night!2018-06-10 11:50:00 good night!2018-06-10 11:50:10 good night!2018-06-10 11:50:20 good night!复制代码

最后,单纯会使用还不行,我们不仅要知其然,还要知其所以然,后期有时间多学学原理,其实底层无非就是java线程池的使用,加油,骚年们,晚安!

转载地址:http://gsfno.baihongyu.com/

你可能感兴趣的文章
Poj1837 Balance 动态规划-01背包
查看>>
芯片测试
查看>>
记录一次tomcat下项目没有加载成功
查看>>
在源代码中插入防止盗版代码片段的方式
查看>>
javascript/dom:对样式进行操作
查看>>
一张图,把我震惊了【转】
查看>>
hdu 3367 Pseudoforest(最大生成树)
查看>>
Spring mvc PostgreSQL 插入timestamp和int8
查看>>
一个人,一则故事,一份情愫,一个世界……
查看>>
ffserver联合ffmpeg建立媒体服务器
查看>>
NSubstitute完全手册(十三)抛出异常
查看>>
下载稻草人下来刷新+gallery
查看>>
构建Python+Selenium2自动化测试环境<一>
查看>>
轻量级前端MVVM框架avalon - 执行流程2
查看>>
删除浏览器浏览器删除cookie方法
查看>>
Unity 3D学习笔记(三)——关于脚本
查看>>
说借钱
查看>>
微软URLRewriter.dll的url重写的简单使用(实现伪静态)
查看>>
基于XMPP实现的Openfire的配置安装+Android客户端的实现
查看>>
提高编程技能最有效的方法(转载)
查看>>