美文网首页
Spring Task的坑

Spring Task的坑

作者: peteLee | 来源:发表于2018-03-22 10:47 被阅读0次

    背景:
    因用到定时任务,选了简单的springTask,使用中发现Task被执行两次。

    解决方案:
    参考了几篇博文:
    这是因为我们很容易在一个基于Spring的Web工程中启动2个定时线程:
    第一次:web容器启动的时候,读取applicationContext.xml(或者别的Spring核心配置文件)文件时,会加载一次。
    第二次:Spring本身会加载applicationContext.xml(或者别的Spring核心配置文件)一次。
    解决方案:将你的Task的相关配置独立出来并在web.xml中通过context-param加载。而不是通过spring加载。
    1) 独立出Spring-Task,如新命名一个文件名叫cms_quartz.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:task="http://www.springframework.org/schema/task"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
        
        <context:component-scan base-package="com.yundong.api.task" />  
          
        <task:annotation-driven scheduler="qbScheduler" mode="proxy"/>  
        <task:scheduler id="qbScheduler" pool-size="10"/>  
    </beans>
    
    1. 在web.xml中去加载该文件:
    <context-param> 
            <param-name>contextConfigLocation</param-name> 
            <param-value>/WEB-INF/cms-servlet.xml, classpath:cms-quartz.xml</param-value> 
    </context-param>
    

    原文:http://josh-persistence.iteye.com/blog/1984331?utm_source=tuicool&utm_medium=referral

    顺便记录spring Task配置方式:

    第一种:配置文件方式

    第一步:编写作业类
    即普通的pojo,如下:

    import org.springframework.stereotype.Service;  
    @Service  
    public class TaskJob {  
          
        public void job1() {  
            System.out.println(“任务进行中。。。”);  
        }  
    } 
    

    第二步:在spring配置文件头中添加命名空间及描述

    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:task="http://www.springframework.org/schema/task"   
        。。。。。。  
        xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
    

    第三步:spring配置文件中设置具体的任务

    <task:scheduled-tasks>   
            <task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/>   
    </task:scheduled-tasks>  
      
    <context:component-scan base-package=" com.gy.mytask " /> 
    

    说明:ref参数指定的即任务类,method指定的即需要运行的方法,cron及cronExpression表达式,具体写法这里不介绍了,详情见上篇文章附录。
    <context:component-scan base-package="com.gy.mytask" />这个配置不消多说了,spring扫描注解用的。
    到这里配置就完成了,是不是很简单。

    第二种:使用注解形式
    也许我们不想每写一个任务类还要在xml文件中配置下,我们可以使用注解@Scheduled,我们看看源文件中该注解的定义:

    @Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE})  
    @Retention(RetentionPolicy.RUNTIME)  
    @Documented  
    public @interface Scheduled  
    {  
      public abstract String cron();  
      
      public abstract long fixedDelay();  
      
      public abstract long fixedRate();  
    }  
    

    可以看出该注解有三个方法或者叫参数,分别表示的意思是:
    cron:指定cron表达式
    fixedDelay:官方文档解释:An interval-based trigger where the interval is measured from the completion time of the previous task. The time unit value is measured in milliseconds.即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。
    fixedRate:官方文档解释:An interval-based trigger where the interval is measured from the start time of the previous task. The time unit value is measured in milliseconds.即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。

    下面我来配置一下。
    第一步:编写pojo

    import org.springframework.scheduling.annotation.Scheduled;    
    import org.springframework.stereotype.Component;  
      
    @Component(“taskJob”)  
    public class TaskJob {  
        @Scheduled(cron = "0 0 3 * * ?")  
        public void job1() {  
            System.out.println(“任务进行中。。。”);  
        }  
    }  
    

    第二步:添加task相关的配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:task="http://www.springframework.org/schema/task"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
        
        <context:component-scan base-package="com.yundong.api.task" />  
          
        <task:annotation-driven scheduler="qbScheduler" mode="proxy"/>  
        <task:scheduler id="qbScheduler" pool-size="10"/>  
    </beans>
    

    说明:理论上只需要加上<task:annotation-driven />这句配置就可以了,这些参数都不是必须的。

    或者时间配置到properties

    import org.springframework.scheduling.annotation.Scheduled;    
    import org.springframework.stereotype.Component;  
      
    @Component(“taskJob”)  
    @PropertySource("classpath:com/xx/api/conf/task.properties")
    public class TaskJob {  
        @Scheduled(cron = "${jobs.schedule}")  
        public void job1() {  
            System.out.println(“任务进行中。。。”);  
        }  
    }  
    

    Ok配置完毕,当然spring task还有很多参数,我就不一一解释了,具体参考xsd文档http://www.springframework.org/schema/task/spring-task-3.0.xsd
    附录:
    cronExpression的配置说明,具体使用以及参数请百度google
    字段 允许值 允许的特殊字符
    秒 0-59 , - * /
    分 0-59 , - * /
    小时 0-23 , - * /
    日期 1-31 , - * ? / L W C
    月份 1-12 或者 JAN-DEC , - * /
    星期 1-7 或者 SUN-SAT , - * ? / L C #
    年(可选) 留空, 1970-2099 , - * /

    • 区间
    • 通配符
      ? 你不想设置那个字段
      下面只例出几个式子

    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触发

    补充 :
    有时候你配置了:@PropertySource("classpath:xxx/task.properties"),而使用
    @Value("${xxx}")
    private String xxx;
    时并不能解析正确的值,你需要加上:

        @Bean
        public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    

    这个bean主要用于解决@value中使用的占位符,如果不使用的话还可以用:

        @Autowired  
        private Environment env;
        然后
        env.getProperty("xxx")这样取配置文件中的值
    

    相关文章

      网友评论

          本文标题:Spring Task的坑

          本文链接:https://www.haomeiwen.com/subject/psohqftx.html