精华内容
下载资源
问答
  • Java定时器——springboot定时器篇 文章目录Java定时器——springboot定时器篇前言一、Java定时器是什么?二、路径1.体验2.编写启动类,添加定时器注解3....示例:java定时器就是用于在规定时间触发指定效果的功能。

    Java定时器——springboot定时器篇



    前言

    大家好我是程序员阿毛,今天给大家带来的是Java定时器的使用,文章内容简洁明了,通俗易懂,适用于新手入门。本文如有出处还望各位看官指点,谢谢大家。


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、Java定时器是什么?

    示例:java定时器就是用于在规定时间触发指定效果的功能。

    二、路径

    • 将采用Spring boot提供的定时器完成Schedule
    • 前提:可以作为web服务器启动即可

    1.体验

    • 添加web坐标

    坐标:

        <dependencies>
            <!--web起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    

    2.编写启动类,添加定时器注解

    代码如下(示例):

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    /**
     * @author 阿毛
     */
    @SpringBootApplication
    @EnableScheduling       //开启定时器
    public class TestScheduleApplication {
        public static void main(String[] args) {
            SpringApplication.run(TestScheduleApplication.class,args);
        }
    }
    
    

    3.编写处理类

    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    /**
     * @author 阿毛
     */
    @Component
    public class TestSchedule {
        /**
         * 每3秒执行一次
         */
        @Scheduled(cron = "0/3 * * * * ?")
        public void handler() {
            System.out.println(System.currentTimeMillis());
        }
    }
    

    cron表达式

    • cron语法:由7部分组成,第七部分为年,一般不写
    秒 分 时 日 月 周 (年)
    
    • 第四位和第六位,至少有一个
    • cron组成取值
      cron组成取值
    • 常见cron表达式
    "30 * * * * ?" 每半分钟触发任务
    "30 10 * * * ?" 每小时的10分30秒触发任务
    "30 10 1 * * ?" 每天1点10分30秒触发任务
    "30 10 1 20 * ?" 每月20号1点10分30秒触发任务
    "30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务
    "30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务
    "30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务
    "30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务
    "15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务
    "15-45 * * * * ?" 15到45秒内,每秒都触发任务
    "15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次
    "15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
    "0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次
    "0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务
    "0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务
    "0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务
    "0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务
    "0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务
    

    特殊字符解释:

    ,		或
    ——		区间
    *		任意
    ?		忽略
    /		每
    其他特殊字符不常使用,这里就不解释,如有需要可百度查询
    

    总结

    提示:这里对文章进行总结:
    例如:

    • 添加web坐标
    • 编写启动类,添加定时器注解
    • 编写处理类
    • cron表达式使用及语法

    结语

    以上就是文章的全部内容,感谢各位看官的浏览,本文如有出处,还望各位看官指点。
    ——程序员阿毛

    展开全文
  • Java定时器

    2017-09-08 00:13:16
    这是在开发环境为JDK1.7的Java定时器,使用了Timer与TimerTask来开发的定时器,Timer作为定时器,而TimerTask作为任务执行者,使用了Java反射来实现使用定时器每隔一段时间执行某一特定的操作

    定时器

    开发环境:JDK1.7

    需求

    1)每隔一段时间来完成某一特定的事

    2)参数:(未定类型 时间,String 方法名,Map 参数)

    思考:没有执行类,那么如何执行操作呢,只传个方法名和参数有卵用

    需求改动

    2)–>2.1)增加字节码参数 Class 操作类

    再次思考:用Map来装载参数合适吗?我可以通过反射来获取形参的名字吗?

    百度中…

    1.http://www.cnblogs.com/guangshan/p/4660564.html

    该方法工作量太大了,所以拒绝使用,但有空来学习一下也不错

    继续百度中…

    2.http://blog.csdn.net/revitalizing/article/details/71036970

    天啊!是JDK8的…无奈…

    继续百度中…

    3.好吧,事实证明只通过JDK1.7的API是获取不了参数名的,所以不使用Map来存储参数了,改为数组来存储参数吧..那么要求传过来的参数的顺序与方法定义的顺序相同就行了…

    此时的参数为:

    (未定类型 时间,Class 操作类, String 方法名,Object[] 参数)

    定时器怎么定义

    查看一下现存代码的定时器是怎么搞的

    //0.定义一个执行操作的任务器
    class MyTask extends TimerTask {
        @Override
        public void run() {//任务操作}
    }
    
    //1.先搞一个定时器
    Timer timer = new Timer();
    
    //2.调用,开始计时调用吧
        //第一个参数,执行操作的类TimerTask
        //第二个参数,延迟时间,单位毫秒
        //第三个参数,执行时间间隔,单位毫秒
    //该方法有有多个重载方法,详情参考API
    timer.schedule(new MyTask(), 0, 1000);
    

    问题又来了,参数怎么传进任务器里?

    1)在TimerTask定义一个public方法,然后再run方法里调用public方法

    2)通过回调机制来实现参数的传递,Thank GOD!听上去非常高大上!

    实现细节是这样的:自己百度去:)

    不用该方法,有简单的不用,干嘛呢

    如果使用回调机制我还需要写个接口,通过接口里方法所返回的值来获取数据,这么的方式明显不是一个好方法,所以就不用了

    问题又来了,该在哪里启动定时器的schedule方法呢 ?

    1)单独建立一个类来作为工具类,里面的public方法可以让使用者来调用来启动任务,当然,需要传参进来,我再把参数传到TimerTask

    2)在TimerTask的public方法启动,把所存参数存到属性里,在run方法里实现操作,而不再run里调用public方法里,或者再写一个private方法,在private方法里实现操作,再在run方法里调用private方法.

    由于我的定时器的操作是单一的,所以就不用再创建一个private方法来封装操作代码了.

    暂时定时器工具类的框架就这么定了

    demo

    public class MyTimerUtil extends TimerTask {
    
        @Override
        public void run() {
            System.out.println("hello timer!");
        }
    
        public <T> Object invokeTimer(long millisecond, Class<T> clazz, String mehtodName, Object... params) {
    
            Timer timer = new Timer();
            timer.schedule(this, 0, millisecond);
            return null;
        }
    
        public static void main(String[] args) {
            MyTimerUtil myTimerUtil = new MyTimerUtil();
            Object myResult = myTimerUtil.invokeTimer(1000L, null, null);
            System.out.println(myResult);
        }
    
    }
    

    总体框架demo

    public class MyTimerUtil extends TimerTask {
    
        private Method method;
        private Object[] params;
        private Object instance;
    
        @Override
        public void run() {
    
            try {
                method.invoke(instance, params);
                System.out.println("hello method");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public <T> void invokeTimer(long millisecond, Class<T> clazz, String mehtodName, Object... params) throws Exception {
    
            method = clazz.getMethod(mehtodName);
            this.params = params;
            instance = clazz.newInstance();
            Timer timer = new Timer();
            timer.schedule(this, 0, millisecond);
        }
    
        public static void main(String[] args) throws Exception {
    
            MyTimerUtil myTimerUtil = new MyTimerUtil();
            myTimerUtil.invokeTimer(1000L, MyTimerUtil.class, "testMethod");
    
        }
    
        public void testMethod() {
            System.out.println("in testMethod");
        }
    
    }
    

    还有什么更好地办法实现定时器呢?

    百度中…

    http://blog.csdn.net/haorengoodman/article/details/23281343/

    使用ScheduledExecutorService方法,接下来会在下面写个demo

    使用这个的优势是:(这是从上面的连接copy下来的)

    • ScheduledExecutorService是从Java SE5的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式。

    • 相比于上两个方法,它有以下好处:

    • 1>相比于Timer的单线程,它是通过线程池的方式来执行任务的

    • 2>可以很灵活的去设定第一次执行任务delay时间
    • 3>提供了良好的约定,以便设定执行的时间间隔

    demo

    public class MyScheduledExecutorUtil implements Runnable{
        private Method method;
        private Object[] params;
        private Object instance;
    
        public <T> void invokeTimer(int second, Class<T> clazz, String mehtodName, Object... params) throws Exception {
    
            method = clazz.getMethod(mehtodName);
            this.params = params;
            instance = clazz.newInstance();
            ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);//线程池的大小,允许的最大线程数
            scheduledExecutorService.scheduleAtFixedRate(this, 0, second, TimeUnit.SECONDS);
        }
    
        @Override
        public void run() {
            try {
                method.invoke(instance, params);
                System.out.println("hello method");
            } catch (Exception e) {
                e.printStackTrace();
            }   
        }
    
        public void testMethod() {
            System.out.println("in testMethod");
        }
    
        public static void main(String[] args) throws Exception {
    
            MyScheduledExecutorUtil myTimerUtil = new MyScheduledExecutorUtil();
            myTimerUtil.invokeTimer(1, MyTimerUtil.class, "testMethod");
    
        }
    }
    

    再次提醒

    本项目使用目录的"总体框架demo"作为工具类模板开发,以下简称该工具类模板为"工具类"
    

    怎么停止定时器?

    Timer有个cancel方法,可以停止定时器
    
    TimerTask也有个cancel方法,可以取消该TimerTask任务,
    我们不是timer.schedule(TimerTask, delay, period);定时执行TimerTask任务的吗?
    
    他们的区别是Timer的cancel是把整个定时器都退出了,而TimerTask的是把任务停止了,但定时器还在工作,尽管定时器里已经没有任务了,定时器还是在监听着,耗费着资源
    
    我们的需求就是要停止定时器,所以调用Timer的cancel.
    

    把Timer定义为静态属性

    原因:
        1)Timer为静态属性,可以被所有"工具类实例"共享
        2)每一个实例实质是一个TimerTask,每次创建工具类实例并执行invokeTimer方法,相当于使用同一个Timer开启一个线程来运行TimerTask任务,每运行一个TimerTask去创建一个Timer实例就太浪费资源了
        3)若想停止各自的TimerTask,则可以调用工具类的cancel方法,而不影响其他任务
        4)若想关闭Timer,则可以使用Timer的cancel方法,当然,该方法封装在工具类且声明为public以供调用
        *5)说了这么多废话,现在才是真正目的:方便关闭Timer
    
        若Timer不声明为静态,那么我想关闭Timer的时候,我先要找出工具类的实列,再通过工具类的实例的已封装的关闭方法去关闭.
    
        问题来了,我作为一个工具类去供人使用,我哪知道他人在哪创建了实例,若我想在非创建实例的类里去关闭Timer,它都不是在我这个类里创建的,那我如何获取该实例呢去关闭Timer呢?
    
        若Timer声明为静态属性那么就好办了,直接"类名.关闭方法",哈哈哈,就关闭了,多么的方便..
    
        若真的只想关闭使用者自己的任务而不影响其他人的任务,那就简单了,"实例.cancel()"就可以来,我都说了,我们的工具类实质是一个TimerTask,其本来就有一个取消任务所用的方法cancel,至于如何在非创建实例的类获取实例的问题,我可就不管了,最起码解决了关闭Timer的问题
    

    问题又来了,反射获取方法需要参数类型

    解决有两种方法:

    1. 通过调用者传进的参数获取其Class字节码,但是如果其传进的为基本类型那么就崩了,因为通过Object[]来获取参数时,会自动打包,如int会打包为Integer,此时类型不匹配,找不到方法,(PS:我测试过许多遍了)所以就不用该方法了
    2. 就让调用者传递那参数类型的字节码过来,想用就要按照规定的来.

    发现东西了,可变参数

    可变参数若只传null,则会为null

    public static void main(String[] args) throws Exception {       
        test(null);
    }
    
    private static void test(Object... a) {
        System.out.println(a);
    }   
    
    输出:null
    

    传多个null.则会不为null

    public static void main(String[] args) throws Exception {
        test(null,null);
    }
    
    private static void test(Object... a) {
        System.out.println(a+" length="+a.length+" a[1]="+a[1]);
    }   
    输出:[Ljava.lang.Object;@45486b51 length=2 a[1]=null
    

    不传时,不为null,其数组大小为0

    public static void main(String[] args) throws Exception {           
        test();
    }
    
    private static void test(Object... a) {
        System.out.println(a+" length="+a.length);
    }
    输出:[Ljava.lang.Object;@2a97cec length=0
    

    又发现问题了,new Timer()后就会开始监听

    那么静态变量何时加载:百度有个说法:

    在第一次创建一个类的对象或者第一次调用一个类的静态属性和方法的时候,会发生类加载

    类加载期间,如果发现有静态属性,就给对应的静态属性分配内存空间,并赋值

    问题在现,Timer的cancel()问题

    Timer执行cancel()方法后Timer不会置为null,但是该对象已经不能再用了

    那么如何判断Timer是否被cancel了?

    1)cancel后将Timer置为空

    2)Timer cancel后再去cancel会抛异常,可以通过捕获异常来判断是否已经被cancel了

    解决cancel问题和静态Timer加载后监听问题

    1)在封装的cancel方法将Timer置为空

    public void cancelTimer() {
        if(timer!=null) {
            timer.cancel();
            timer = null;
        }
    }
    

    2)在构造方法里new Timer(),避免任何第一次加载工具类时都触发new Timer 从而监听,浪费资源

    public TimerUtils() {
        if(timer == null) {
            timer = new Timer();
        }
    }
    

    最终的结果如下

    import java.lang.reflect.Method;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.TimeUnit;
    
    
    /**
     * 1.定时器工具类,定时器Timer为static,所有实列共享<br>
     * 2.该工具类提供了cancelTimer()方法,以终止定时器的运行<br>
     * 3.该工具类本身继承了TimerTask类,故若想终止某一实例所开启的任务,可以直接调用继承方法cancel(),只终止任务,不终止定时器
     */
    public class TimerUtils extends TimerTask {
    
        private Method method;
        private Object[] params;
        private Object instance;
        private static Timer timer;//全部实例共享的定时器
    
        /**
         * Timer在构造方法里实例化
         */
        public TimerUtils() {
            if(timer == null) {
                timer = new Timer();
            }
        }
    
        @Override
        public void run() {
    
            try {
                method.invoke(instance, params);
            } catch (Exception e) {
                e.printStackTrace();
                this.cancel();//调用方法失败,取消该任务,但不终止Timer,Timer可能存在有其他任务
            }
        }
    
        /**
         * 反射获取方法
         * @param clazz 被调用方法的类的字节码,用来获取Method实例
         * @param mehtodName 方法名
         * @param paramTypes 参数类型,注意:基本类型与其包装类是有区别的,如:int与Integer
         * @param params 参数
         * @throws NoSuchMethodException
         * @throws InstantiationException
         * @throws IllegalAccessException
         */
        private void initMehtod(Class<?> clazz, String mehtodName, Class<?>[] paramTypes,
                Object... params) throws Exception {
    
            if(!isAccessableMehtod(clazz, mehtodName, paramTypes, params)) {
                throw new Exception("所传参数不符合反射获取方法或者调用方法的最低条件");
            }
            try {   
                method = clazz.getMethod(mehtodName, paramTypes); 
            } catch (NoSuchMethodException e) {
                method = clazz.getDeclaredMethod(mehtodName, paramTypes);
                method.setAccessible(true); //获取方法的访问权限
            }
            this.params = params;
            instance = clazz.newInstance();
    
        }
    
        /**
         * 判断参数是否满足反射获取方法或者调用方法的最低条件
         * @param clazz 被调用方法的类的字节码,用来获取Method实例
         * @param mehtodName 方法名
         * @param paramTypes 参数类型,注意:基本类型与其包装类是有区别的,如:int与Integer
         * @param params 参数
         * @return
         */
        private boolean isAccessableMehtod(Class<?> clazz, String mehtodName, Class<?>[] paramTypes, Object... params) {
            paramTypes = paramTypes==null || paramTypes.length==0 ? null : paramTypes;
            params = params==null || params.length==0 ? null : params;
            if(clazz==null || StringUtil.isEmpty(mehtodName))
                return false;
            if(paramTypes==params || (paramTypes!=null && params!=null && (paramTypes.length == params.length)))
                return true;
            return false;
        }
    
        /**
         * @param millisDelay 首次执行的延迟时间,单位:毫秒
         * @param millisPeriod 周期,上一次与下一次执行的时间间隔,单位:毫秒
         * @param clazz 执行操作的类的字节码
         * @param mehtodName 执行操作的方法名
         * @param paramTypes 参数类型,注意:基本类型与其包装类是有区别的,如:int与Integer
         * @param params 参数
         * @throws Exception
         */
        public void invokeTimer(long millisDelay, long millisPeriod, Class<?> clazz, String mehtodName, Class<?>[] paramTypes, Object... params) throws Exception {
            initMehtod(clazz, mehtodName, paramTypes, params);
            timer.schedule(this, millisDelay, millisPeriod);
        }
    
        /**
         * @param firstTime 首次执行的时间,若时间已过则立即执行
         * @param millisPeriod 周期,上一次与下一次执行的时间间隔,单位:毫秒
         * @param clazz 执行操作的类的字节码
         * @param mehtodName 执行操作的方法名
         * @param paramTypes 参数类型,注意:基本类型与其包装类是有区别的,如:int与Integer
         * @param params 参数
         * @throws Exception
         */
        public void invokeTimer(Date firstTime, long millisPeriod, Class<?> clazz, String mehtodName, Class<?>[] paramTypes, Object... params) throws Exception {
            initMehtod(clazz, mehtodName, paramTypes, params);
            timer.schedule(this, firstTime, millisPeriod);
        }
    
        /**
         * 终止定时器
         */
        public static void cancelTimer() {
            if(timer!=null) {
                timer.cancel();
                timer = null;
            }
        }
    
    }
    
    展开全文
  • 当前java程序中能够实现定时的主要有三种方式,分别是:java定时器,spring定时器,quartz定时器。 下面依次讲讲他们的应用! java定时器的应用 其实java很早就有解决定时器任务的方法了,java提供了类java.util....

    当前java程序中能够实现定时的主要有三种方式,分别是:java定时器,spring定时器,quartz定时器。

       下面依次讲讲他们的应用!

    java定时器的应用
       其实java很早就有解决定时器任务的方法了,java提供了类java.util.TimerTask类基于线程的方式来实现定时任务的操作,然后再提供java.util.Timer类来注册调用,先创建一个类 RingTask 继承 java.util.TimerTask,实现run方法,相关代码如下:

    package timer;
     
    import java.util.TimerTask;
     
    /**
      * 这是一个打铃的程序,必须隔一段时间打一次
      */
    public class RingTask extends TimerTask{
     
        public RingTask() {
            // TODO Auto-generated constructor stub
        }
     
        public RingTask(int s,int d) {
            // TODO Auto-generated constructor stub
            this.second = s;
            this.delay  = d;
        }
     
        int second = 1;
     
        int delay  = 1;
     
        public void setSecond(int second) {
            this.second = second;
        }
     
        public void setDelay(int delay) {
            this.delay = delay;
        }
     
        @Override
     
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("我是打铃程序!"+"我第一次打铃延迟了"+delay+"秒!");
            System.out.println("打铃了!每过"+second+"秒一次");
        }
     
    }
     
    //定义好后,下面需要注册调用了,注册调用的方法如下:
    public static void main(String[] args) {
        //以 java定时器的模式调用
        Timer timer = new Timer();
        timer.schedule(
                new RingTask(3,3),  //需要注册的定时类
                3000,             //最开始先延迟3秒的时间
                3000);            //每隔3秒的时间调用一次
    }


       一个简单的java定时器就写好了,方便而简介,但是有不好的缺点: 如果需要实现每天早晨7点钟的定时执行一次,且周末的时候早晨7点钟不需要提醒,那这个可就不够用了,并且如果需要服务器一开启就触发这个定时器,则这种注册调用的方法也是不行的。

    Spring定时器的应用
       spring定时器是在spring框架中应用较成熟的一种方式,spring将定时任务的调用部分提到了配置文件当中,使定时器的触发条件变得更加灵活,spring定时器的实现,仍然需要 继承 java.util.TimerTask,实现run方法 ,示例类上面已给出,调用的配置如下: 

    <!-- 定时器的配置 (spring定时器)-->
    <!-- 要调度的bean配置 -->
    <bean id="ringTask" class="timer.RingTask">
        <!-- 给 属性 second 赋值 为 3 -->    
        <property name="second" >    
            <value>3</value>        
        </property>
        <!-- 给 属性 delay 赋值 为 3 -->
        <property name="delay" >
            <value>3</value>    
        </property>
    </bean>
    <!--配置一个触发器 配置触发器的参数-->
    <bean id="scheduleRingTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
        <property name="delay" value="3000"></property>           <!--第一次延迟3秒的时间-->
        <property name="period" value="3000"></property>          <!--每隔3秒的时间执行一次-->
        <property name="timerTask" ref="ringTask"></property>   <!--制定触发的类-->
    </bean>
    <!-- 总调度,用于启动定时器 -->
    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
        <property name="scheduledTimerTasks">
            <list>    
                <ref bean="scheduleRingTask"/>    
            </list>
        </property>
    </bean>


       在调用方面是不是灵活些了,且能够实现服务器已启动,就将定时器的执行纳入的被监控的范围,符合条件马上触发执行。但是还是存在缺点: 对于指定了具体的年月日时分秒而执行的任务还是不能解决。

    Quartz定时器
      Quartz是基于Spring框架之上的更加强大的定时器,它不仅可以轻松的实现前面两种定时器的功能,还实现了非常繁复的时间触发执行的任务,Quartz有两种方式来调度定时任务,一是使用Spring提供的 MethodInvokingJobDetailFactoryBean 代理类,Quartz通过该代理类直接调度任务类的某个函数;二是任务类继承QuartzJobBean类或者实现org.quartz.Job接口,Quartz通过该父类或者接口进行调度。

       先来看看实现前面个两种定时器的功能,现在先来举个例子,比如烧水,每1小时烧开一次,进行定时提醒,然后重新换水,再烧。

       具体的烧水定时类代码如下:

    package timer;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.scheduling.quartz.QuartzJobBean;
     
    /**
     * 这是一个热水的程序,必要要经过一段时间烧热了,才提醒重新换水
     * 这个类不管是继承 QuartzJobBean还是实现org.quartz.Job都行
     */
    public class HotWaterTask extends QuartzJobBean /*implements Job*/{
        // public void execute(JobExecutionContext arg0) 
        // throws JobExecutionException {
            // // TODO Auto-generated method stub
            // System.out.println("我是热水程序,我第一烧水需要1小时");
            // System.out.println("水现在烧开了,要及时换水哦!");
        // }
        
        @Override
        protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
            // TODO Auto-generated method stub
            System.out.println("我是热水程序, 我第一烧水需要1小时 ");
            System.out.println("水现在烧开了,要及时换水哦!");
        }
    }
    类定义好了,下面需要配置进去,配置的代码如下:
    
    <!-- 配置需要调度的任务类 -->
    <bean id="hotWaterTask" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="timer.HotWaterTask"></property>
    </bean>
    <!-- 配置一个触发器 -->
    <bean id="hotWaterTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail" ref="hotWaterTask"></property>
        <property name="startDelay" value="3600000"></property>
        <property name="repeatInterval" value=" 3600000"></property>
    </bean>
    <!-- 总调度,用于启动定时器 -->
    <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers" >
            <list>
                <ref bean="hotWaterTrigger"/>
            </list>
        </property>
    </bean>
      看到了吗,在这里我们并没有直接声明一个 HotWaterTask  Bean,而是声明了一个JobDetailBean。这个是Quartz的特点。JobDetailBean是Quartz的org.quartz.JobDetail的子类,它要求通过jobClass属性来设置一个Job对象。
    
      好了,上面的任务已经实现了,下面看看 如何实现 具体的年月日时分秒执行的代码
    
    Quartz在指定的时间执行 (很强大的代理定时执行机制)
    
      (1) 定义上班闹钟定时类代码如下: 
    
    package timer;
     
    /**
     * 开始上班,这个程序要求每天(非周末)早晨八点需要启动一次
     */
    public class StartWorkJob {
        public void startWork(){
            System.out.println("我是上班程序,每天(非周末)早晨八点需要启动一次");
            System.out.println("上班了!~")
        }
    }
      看到了吗,这个类StartWorkJob 并没有继承任何类也没有实现任何接口,且方法 startWork也是自己定义的,原有的业务代码不需要做任何更改。下面就要提到Quartz实现的一种机制,通过Spring提供的代理类(MethodInvokingJobDetailFactoryBean)来实现定时任务,这个类只需要提供它要代理的类以及要代理的方法,就能够很好的就行定时监控了,强大吧,相关的代码如下:
    
    <!-- 配置需要定时的bean类 -->
    <bean id="startWorkJob" class="timer.StartWorkJob"></bean>
    <!-- 配置任务的具体类和方法 -->
    <bean id="startWorkTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 要调用的bean -->
        <property name="targetObject" ref="startWorkJob"></property> 
        <!-- 要调用的Method -->
        <property name="targetMethod" value="startWork"></property>
        <!-- 是否并发,false表示 如果发生错误也不影响下一次的调用 -->
        <property name="concurrent" value="false"></property>
    </bean>
    <!-- 配置一个触发器 -->
    <bean id="startWorkTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="startWorkTask"></property>
        <property name="cronExpression" value="0 * 13 * * ?"></property> <!--每天的下午1点的每分钟的0秒都执行一次-->
    </bean>
     
    <!-- 总调度,用于启动定时器 -->
    <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers" >
            <list>
                <ref bean="startWorkTrigger"/>
            </list>
        </property>
    </bean>


       好了一个指定了具体时间的定时触发任务也已经实现了,下面来看看cronExpression 有哪些需要知道的配置信息,信息如下:

       一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。从左到右:

    1.秒2.分3.小时4.月份中的日期(1-31)5.月份(1-12或JAN-DEC)6.星期中的日期(1-7或SUN-SAT)7.年份(1970-2099) 
    每个元素都显示的规定一个值(如6),一个区间(9-12),一个列表(9,11,13)或一个通配符(*)。因为4和6这两个元素是互斥的,因此应该通过设置一个问号(?)来表明不想设置的那个字段,“/”如果值组合就表示重复次数(10/6表示每10秒重复6次)。

    最后提供一个在线cron表达式生成器:http://cron.qqe2.com/

    展开全文
  • java 定时器

    2019-07-18 11:11:11
    昨天看定时器,被Quartz定时器框架困扰到现在,以为是调用的时候出了问题,以为是我不知道怎么调用然后出的问题,结果是少了jar包。哎,这个问题真的是,告诉我们以后导入一个框架的jar包时,一定要导全,不要只导...

    昨天看定时器,被Quartz定时器框架困扰到现在,以为是调用的时候出了问题,以为是我不知道怎么调用然后出的问题,结果是少了jar包。哎,这个问题真的是,告诉我们以后导入一个框架的jar包时,一定要导全,不要只导核心包,因为核心包可能依赖其他包。

    定时任务不执行原因:没有导入除quartz-2.3.0-SHAPSHOT.jar以外的包。

    解决方法,把其余包都导入。

    这个问题真的是!!!!!真是个值得记忆的教训。现在来说说定时器吧!

    我在理解定时器的时候,提出了这些问题!

    首先,jdk自带Timer,TimerTask类,可以实现定时任务,为什么还需要其他定时器框架呢?

    用java自带的类来做定时任务时,只需写一个类,让这个类extendsTimerTask,然后重写它的Run()方法。

    然后,如果把定时器放在监听器里的话,直接在监听器的某个方法中执行Timer的schedule(task,...)方法。

    我们可以发现,

    schedule(task, 0, PERIOD*PERIODTIME);方法实现的定时种类不多。它不能控制一些复杂的定时任务。

    所以这就是为什么要使用其他定时器框架的原因吧,因为不能满足复杂的任务需求。

    那常见的定时器框架有哪些呢?

    java定时器,Spring定时器,Quartz定时器。

    我暂时只用过java自带的定时器和Quartz定时器,因为Quartz定时器已经够强大了,我觉得了解Spring定时器也就没必要了。

    那Quartz定时器框架是怎么用的呢?

    首先我们要理解Quartz的几个核心概念。

    然后我们要引入我们需要的jar包,注意一个都不能少,不然会引发一系列问题,前面已经截图过。

    最后我们进入代码部分。

    我们要先建一个job类,它是任务的核心,即这个定时任务究竟要做什么,就是做的内容。这个类需要implements该框架的Job类,然后实现它的execute()方法,方法的具体内容就是执行的这个任务,即任务的内容。

     然后,我们需要创建一个JobDetail。

    JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。最开始创建的job类就会在创建它时被用到。

    接着呢,我们需要创建一个触发器,Trigger

    Trigger 代表一个调度参数的配置,什么时候去调。它可以配置定时任务中的定时。尤其是cron表达式的配置,让定时任务想怎么定时就怎么定时,配置可以在http://cron.qqe2.com/中生成,方便快捷。

    最后呢,我们需要一个调度器,Scheduler。

    Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。刚刚创建的JobDetail和Trigger都需被它调度。

    最后的最后,我们只需在监听器或者其他地方直接调用刚刚写好的方法即可,然后如果实在监听器里调用的话,程序一执行,定时任务就开始了。下面我粘一下我的代码。

    web.xml中的配置。

        <listener>
            <listener-class>com.practice.mylistener.QuartzListener</listener-class>
        </listener>

    QuartzListener类。

    package com.practice.mylistener;
    
    import com.practice.tool.QuartzTimeManager;
    import com.practice.tool.QuertzTask;
    import com.practice.tool.job;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    public class QuartzListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            System.out.println("quertztask监听器启动==============================");
            QuartzTimeManager.addJob("myJob","group1","mytrigger","group1", job.class,"1-2 * * * * ?");
            System.out.println("task excute==================================");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
    
        }
    }
    

    QuartzListener类

    package com.practice.tool;
    
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    import java.util.Collection;
    
    public class QuartzTimeManager {
        private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    
        /**
         * @Description: 添加一个定时任务
         *
         * @param jobName 任务名
         * @param jobGroupName  任务组名
         * @param triggerName 触发器名
         * @param triggerGroupName 触发器组名
         * @param jobClass  任务
         * @param cron   时间设置,参考quartz说明文档
         */
        public static void addJob(String jobName, String jobGroupName,
                                  String triggerName, String triggerGroupName, Class jobClass, String cron) {
    
            try {
                Scheduler sched = schedulerFactory.getScheduler();
    
                // 任务名,任务组,任务执行类
                JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
    
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
    
                // 触发器名,触发器组
                triggerBuilder.withIdentity(triggerName, triggerGroupName);
                triggerBuilder.startNow();
    
    
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
    
    
                // 创建Trigger对象
                CronTrigger trigger = (CronTrigger) triggerBuilder.build();
    
    
                // 调度容器设置JobDetail和Trigger
                sched.scheduleJob(jobDetail, trigger);
    
    
                // 启动
                if (!sched.isShutdown()) {
                    System.out.println("=================定quartz定时任务开始");
                    sched.start();
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
    
    
        /**
         * @Description: 修改一个任务的触发时间
         *
         * @param jobName
         * @param jobGroupName
         * @param triggerName 触发器名
         * @param triggerGroupName 触发器组名
         * @param cron   时间设置,参考quartz说明文档
         */
        public static void modifyJobTime(String jobName,
                                         String jobGroupName, String triggerName, String triggerGroupName, String cron) {
            try {
                Scheduler sched = schedulerFactory.getScheduler();
                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
                CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
                if (trigger == null) {
                    return;
                }
    
    
                String oldTime = trigger.getCronExpression();
                if (!oldTime.equalsIgnoreCase(cron)) {
                    /** 方式一 :调用 rescheduleJob 开始 */
                    // 触发器
                    TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                    // 触发器名,触发器组
                    triggerBuilder.withIdentity(triggerName, triggerGroupName);
                    triggerBuilder.startNow();
                    // 触发器时间设定
                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
                    // 创建Trigger对象
                    trigger = (CronTrigger) triggerBuilder.build();
                    // 方式一 :修改一个任务的触发时间
                    sched.rescheduleJob(triggerKey, trigger);
                    /** 方式一 :调用 rescheduleJob 结束 */
    
    
                    /** 方式二:先删除,然后在创建一个新的Job  */
                    //JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
                    //Class<? extends Job> jobClass = jobDetail.getJobClass();
                    //removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
                    //addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
                    /** 方式二 :先删除,然后在创建一个新的Job */
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    
        /**
         * @Description: 移除一个任务
         *
         * @param jobName
         * @param jobGroupName
         * @param triggerName
         * @param triggerGroupName
         */
        public static void removeJob(String jobName, String jobGroupName,
                                     String triggerName, String triggerGroupName) {
            try {
                Scheduler sched = schedulerFactory.getScheduler();
    
    
                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
    
    
                sched.pauseTrigger(triggerKey);// 停止触发器
                sched.unscheduleJob(triggerKey);// 移除触发器
                sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    
        /**
         * @Description:启动所有定时任务
         */
        public static void startJobs() {
            try {
                Scheduler sched = schedulerFactory.getScheduler();
                sched.start();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    
        /**
         * @Description:关闭所有定时任务
         */
        public static void shutdownJobs() {
            try {
                Scheduler sched = schedulerFactory.getScheduler();
                if (!sched.isShutdown()) {
                    sched.shutdown();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    job类

    package com.practice.tool;
    
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class job implements Job {
        @Override
        public void execute(JobExecutionContext jobExecutionContext)
                throws JobExecutionException {
            System.out.println("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
            Date date=new Date();
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("Time:"+sf.format(date));
            System.out.println("Hello");
        }
    }
    

    运行结果:

    最重要的一点,注意导入jar包要完整哦!其实定时器还是挺简单的对不对。

    展开全文
  • java定时器

    2020-02-10 10:41:13
    Java定时器用于在特定时间运行指定的Java程序,其实现方式有两种:TimerTask和Quartz,其中Quartz最为常用,接下来演示如何在Spring框架中配置Quartz定时器: Quartz下载地址:...
  • Java Timer触发定时器

    2016-06-13 20:12:00
    -- Java Timer定时 --> <!-- <bean id="shortUrlTask" class=" com.spring.common.ShortUrlTask"> </bean> <bean id="scheduleReportTask" class="org.springfra...
  • 首先讲一下java定时器的工作原理: java定时器类为java.util.Timer,一个定时器可以执行多个定时任务,每个定时任务就是一个线程,这个类是线程安全的,即多个线程可以无需进行外部同步共享单个Timer对象 任务类为...
  • JAVA定时器

    千次阅读 2009-08-04 12:10:00
    本文转自http://blog.csdn.net/cping1982/archive/2007/11/21/1896794.aspx 用JAVA写了一个定时器类,此类作为一个线程运行,包含了一个队列存放定时器消息,通过比较定时器触发时间,俺触发事件先后顺序排列队列...
  • 本片文章主要介绍基于Timer的定时任务 需求介绍:实现不同定时间隔的两个任务依次循环触发(间隔两秒触发事件一,再间隔四秒触发事件二) 代码实现:package com.zh.timer; import java.util.Date; ...
  • 在现实生活中,会出现这样的例子,比如烧水,一般烧了20分钟后,水开了,会需要及时换水,再烧20分钟,水又开了,继续提醒,比如上班,... 当前java程序中 能够实现定时的 主要有 三种 方式 ,分别是: java定时器 ...
  • 当前java程序中 能够实现定时的 主要有 三种 方式 ,分别是: java定时器 , spring定时器 , quartz定时器.下面依次讲讲他们的应用! <1>java定时器的应用。 java提供了了类java.util.TimerTask类基于线程...
  • 在现实生活中,会出现这样的例子,比如烧水,一般烧了20分钟后,水开了,会需要及时换水,再烧20分钟,水又开了,继续提醒,比如上班,... 当前java程序中 能够实现定时的 主要有 三种 方式 ,分别是: java定时器 , s

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,668
精华内容 7,467
关键字:

java定时器触发

java 订阅