您的位置:首页 > 编程语言 > Java开发

两种方式实现java定时器,使用quartz定时器框架和java自带Timer定时器,编写定时任务

2018-03-15 10:17 1216 查看
    开启定时任务的方式有几种:包括quartz定时框架和java自带Timer定时器,区别在于,quartz定时任务在程序报错后能不断执行,而在Timer定时任务中,程序一旦报错,定时任务即不再执行,可根据需求选用。
    前两天工作需求,需要写个定时任务去跑一些数据,我首先选择的就是quartz定时器,不过后来因为环境问题而改用了Timer定时器,下面简单介绍一下两种定时器的书写。

    1,quaetz定时器,需要在applicationContext.xml中进行一些配置,代码如下:

    <!-- 实现定时器任务-要调度的对象 -->  
   <bean id="jobBean" class="com.mer.listener.job.TimerJob" />
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
        <property name="targetObject" ref="jobBean" />  
        <property name="targetMethod" value="execute" />  
        <!-- 将并发设置为false -->  
        <property name="concurrent" value="false" />  
    </bean>  
 
    <bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerBean">  
        <property name="jobDetail" ref="jobDetail" />  
       <!--  定时任务,每天凌晨2点执行一次   -->
      <!--   <property name="cronExpression" value="0 0 2 * * ?"  />   -->
        <property name="cronExpression" value="0/5 * * * * ?"  />  
    </bean>  
  
     <!-- 总管理类如果将lazy-init='false'那么容器启动就会执行调度程序     -->
    <bean id="startQuertz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" >  
        <property name="triggers">  
            <list>  
               <!--  作业调度器,list下可加入其他的调度器   -->
                <ref bean="trigger" />  
            </list>  
        </property>  
    </bean>  

<!-- 注入工具类,普通类中能够调用server层方法 -->
<!-- <bean id="springContextUtil" class="com.mer.util.SpringContextUtil"></bean> -->

<bean id="springBeanFactoryUtils" class="com.mer.util.SpringBeanFactoryUtils"/>
       配置完成后,只需在TimerJob中完成相关逻辑代码即可,execute方法即为定时任务执行方法,我的TimerJob类如下:

package com.mer.listener.job;
import org.springframework.context.ApplicationContext;
import com.mer.service.BaseService;
import com.mer.service.cailanzidb.TranddelService;
import com.mer.util.LogUtil;
import com.mer.util.SpringBeanFactoryUtils;
import com.mer.util.SpringContextUtil;

public class TimerJob{
        //使用工具类获取bean,在普通类中调用service

BaseService baseService = (BaseService)SpringBeanFactoryUtils.getBean("baseServiceImpl");
LogUtil log = new LogUtil();
        public void execute(){  
        try {
    //菜市场 市区 查看数据功能    每天定时录入交易数据到汇总表
        System.out.println("定时器-----定时录入交易汇总表");
        baseService.insert("transInsertGM");
        baseService.insert("transInsertFJ");
        baseService.insert("transInsertDM");
} catch (Exception e) {
log.errinfoe("执行定时器导入菜市场数据报错", e);
e.printStackTrace();
}
            }  
    }
}
    上面的quartz定时器就写好了,最后别忘了导入quartz定时器的相关jar包哦,下面说一下我遇到的一个坑,这里不属于定时器编写范围。

        因为业务需求,定时器里要调用service层的相关方法跑数据,但是因为此类为普通类,不能直接通过注解直接注入service,如果直接使用的花,会报错baseService空指针。因此需要另外写一个工具类,工具类代码如下:
package com.mer.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 普通类调用Spring注解方式的Service层bean
 * Created by HZC on 2015/10/21.
 */
public class SpringBeanFactoryUtils implements ApplicationContextAware {
    private static ApplicationContext appCtx;

    /**
     * 此方法可以把ApplicationContext对象inject到当前类中作为一个静态成员变量。
     *
     * @param applicationContext ApplicationContext 对象.
     * @throws BeansException
     * @author hzc
     */

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appCtx = applicationContext;
    }

    /**
     * 获取ApplicationContext
     *
     * @return
     * @author hzc
     */
    public static ApplicationContext getApplicationContext() {
        return appCtx;
    }

    /**
     * 这是一个便利的方法,帮助我们快速得到一个BEAN
     *
     * @param beanName bean的名字
     * @return 返回一个bean对象
     * @author hzc
     */
    public static Object getBean(String beanName) {
        return appCtx.getBean(beanName);
    }

}
    此工具类需要在applicationContext.xml配置里添加一行配置,如下:
        <!-- 注入工具类,普通类中能够调用server层方法 -->
<bean id="springBeanFactoryUtils" class="com.mer.util.SpringBeanFactoryUtils"/>

    如果有遇到相同问题的小伙伴,可以借鉴一下这个工具类,亲测可用。
2,好了,上面是使用quartz定时框架写定时任务,下面讲一下怎么用java自带的Timer定时器写定时任务,
    Tim
4000
er定时器用到的是litener监听器,所以需要在web.xml中将需要监听的定时任务加入定时器,配置如下:


  <listener>
    <listener-class>com.mer.conn.InitServletListener</listener-class>
  </listener>

    然后在监听类InitServletListener中完成相关代码,如下:
package com.mer.conn;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.mer.service.cailanzidb.TranddelService;
import com.mer.util.LogUtil;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
 * 
 *********************************************************.<br>
 * [类名] InitServletListener <br>
 * [描述] 项目初始化监听器 <br>
 * [作者] gw <br>
 * [时间] 2016-1-9 下午9:48:07 <br>
 *********************************************************.<br>
 */
public class InitServletListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
}

public void contextInitialized(ServletContextEvent sce) {
//获取service
WebApplicationContext applicationContext =  WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());  
final TranddelService tranddelService= (TranddelService) applicationContext.getBean("tranddelService");
LogUtil log = new LogUtil();
try {
//设置TimerTask
TimerTask task = new TimerTask() {
@SuppressWarnings("static-access")
@Override
public void run() {
    //菜市场 市区 查看数据功能    每天定时录入交易数据到汇总表
            System.out.println("定时器-----定时录入交易汇总表");
            tranddelService.insert("transInsertGM");
            tranddelService.insert("transInsertFJ");
            tranddelService.insert("transInsertDM");
}
};
int dateSpan=24*60*60*1000;
//设置执行时间
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH)+1;//每天
//定制每天定时执行一次
calendar.set(year, month, day, 17,59,00);    //时间设置 后三位是时分秒
Date date = calendar.getTime();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));
Timer timer = new Timer();
//每天的date时刻执行task, 仅执行一次
timer.schedule(task, date,dateSpan);
Thread.sleep(1000);      //延迟一秒执行
} catch (Exception e) {
log.errinfoe("执行定时器导入菜市场数据报错", e);
e.printStackTrace();
}
}
}

    项目启动初始化监听器之后,即进行了任务监听。
    后语:假如你跟我一样有业务需求,要通过普通类调用service层或dao层方法,建议使用Timer定时器,因为Timer和quartz的管理容器不同,所以在进行bean注入时,使用quartz会出现一些框架知识方面的坑,对此方面理解不太深的小伙伴,还是选择Timer比较保险,比如我哈。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息