spring任务调度

         最近项目中遇到任务调度的问题,学习总结如下:

         Quartz是一个任务调度框架,由Java语言开发,可以用来做一些定时发送,监听事件等工作。
Quartz完成调度需要3步:
JobDetail:告诉调度器要做什么。
Trigger:告诉调度器什么时候做。
Scheduler:准备妥了就从这里start

依赖包:
 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.2.6.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
 </dependency>

完整实例如下(xml和java):
spring.xml中
<!-- 完整配置:1.配置调度器工厂,2.配置要用的bean,3.配置调度器,4.配置触发器,5.把触发器加入调度器工厂里(SchedulerFactoryBean) -->
<!--配置调度器工厂-->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <!--配置触发器 -->
    <property name="triggers">
        <list>
             <ref bean="sysTaskTimerTrigger"/><!--对应于触发器-->
        </list>
    </property>
</bean>

<!-- start -->
<!-- 要调用的bean -->
<bean id="SysTaskTimer" class="com.topcheer.framework.core.job.SysTaskTimer" /><!--对应于java类-->
    
<!-- 调度器  -->
<bean id="sysTaskTimerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
    <property name="targetObject" ref="SysTaskTimer"></property>  
    <property name="targetMethod" value="timerRun"></property>  
    <!-- concurrent : false表示等上一个任务执行完后再开启新的任务 -->  
    <property name="concurrent" value="false"></property>  
</bean>
    
<!-- 触发器 -->
<bean id="sysTaskTimerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <!--调度器-->
    <property name="jobDetail" ref="sysTaskTimerJobDetail"/><!--对应于调度器-->
    <!-- 延迟3s执行 -->
    <property name="startDelay" value="3000"/>
    <!--每隔10s执行一次 -->
    <property name="repeatInterval" value="10000"/>
</bean>
<!-- end -->

java代码如下:(部分代码省略)
@Component
public class SysTaskTimer  { 
//每次调用的这个方法
public void timerRun(){
try {
while(true){
if(myWorkQueue == null || myWorkQueue.size() == 0){
    Map<Object,Object> param1 = new HashMap<Object,Object>();
    param1.put("recordNum", 10);
    List<FndSysTaskTimer> sysTaskTimerList = sysTaskTimerService.getSysTaskTimerHowMany(param1);
    if(sysTaskTimerList == null || sysTaskTimerList.size() == 0){
        if(myWorkQueue != null && threadPool != null){
            threadPool.shutdownNow();
        }
        break;
    }
    if(sysTaskTimerList != null && sysTaskTimerList.size() > 0){
        myWorkQueue=new ArrayBlockingQueue<Runnable>(10);
        threadPool = new ThreadPoolExecutor(1,10,10L,TimeUnit.SECONDS,myWorkQueue);
                        
        for(int i=0 ; i < sysTaskTimerList.size(); i++){
            setSysTaskTimer(sysTaskTimerList.get(i));
            TaskThread taskThread =  new TaskThread();
            taskThread.init();
            myWorkQueue.put(taskThread);
        }
        for(Runnable runnable : myWorkQueue){
            threadPool.execute(runnable);
        }
    }
    }
    else{
    break;
    }
}
            
} catch (Exception e) {
    e.printStackTrace();
}
}
}

下面针对以上的部门进行讲解:
一、配置调度工厂,是为了解决spring 注入问题,有两种方法:

1.
ApplicationContext content = 
        new ClassPathXmlApplicationContext("classpath:META-INF/applicationContext.xml");
        userDaoI = content.getBean(UserDaoI.class);
使用ApplicationContex对象加载applicationContext.xml文件注入UserDaoI接口,但是这个方法不好的一点是每当用一个接口就要写一个,比较麻烦。

2.
<bean id="jobFactory" class="com.config.quartz.JobFactory"></bean>
        <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobFactory" ref="jobFactory"></property>
        <property name="triggers">
            <list>
                <ref bean="cronTrigger"/>
            </list>
        </property>
    </bean>

@Service("jobFactory")
public class JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        // 进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}
先写一个类继承AdaptableJobFactory 抽象方法,不需要任何改动。
其实不用用继承,只需要写这个配置,映射jar里的类即可,如下:
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobFactory" ref="jobFactory"></property>
        <property name="triggers">
            <list>
                <ref bean="cronTrigger"/>
            </list>
        </property>
    </bean>

二、以上start--end部分,分别有两种方式:
     定时任务详情(上面说的调度器)的两种方法:
1.第一种写法:
<!-- 要调用的bean -->
<bean id="SysTaskTimer" class="com.topcheer.framework.core.job.SysTaskTimer" /><!--对应于java类-->
<!-- 调度器  -->
<bean id="sysTaskTimerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
    <property name="targetObject" ref="SysTaskTimer"></property>  
    <!--  指定要调用的方法 timerRun -->
    <property name="targetMethod" value="timerRun"></property>  
    <!-- concurrent : false表示等上一个任务执行完后再开启新的任务 -->  
    <property name="concurrent" value="false"></property>  
</bean>
这种方式可以直接指定要调用的方法。

2.第二种写法:
<bean id="cronJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <!--配置简单作业的目标类 -->
    <property name="jobClass" value="com.topcheer.framework.core.job.MyCronJob"/>
    <!--配置耐久性,如果一个任务不是durable,那么当没有Trigger关联它的时候,它就会被自动删除 -->
    <property name="durability" value="true"/>
</bean>

public class MyCronJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("Quartz的cron表达式任务执行了:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

}
这种方式要继承QuartzJobBean类,实现executeInternal方法。两种方式任选一种。

    触发器的两种写法:
1.第一种写法:
<bean id="sysTaskTimerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail" ref="sysTaskTimerJobDetail"/>
    <!-- 延迟3s执行 -->
    <property name="startDelay" value="3000"/>
    <!--每隔1000s执行一次 -->
    <property name="repeatInterval" value="1000000"/>
</bean>

2.第二种写法:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <!--使用定时作业详情  或 使用简单作业详情- -->
    <property name="jobDetail" ref="cronJobDetail"/>
    <!--每隔5s执行一次 -->
    <property name="cronExpression" value="*/5 * * * * ?"/>
    <property name="startDelay" value="3000"></property>  
</bean>
使用CronTriggerFactoryBean类配置,这个方法的好处在于可以使用cronExpression表达式。


cronExpression表达式介绍:

cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:

1.        Seconds
2.        Minutes
3.        Hours
4.        Day-of-Month
5.        Month
6.        Day-of-Week
7.        Year (可选字段)


例  "0 0 12 ? * WED" 在每星期三下午12:00 执行,

个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT".

“*” 代表整个时间段.

每一个字段都有一套可以指定有效值,如

Seconds (秒)         :可以用数字0-59 表示,

Minutes(分)          :可以用数字0-59 表示,

Hours(时)             :可以用数字0-23表示,

Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份

Month(月)            :可以用0-11 或用字符串  “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示

Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

 

“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行

“?”:表示每月的某一天,或第周的某一天

“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”

“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”

““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or "FRI#3" 则表示“每月第三个星期五”

 

1)Cron表达式的格式:秒 分 时 日 月 周 年(可选)。

               字段名                 允许的值                        允许的特殊字符  
               秒                         0-59                               , - * /  
               分                         0-59                               , - * /  
               小时                     0-23                               , - * /  
               日                         1-31                               , - * ? / L W C  
               月                         1-12 or JAN-DEC             , - * /  
               周几                     1-7 or SUN-SAT                , - * ? / L C #  
               年 (可选字段)     empty, 1970-2099              , - * /

 

               “?”字符:表示不确定的值

               “,”字符:指定数个值

               “-”字符:指定一个值的范围

               “/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m

               “L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X

               “W”字符:指定离给定日期最近的工作日(周一到周五)

               “#”字符:表示该月第几个周X。6#3表示该月第3个周五

 
         2)Cron表达式范例:

                 每隔5秒执行一次:*/5 * * * * ?

                 每隔1分钟执行一次:0 */1 * * * ?

                 每天23点执行一次:0 0 23 * * ?

                 每天凌晨1点执行一次:0 0 1 * * ?

                 每月1号凌晨1点执行一次:0 0 1 1 * ?

                 每月最后一天23点执行一次:0 0 23 L * ?

                 每周星期天凌晨1点实行一次:0 0 1 ? * L

                 在26分、29分、33分执行一次:0 26,29,33 * * * ?

                 每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?

      每天上午10:15触发 :0 15 10 * * ? *

     2005年的每天上午10:15触发:0 15 10 * * ? 2005


Quartz属于重量级的定时任务框架,我们一般都会选择轻量级的如Spring Task定时任务进行开发。

参考:
https://segmentfault.com/a/1190000012926491
https://blog.csdn.net/x6582026/article/details/52947878
https://www.cnblogs.com/hafiz/p/6159280.html
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值