写随笔主要是当做日记,方便以后查看,遇到该问题时获取解决方法。

 Spring3.0后就自带了定时任务功能,接下来记录 Spring如何配置定时器,定时器运行流程。

一、Spring配置定时器,开启定时调度功能。

  javaWeb 工程得先集成Spring框架,集成后在applicationcontext.xml文件同级目录下新建一个quartz_config.xml文件,工程目录如下:

  quartz_config.xml代码如下(配置Spring定时任务所需信息,如果applicationcontext.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: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/task
            http://www.springframework.org/schema/task/spring-task-3.0.xsd">
    <task:annotation-driven></task:annotation-driven>
    
</beans>

二、创建定时执行方法。

  后台创建一个MyTestJob.java类,创建一个定时执行的方法executeCalcReconFileData。

package com.tscp.base.job;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.tscp.base.utils.spring.DateUtils;

/**
 * 定时器测试类
 * 
 * @author yangmin
 * @since 1.0
 * @version 2017-11-18 yangmin
 */
@Component
public class MyTestJob {
    
    /**
     * 执行定时统计对账结果
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void executeCalcReconFileData() {
        String strNowTime = DateUtils.getTime();
        System.out.println("\n执行定时器,执行时间:" + strNowTime);
    }
}
这里对方法使用Spring的Scheduled注解,配置定时器每五秒钟调用一次executeCalcReconFileData方法,cron表达式参考: http://rainbowdesert.iteye.com/blog/2107220。
程序运行结果:

 

三、通过配置文件获取定时器执行时间。

  1、创建配置文件项目启动时将配置信息读取到容器中。

  在config目录下创建一个quart_config.properties文件,用来配置定时器信息。在里面配置一个 job.test.taskTimeout=0/10 * * * * ? 的配置信息,既每10秒中执行一次。

#测试定时器
job.test.taskTimeout = 0/10 * * * * ?

 

   2、项目启动加载配置到容器。

  在后台创建一个PropertyPlaceholder类,继承PropertyPlaceholderConfigurer类。

package com.tscp.base.utils.spring;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

/**
 * 获取配置文件类
 *
 * @author yangmin
 * @since 1.0
 * @version 2017-11-18 yangmin
 */
public class PropertyPlaceholder extends PropertyPlaceholderConfigurer {
    
    /** 配置信息存在内存中 */
    private static Map<String, String> propertyMap;
    
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        super.processProperties(beanFactoryToProcess, props);
        propertyMap = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            String value = props.getProperty(keyStr);
            propertyMap.put(keyStr, value);
        }
    }
    
    /**
     * 获得内存的配置信息
     * 
     * @param name 配置项名称
     * @return String 配置的对象
     */
    public static String getProperty(String name) {
        return propertyMap.get(name);
    }
}

  在applicationcontext.xml中配置项目启动加载PropertyPlaceholder的代码,配置在quartz_config.xml文件前,我的applicationcontext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
    <!-- spring集成,注释掉 -->
    <context:component-scan base-package="com.tscp" />
    
    <!-- 将多个配置文件读取到容器中,交给Spring管理 -->
    <bean id="propertyConfigurer"
        class="com.tscp.base.utils.spring.PropertyPlaceholder">
        <property name="locations">
            <list>
                <value>/WEB-INF/config/*_config.properties</value>
            </list>
        </property>
    </bean>
    
    <import resource="quartz_config.xml" />

</beans>

  这样项目每次启动时就会把quart_config.properties文件中的信息加载到容器中。

   3、后台定时方法修改。

    MyTestJob.executeCalcReconFileData方法之前是直接配置cron参数,现在直接去容器中的信息。

@Component
public class MyTestJob {
    
    /**
     * 执行定时统计对账结果
     */
    //@Scheduled(cron = "0/5 * * * * ?")
    @Scheduled(cron = "${job.test.taskTimeout}")
    public void executeCalcReconFileData() {
        String strNowTime = DateUtils.getTime();
        System.out.println("\n执行定时器,执行时间:" + strNowTime);
    }
}

  现在的cron取额是quart_config.properties文件中的信息,启动项目定时器为每十秒钟执行一次。

三、定时器动态修改cron。

  动态修改cron,需要修改定时器执行方法,新建一个UpdateJobTask.java类并实现SchedulingConfigurer接口:

package com.tscp.base.job;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

/**
 * 修改定时器任务执行时间
 *
 * 
 * @author yangmin
 * @since 1.0
 * @version 2017-11-21 yangmin
 */
@Component(value = "updateJobTask")
@EnableScheduling
public class UpdateJobTask implements SchedulingConfigurer {
    
    /** FIXME */
    public static String cron = "0/5 * * * * ?";
    
    /** FIXME */
    public static ScheduledTaskRegistrar taskRegistrar;
    
    /** FIXME */
    int i = 0;
    
    /**
     * 修改执行时间
     * 
     * @param cronExpression 表达式
     * @return 修改结果
     */
    public boolean setCron(String cronExpression) {
        UpdateJobTask.cron = cronExpression;
        return true;
    }
    
    /**
     * @param taskRegistrar ScheduledTaskRegistrar
     * @see org.springframework.scheduling.annotation.SchedulingConfigurer#configureTasks(org.springframework.scheduling.config.ScheduledTaskRegistrar)
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // taskRegistrar.setTaskScheduler(poolScheduler());
        
        taskRegistrar.addTriggerTask(new Runnable() {
            
            @Override
            public void run() {
                i++;
                // 任务逻辑
                System.out.println("第" + (i) + "次任务逻辑开始执行操作... " + "时间:【" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()) + "】");
            }
        }, new Trigger() {
            
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                // 任务触发,可修改任务的执行周期
                CronTrigger trigger = new CronTrigger(cron);
                Date nextExec = trigger.nextExecutionTime(triggerContext);
                System.out.println("第" + (i) + "次任务触发执行操作... " + "时间:【" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(nextExec) + "】");
                return nextExec;
            }
        });
    }
}

  定时方法configureTasks在项目启动时会被调用,Trigger一个多少时间之后执行的定时任务,在定时任务run后,会再去Trigger,依次循环。创建一个setCron方法用于改变cron参数,执行结果如下:

  nextExecutionTime方法是从i=o开始执行,run从i=1开始执行,在第四次nextExecutionTime后执行了setCron方法,将cron改为10秒执行一次,而任务会在下一次run方法后才使用新的cron,也就是不会立即执行,如需立即执行,则使用Quartz。

  javaWeb项目中经常会使用动态定时器,做一下倒计时之类的事务,下篇记录。

   ps:好东西值得记录。