Spring 的@Scheduled注解实现定时任务执行和调度


首先要配置我们的spring.xml   ---  即spring的主配置文件(有的项目中叫做applicationContext.xml或context.xml)


xmlns 多加下面的内容、



[html]  view plain copy


1. xmlns:task="http://www.springframework.org/schema/task"



然后xsi:schemaLocation多加下面的内容、



[html]  view plain copy


  1. http://www.springframework.org/schema/task  
  2. http://www.springframework.org/schema/task/spring-task-3.1.xsd  


最后是我们的task任务扫描注解



[html]  view plain copy


1. <task:annotation-driven/>


我的配置扫描位置是:



[html]  view plain copy



    1. <context:annotation-config/>  
    2. <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  
    3. <context:component-scan base-package="com.test"/>





    扫描的是com.test这样的包下的内容、

    下面需要接口和实现(我的这几个java文件都是com.test的包下的、)



    [java]  view plain copy


    1. public interface IMyTestService {  
    2. public void myTest();  
    3. }


    [java]  view plain copy



      1. @Component  //import org.springframework.stereotype.Component;  
      2. public class MyTestServiceImpl  implements IMyTestService {  
      3. @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次  
      4. @Override  
      5. public void myTest(){  
      6. "进入测试");  
      7.       }  
      8. }



      执行后控制台就会打印出   进入测试   了



      需要注意的几点:

      1、spring的@Scheduled注解  需要写在实现上、

      2、 定时器的任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true、具体就去百度google吧)

      3、实现类上要有组件的注解@Component


      剩下的就是corn表达式了、具体使用以及参数请百度google、

      下面只例出几个式子

      CRON表达式    含义 
      "0 0 12 * * ?"    每天中午十二点触发 
      "0 15 10 ? * *"    每天早上10:15触发 
      "0 15 10 * * ?"    每天早上10:15触发 
      "0 15 10 * * ? *"    每天早上10:15触发 
      "0 15 10 * * ? 2005"    2005年的每天早上10:15触发 
      "0 * 14 * * ?"    每天从下午2点开始到2点59分每分钟一次触发 
      "0 0/5 14 * * ?"    每天从下午2点开始到2:55分结束每5分钟一次触发 
      "0 0/5 14,18 * * ?"    每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 
      "0 0-5 14 * * ?"    每天14:00至14:05每分钟一次触发 
      "0 10,44 14 ? 3 WED"    三月的每周三的14:10和14:44触发 
      "0 15 10 ? * MON-FRI"    每个周一、周二、周三、周四、周五的10:15触发 


      参数分析:
      “*”——字符可以用于所有字段,在“分”字段中设为"*"表示"每一分钟"的含义。
      “?”——字符可以用在“日”和“周几”字段.它用来指定'不明确的值'.这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。在后面的例子中可以看到其含义。
      “-”——字符被用来指定一个值的范围,比如在“小时”字段中设为"10-12"表示"10点到12点"。
      “,”——字符指定数个值。比如在“周几”字段中设为"MON,WED,FRI"表示"the days Monday, Wednesday, and Friday"。
      “/”——字符用来指定一个值的的增加幅度.比如在“秒”字段中设置为"0/15"表示"第0, 15, 30,和45秒"。而"5/15"则表示"第5, 20, 35,和50".在'/'前加"*"字符相当于指定从0秒开始.每个字段都有一系列可以开始或结束的数值。对于“秒”和“分”字段来说,其数值范围为0到59,对于“小时”字段来说其为0到23,对于“日”字段来说为0到31,而对于“月”字段来说为1到12。"/"字段仅仅只是帮助你在允许的数值范围内从开始"第n"的值。
      “L”——字符可用在“日”和“周几”这两个字段。它是"last"的缩写,但是在这两个字段中有不同的含义。例如,“日”字段中的"L"表示"一个月中的最后一天" ——对于一月就是31号对于二月来说就是28号(非闰年)。而在“周几”字段中,它简单的表示"7" or "SAT",但是如果在“周几”字段中使用时跟在某个数字之后,它表示"该月最后一个星期×" ——比如"6L"表示"该月最后一个周五"。当使用'L'选项时,指定确定的列表或者范围非常重要,否则你会被结果搞糊涂的。
      “W”——可用于“日”字段。用来指定历给定日期最近的工作日(周一到周五)。比如你将“日”字段设为"15W",意为: "离该月15号最近的工作日"。因此如果15号为周六,触发器会在14号即周五调用。如果15号为周日,触发器会在16号也就是周一触发。如果15号为周二,那么当天就会触发。然而如果你将“日”字段设为"1W",而一号又是周六,触发器会于下周一也就是当月的3号触发,因为它不会越过当月的值的范围边界。'W'字符只能用于“日”字段的值为单独的一天而不是一系列值的时候。
      “L”和“W”可以组合用于“日”字段表示为'LW',意为"该月最后一个工作日"。
      “#”——字符可用于“周几”字段。该字符表示“该月第几个周×”,比如"6#3"表示该月第三个周五( 6表示周五而"#3"该月第三个)。再比如: "2#1" =表示该月第一个周一而"4#5" =该月第五个周三。注意如果你指定"#5"该月没有第五个“周×”,该月是不会触发的。
      “C”——字符可用于“日”和“周几”字段,它是"calendar"的缩写。它表示为基于相关的日历所计算出的值(如果有的话)。如果没有关联的日历,那它等同于包含全部日历。“日”字段值为"5C"表示"日历中的第一天或者5号以后",“周几”字段值为"1C"则表示"日历中的第一天或者周日以后"。
      对于“月份”字段和“周几”字段来说合法的字符都不是大小写敏感的。

      实例展示


      Spring主配置文件:context-globle.xml

      xmlns 多加下面的内容、



      [html]  view plain copy



        1. xmlns:task="http://www.springframework.org/schema/task"



        然后xsi:schemaLocation多加下面的内容、



        [html]  view plain copy

        1. http://www.springframework.org/schema/task  
        2. http://www.springframework.org/schema/task/spring-task-3.1.xsd  



        最后是我们的task任务扫描注解




        [html]  view plain copy


        1. <task:annotation-driven/>

        定时任务类:

        TimoutUrlJob  ---- 定时向指定url发送Http  Get请求

        @Component
        public class TimoutUrlJob {
        @Autowired
        private CaptchaTimeoutUrlService captchaTimeoutUrlService;
        
        @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次  
        public void test(){
        System.out.println("aaaa");
        List<CaptchaTimeoutUrl> list = captchaTimeoutUrlService.getTimeoutUrl();
        
        System.out.println(list);
        for(CaptchaTimeoutUrl captchaTimeoutUrl:list){
        try {
        //使用Java代码请求反馈路径,并返回reqId和result结果
        String backInfo = HttpRequestUtils.httpRequestGet(captchaTimeoutUrl.getUrl());
        if(null==backInfo||backInfo==""){
        HttpRequestUtils.httpRequestGet(captchaTimeoutUrl.getUrl());
        captchaTimeoutUrlService.updateTimeputUrl(captchaTimeoutUrl);
        }
        } catch (Exception e) {
        e.printStackTrace();
        }
        }
        }
        }



        发送Get请求的工具类 :


        public class HttpRequestUtils {
        private static final String POST_URL="http://localhost:8088/services/xxx/xxx/get.htm";
        public static void main(String[] args) {
        try {
        httpRequestGet(POST_URL);
        } catch (Exception e) {
        e.printStackTrace();
        }
        }
        /** 
             * http get 请求 
             * @param urlStr 请求URL地址 
             * @throws Exception 
             */  
        public static  String httpRequestGet(String urlStr) throws Exception{  
               //URL拼接,如:"http://www.baidu.com?name=HI,中国",这里对特殊字符进行了编码,不然会产生乱码  
               URL url = new URL(urlStr);  
               System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
               System.out.println("进入回调方法!");
        System.out.println(urlStr);
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
               //openConnection函数会根据URL的协议返回不同的URLConnection子类的对象  
               //这里URL是一个http,因此实际返回的是HttpURLConnection   
               HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();  
                 
               //进行连接,实际上request要在下一句的connection.getInputStream()函数中才会真正发到 服务器****待验证  
               httpConn.connect();  
                 
                // 取得输入流,并使用Reader读取  
               BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));  
                 
               System.out.println("=========get request接收数据内容开始============");  
               String lines;  
               while ((lines = reader.readLine()) != null) {  
                   System.out.println(lines);  
               }  
               System.out.println(reader);
               reader.close();  
               System.out.println("=========get request接收数据内容结束============");  
               httpConn.disconnect();  
               return lines;
           }  
        }






        首先要配置我们的spring.xml   ---  即spring的主配置文件(有的项目中叫做applicationContext.xml或context.xml)


        xmlns 多加下面的内容、



        [html]  view plain copy



          1. xmlns:task="http://www.springframework.org/schema/task"



          然后xsi:schemaLocation多加下面的内容、



          [html]  view plain copy

          1. http://www.springframework.org/schema/task  
          2. http://www.springframework.org/schema/task/spring-task-3.1.xsd  



          最后是我们的task任务扫描注解



          [html]  view plain copy


          1. <task:annotation-driven/>


          我的配置扫描位置是:



          [html]  view plain copy


          1. <context:annotation-config/>  
          2. <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  
          3. <context:component-scan base-package="com.test"/>



          扫描的是com.test这样的包下的内容、

          下面需要接口和实现(我的这几个java文件都是com.test的包下的、)



          [java]  view plain copy



            1. public interface IMyTestService {  
            2. public void myTest();  
            3. }



            [java]  view plain copy


            1. @Component  //import org.springframework.stereotype.Component;  
            2. public class MyTestServiceImpl  implements IMyTestService {  
            3. @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次  
            4. @Override  
            5. public void myTest(){  
            6. "进入测试");  
            7.       }  
            8. }


            执行后控制台就会打印出   进入测试   了



            需要注意的几点:

            1、spring的@Scheduled注解  需要写在实现上、

            2、 定时器的任务方法不能有返回值(如果有返回值,spring初始化的时候会告诉你有个错误、需要设定一个proxytargetclass的某个值为true、具体就去百度google吧)

            3、实现类上要有组件的注解@Component


            剩下的就是corn表达式了、具体使用以及参数请百度google、

            下面只例出几个式子

            CRON表达式    含义 
            "0 0 12 * * ?"    每天中午十二点触发 
            "0 15 10 ? * *"    每天早上10:15触发 
            "0 15 10 * * ?"    每天早上10:15触发 
            "0 15 10 * * ? *"    每天早上10:15触发 
            "0 15 10 * * ? 2005"    2005年的每天早上10:15触发 
            "0 * 14 * * ?"    每天从下午2点开始到2点59分每分钟一次触发 
            "0 0/5 14 * * ?"    每天从下午2点开始到2:55分结束每5分钟一次触发 
            "0 0/5 14,18 * * ?"    每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 
            "0 0-5 14 * * ?"    每天14:00至14:05每分钟一次触发 
            "0 10,44 14 ? 3 WED"    三月的每周三的14:10和14:44触发 
            "0 15 10 ? * MON-FRI"    每个周一、周二、周三、周四、周五的10:15触发 


            参数分析:
            “*”——字符可以用于所有字段,在“分”字段中设为"*"表示"每一分钟"的含义。
            “?”——字符可以用在“日”和“周几”字段.它用来指定'不明确的值'.这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。在后面的例子中可以看到其含义。
            “-”——字符被用来指定一个值的范围,比如在“小时”字段中设为"10-12"表示"10点到12点"。
            “,”——字符指定数个值。比如在“周几”字段中设为"MON,WED,FRI"表示"the days Monday, Wednesday, and Friday"。
            “/”——字符用来指定一个值的的增加幅度.比如在“秒”字段中设置为"0/15"表示"第0, 15, 30,和45秒"。而"5/15"则表示"第5, 20, 35,和50".在'/'前加"*"字符相当于指定从0秒开始.每个字段都有一系列可以开始或结束的数值。对于“秒”和“分”字段来说,其数值范围为0到59,对于“小时”字段来说其为0到23,对于“日”字段来说为0到31,而对于“月”字段来说为1到12。"/"字段仅仅只是帮助你在允许的数值范围内从开始"第n"的值。
            “L”——字符可用在“日”和“周几”这两个字段。它是"last"的缩写,但是在这两个字段中有不同的含义。例如,“日”字段中的"L"表示"一个月中的最后一天" ——对于一月就是31号对于二月来说就是28号(非闰年)。而在“周几”字段中,它简单的表示"7" or "SAT",但是如果在“周几”字段中使用时跟在某个数字之后,它表示"该月最后一个星期×" ——比如"6L"表示"该月最后一个周五"。当使用'L'选项时,指定确定的列表或者范围非常重要,否则你会被结果搞糊涂的。
            “W”——可用于“日”字段。用来指定历给定日期最近的工作日(周一到周五)。比如你将“日”字段设为"15W",意为: "离该月15号最近的工作日"。因此如果15号为周六,触发器会在14号即周五调用。如果15号为周日,触发器会在16号也就是周一触发。如果15号为周二,那么当天就会触发。然而如果你将“日”字段设为"1W",而一号又是周六,触发器会于下周一也就是当月的3号触发,因为它不会越过当月的值的范围边界。'W'字符只能用于“日”字段的值为单独的一天而不是一系列值的时候。
            “L”和“W”可以组合用于“日”字段表示为'LW',意为"该月最后一个工作日"。
            “#”——字符可用于“周几”字段。该字符表示“该月第几个周×”,比如"6#3"表示该月第三个周五( 6表示周五而"#3"该月第三个)。再比如: "2#1" =表示该月第一个周一而"4#5" =该月第五个周三。注意如果你指定"#5"该月没有第五个“周×”,该月是不会触发的。
            “C”——字符可用于“日”和“周几”字段,它是"calendar"的缩写。它表示为基于相关的日历所计算出的值(如果有的话)。如果没有关联的日历,那它等同于包含全部日历。“日”字段值为"5C"表示"日历中的第一天或者5号以后",“周几”字段值为"1C"则表示"日历中的第一天或者周日以后"。
            对于“月份”字段和“周几”字段来说合法的字符都不是大小写敏感的。

            实例展示


            Spring主配置文件:context-globle.xml

            xmlns 多加下面的内容、



            [html]  view plain copy


            1. xmlns:task="http://www.springframework.org/schema/task"


            然后xsi:schemaLocation多加下面的内容、



            [html]  view plain copy


            1. http://www.springframework.org/schema/task  
            2. http://www.springframework.org/schema/task/spring-task-3.1.xsd  



            最后是我们的task任务扫描注解




            [html]  view plain copy



            1. <task:annotation-driven/>  

            定时任务类:

            TimoutUrlJob  ---- 定时向指定url发送Http  Get请求

            @Component
            public class TimoutUrlJob {
            @Autowired
            private CaptchaTimeoutUrlService captchaTimeoutUrlService;
            
            @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次  
            public void test(){
            System.out.println("aaaa");
            List<CaptchaTimeoutUrl> list = captchaTimeoutUrlService.getTimeoutUrl();
            
            System.out.println(list);
            for(CaptchaTimeoutUrl captchaTimeoutUrl:list){
            try {
            //使用Java代码请求反馈路径,并返回reqId和result结果
            String backInfo = HttpRequestUtils.httpRequestGet(captchaTimeoutUrl.getUrl());
            if(null==backInfo||backInfo==""){
            HttpRequestUtils.httpRequestGet(captchaTimeoutUrl.getUrl());
            captchaTimeoutUrlService.updateTimeputUrl(captchaTimeoutUrl);
            }
            } catch (Exception e) {
            e.printStackTrace();
            }
            }
            }
            }



            发送Get请求的工具类 :


            public class HttpRequestUtils {
            private static final String POST_URL="http://localhost:8088/services/xxx/xxx/get.htm";
            public static void main(String[] args) {
            try {
            httpRequestGet(POST_URL);
            } catch (Exception e) {
            e.printStackTrace();
            }
            }
            /** 
                 * http get 请求 
                 * @param urlStr 请求URL地址 
                 * @throws Exception 
                 */  
            public static  String httpRequestGet(String urlStr) throws Exception{  
                   //URL拼接,如:"http://www.baidu.com?name=HI,中国",这里对特殊字符进行了编码,不然会产生乱码  
                   URL url = new URL(urlStr);  
                   System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
                   System.out.println("进入回调方法!");
            System.out.println(urlStr);
            System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
                   //openConnection函数会根据URL的协议返回不同的URLConnection子类的对象  
                   //这里URL是一个http,因此实际返回的是HttpURLConnection   
                   HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();  
                     
                   //进行连接,实际上request要在下一句的connection.getInputStream()函数中才会真正发到 服务器****待验证  
                   httpConn.connect();  
                     
                    // 取得输入流,并使用Reader读取  
                   BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));  
                     
                   System.out.println("=========get request接收数据内容开始============");  
                   String lines;  
                   while ((lines = reader.readLine()) != null) {  
                       System.out.println(lines);  
                   }  
                   System.out.println(reader);
                   reader.close();  
                   System.out.println("=========get request接收数据内容结束============");  
                   httpConn.disconnect();  
                   return lines;
               }  
            }