Java定时任务详解

定时任务在项目中经常会使用到,本文主要根据博主自己使用定时的经验分如下几点介绍定时任务:

1、Quartz定时任务简介及Spring配置Quartz定时任务

2、SchedulerFactory对定时任务进行增删改查

3、总结

Quartz定时任务简介:

Quartz是项目中经常用到的定时任务之一,是一个完全由java编写的开源作业调度框架,可以与J2EE与J2SE应用程序相结合也可以单独使用,其主要组成部分包括Job、Scheduler、CronExpression,这里就不一一介绍了,下面介绍Spring如何配置Quartz。

配置Quartz需要明白的一点是配置Quartz即配置Job、Scheduler和CronExpression,这三部分配置完成后,就是一个完整的定时任务,配置如下:

<bean id= "TestJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
  <property name="jobClass" value="xx.TestQuartzJob"/>
  <!-- 可以封装各种数据到JobExecutionContext里,包括接口、类,其中testServiceImpl是Spring管理的Bean,需要什么声明 -->
  <property name="jobDataAsMap">
    <map>
      <entry key="test" value="test"/>
      <entry key ="testServiceImpl" value-ref="testServiceImpl"/>
    </map>
  </property>
</bean>

<bean id= "TestTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
  <property name="jobDetail" ref="TestJobDetail" />
  <property name="cronExpression" value="0 0/1 * * * ?" />
</bean>

<bean id= "testSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="triggers" >
    <list>
      <ref bean="TestTrigger" />
    </list>
  </property>
</bean>
<bean id="testServiceImpl" class="xx.service.impl.TestServiceImpl">

配置完成后,就是增加一个为你执行一个任务的Java类。每一个Quartz Job必须有一个 实现了org.quartz.Job接口的具体类,代码如下:

public class TestQuartzJob extends QuartzJobBean {
  @Override
  protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException
  {
    // 获取Job配置的接口
    TestServiceImpl testServiceImpl = (TestServiceImpl) arg0.getJobDetail().getJobDataMap().get("testServiceImpl");
    // 执行业务方法
    quartzStart();
  }
  public void quartzStart(){
    // 业务方法...
  }
}

当然,在Job中其实不用特意的配置接口,使用Spring的注入即可,这里只是把这个配置接口的方法进行说明。

到这里,简单的配置Quartz定时任务已经完成,下面附加一个我在项目中使用Quartz的情形:cronExpression表达式从数据库读取。

当时,我解决这个问题的方法是继承org.springframework.scheduling.quartz.CronTriggerBean,设置cronExpression,具体代码如下:

Trigger的配置要改:

<bean id="TestTrigger" class="xx.InitCronTriggerFactoryBean">
  <property name="jobDetail" ref="TestJobDetail" />
  <property name="key" value="key" />
</bean>

xx.InitCronTriggerFactoryBean代码:

public class InitCronTriggerFactoryBean extends CronTriggerFactoryBean implements Serializable {

  private static final long serialVersionUID = 1L;

  @Resource
  private SysParamService sysParamService;

  private String key;

  public void setKey(String key)
  {
    this.key = key;

    setCronExpression(getCronExpressionFromDB());
  }

  private String getCronExpressionFromDB()
  {
    if(StringUtils.isEmpty(key))
      return "0 0/5 * * * ?";

    SysParam sysParam = new SysParam();

    try
    {
      sysParam = sysParamService.getNameByKey(key);
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    if(sysParam != null && !StringUtils.isEmpty(sysParam.getParamValue()))
      return sysParam.getParamValue();

    return "0 0/5 * * * ?";
  }
}

其中,SysParamService是根据key到数据库查询对应的cronExpression表达式的接口,这个接口除了使用Spring注入,也可以使用set方法设置,如下:

<bean id="TestTrigger" class="xx.InitCronTriggerFactoryBean">
  <property name="jobDetail" ref="TestJobDetail" />
  <property name="key" value="key" />
  <property name="sysParamService" ref="sysParamService" />
</bean>
<bean id="sysParamService" class="xx.service.impl.SysParamServiceImpl">

这样,在xx.InitCronTriggerFactoryBean就要加入sysParamService的set方法,此时的xx.InitCronTriggerFactoryBean代码为:

public class InitCronTriggerFactoryBean extends CronTriggerFactoryBean implements Serializable {
  private static final long serialVersionUID = 1L;
  private SysParamServiceImpl sysParamService;
  private String key;
  public void setKey(String key)
  {
    this.key = key;
  }
  public void setSysParamService(SysParamServiceImpl sysParamService)
  {
    this.sysParamService = sysParamService;
    setCronExpression(getCronExpressionFromDB());
  }
  private String getCronExpressionFromDB()
  {
    if(StringUtils.isEmpty(key))
      return "0 0 0/1 * * ?";
    SysParam sysParam = new SysParam();
    try
    {
      sysParam = sysParamServiceImpl.getNameByKey(key);
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    if(sysParam != null && !StringUtils.isEmpty(sysParam.getParamValue()))
      return sysParam.getParamValue();
    return "0 0 0/1 * * ?";
  }
}

Quartz定时任务到这里就差不多了,基本的配置和使用就是上面将的,想要深入了解Quartz可以在网上查找更多的资料,并在实践中使用。接下来将讲解在项目中使用的可以随时对定时任务进行增删改查操作的实例。

定时任务的增删改查,其实可以看做是对数据进行增删改查。不过,定时任务的增删改查是操作Job和Trigger,具体代码如下:

定时任务管理器代码:

public class QuartzManager {

  private static final Logger logger = LogPresident.getRootLogger();

  private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();

  private static Map<String, JobKey> jobKeyMap = new HashMap<String, JobKey>();

  /**
  * 增加一个定时任务
  * @author zhiyuan.wu
  * @date 2017年3月30日
  * @param jobName
  * @param triggerName
  * @param cls
  * @param date
  */
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void addJob(String jobName, String triggerName, Class cls, Date date)
  {
    try
    {
      Scheduler scheduler = schedulerFactory.getScheduler();

      // job
      JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, Scheduler.DEFAULT_GROUP).build();

      // 触发器
      SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity(triggerName, Scheduler.DEFAULT_GROUP).startAt(date).build();

      scheduler.scheduleJob(jobDetail, trigger);

      // 启动
      scheduler.start();

      jobKeyMap.put(jobDetail.getKey().getName(), jobDetail.getKey());
    }
    catch (Exception e)
    {
      logger.error("--------添加定时任务出错:" + e.getMessage(), e);
    }
  }

/**
* 删除对应的定时任务
* @author zhiyuan.wu
* @date 2017年3月29日
* @param jobKey
*/
public static void removeJob(JobKey jobKey)
{
  Scheduler scheduler;
  try
  {
    scheduler = schedulerFactory.getScheduler();
    scheduler.deleteJob(jobKey);

      jobKeyMap.remove(jobKey.getName());
    }
    catch (SchedulerException e)
    {
      logger.error("--------删除定时任务出错:" + e.getMessage(), e);
    }
  }

/**
* 启动所有定时任务
* @author zhiyuan.wu
* @date 2017年3月29日
*/
public static void startJobs()
{
  try
  {
    Scheduler sched = schedulerFactory.getScheduler();
    sched.start();
  }
  catch (Exception e)
  {
    logger.error("--------启动所有定时任务出错:" + e.getMessage(), e);
  }
}

/**
* 停止所有定时任务
* @author zhiyuan.wu
* @date 2017年3月29日
*/
public static void shutdownJobs()
{
  try
  {
    Scheduler sched = schedulerFactory.getScheduler();

    if (!sched.isShutdown())
    {
      sched.shutdown();
    }
  }
  catch (Exception e)
  {
    logger.error("--------停止所有定时任务出错:" + e.getMessage(), e);
  }
}

/**
* 修改定时任务
* @author zhiyuan.wu
* @date 2017年3月29日
* @param jobKey
* @param jobName
* @param triggerName
* @param cls
* @param date
*/
@SuppressWarnings("rawtypes")
public static void modifyJobTime(JobKey jobKey, String jobName, String triggerName, Class cls, Date date)
{
  try
  {
    removeJob(jobKey);

    addJob(jobName, triggerName, cls, date);
  }
  catch (Exception e)
  {
    logger.error("--------修改定时任务出错:" + e.getMessage(), e);
  }
}

/**
* 打印当前定时任务的jobName
* @author zhiyuan.wu
* @date 2017年3月29日
* @throws SchedulerException
*/
public static void printJobName() throws SchedulerException
{
  for (String jobName : jobKeyMap.keySet())
  {
    logger.info("--------jobName:" + jobName);
  }
}
}

Job代码:

public class TestJob implements Job {

  private static final Logger logger = LogPresident.getRootLogger();

  public void execute(JobExecutionContext context) throws JobExecutionException
  {
    JobKey jobKey = context.getJobDetail().getKey();

    logger.info("--------定时任务开始执行:" + jobKey.getName());

    // 业务方法...
    // 移除定时任务
    QuartzManager.removeJob(jobKey);
  }
}

增加一个定时任务代码:

QuartzManager.addJob(JobName, TriggerName , TestJob.class, Date);

这样,在到达时间Date时,定时任务将会执行。不过这样增加的任务是保存在内存中,项目重启将会丢失定时任务,所以,最好增加一个类,在项目启动时将会扫描数据库,将未执行的定时任务重新加载到内存中去。

定时任务在项目中运用需要根据业务具体调整,但只要弄清楚定时任务的原理和实现,那么就可以在项目中灵活运它用来具体的业务,希望这篇文章可以让大家快速了解和运用定时任务,并运用到实践中。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • Java Web项目中编写定时任务的实现

    之前在的公司有专门的任务调度框架,需要使用的时候引个jar包加个配置和注解就可以使用了,还有专门的平台来维护运行的机器及监控执行状态等等. 现在突然没了这个工具,而又要写定时任务,该怎么办呢? 对于非Web应用来说,我们可以使用Quartz,使用简单,功能强大. 对于Java Web应用来说,当然也可以使用Quartz(有一篇介绍了方法:http://www.jb51.net/article/104105.htm),但是还有更方便的工具,那就是spring自带的支持定时任务功能. Spring的

  • java中 spring 定时任务 实现代码

    复制代码 代码如下: import org.apache.log4j.*;public class TaskJob {       public static Logger log = Logger                     .getLogger(TaskJob.class);       public void SayHello() {              // TODO Auto-generated method stub              try {      

  • 实例讲解java定时任务

    今天为大家分享的一个经验就是java的定时任务,就是说在一天的某个时间点执行以下代码. public class TimerManager { //时间间隔 private static final long PERIOD_DAY = 24 * 60 * 60 * 1000; public TimerManager() { Calendar calendar = Calendar.getInstance(); /*** 定制每日2:00执行方法 ***/ calendar.set(Calenda

  • java定时任务的实现方式

    在开发测试工具的应用后台,经常听到同事说要做个定时任务把做日志处理,或者数据清理,包括做些复杂的业务计算逻辑,在选择定时任务的时候,怎么能够快速实现,并且选择一种更适合自己的方式呢? 我这里把定时任务的实现收集整理了一些方法,希望可以帮到刚开始做定时任务的同学,写得不对的地方请指正. 一  Java 基本的定时任务,总结方法有三种: 1.1   创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果: 1.2   用Timer和TimerTask与第一

  • 最流行的java后台框架spring quartz定时任务

    配置quartz 在spring中需要三个jar包: quartz-1.8.5.jar.commons-collections-3.2.1.jar.commons-logging-1.1.jar 首先要配置我们的spring.xml xmlns 多加下面的内容. xmlns:task="http://www.springframework.org/schema/task" 然后xsi:schemaLocation多加下面的内容. http://www.springframework.o

  • java基于线程池和反射机制实现定时任务完整实例

    本文实例讲述了java基于线程池和反射机制实现定时任务的方法.分享给大家供大家参考,具体如下: 主要包括如下实现类: 1. Main类: 任务执行的入口: 调用main方法,开始加载任务配置并执行任务 package com.yanek.task; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import ja

  • java定时任务的实现方法

    复制代码 代码如下: package com.ucap.sms; import java.util.Timer; import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener; public class SmsListener implements ServletContextListener{    private Timer timer=null; public void contex

  • 使用java执行定时任务示例

    这是一个演示如何使用java执行定时任务的实例,本实例开始运行后不会自动结束,请在运行本实例后手动结束程序. 复制代码 代码如下: package com.hongyuan.test; import java.awt.Desktop;import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import j

  • Java定时任务的三种实现方法

    译者注:个人觉得用定时任务来跑垃圾回收不是很好的例子,从译者接触到的项目来看,比较常见的是用定时任务来进行非实时计算,清除临时数据.文件等.在本文里,我会给大家介绍3种不同的实现方法:1.普通thread实现2.TimerTask实现3.ScheduledExecutorService实现 一.普通thread 这是最常见的,创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果.这样可以快速简单的实现,代码如下: 复制代码 代码如下: public

  • Java定时任务详解

    定时任务在项目中经常会使用到,本文主要根据博主自己使用定时的经验分如下几点介绍定时任务: 1.Quartz定时任务简介及Spring配置Quartz定时任务 2.SchedulerFactory对定时任务进行增删改查 3.总结 Quartz定时任务简介: Quartz是项目中经常用到的定时任务之一,是一个完全由java编写的开源作业调度框架,可以与J2EE与J2SE应用程序相结合也可以单独使用,其主要组成部分包括Job.Scheduler.CronExpression,这里就不一一介绍了,下面介

  • Java下SpringBoot创建定时任务详解

    序言 使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式: 一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer) 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就派上用场了. 三.基于注解设定多线程定时任务 一.静态:基于注解 基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响. 1.创建定时器 使用SpringBoo

  • springboot定时任务详解

    在我们开发项目过程中,经常需要定时任务来帮助我们来做一些内容, Spring Boot 默认已经帮我们实行了,只需要添加相应的注解就可以实现 一.基于注解(静态) 1.pom 包配置 pom 包里面只需要引入 Spring Boot Starter 包即可 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactI

  • SpringBoot集成quartz实现定时任务详解

    目录 准备知识点 什么是Quartz Quartz的体系结构 什么是Quartz持久化 实现案例 - 单实例方式 实现案例 - 分布式方式 后端实现 前端实现 测试效果 准备知识点 需要了解常用的Quartz框架. 什么是Quartz 来源百度百科, 官网地址:http://www.quartz-scheduler.org/ Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来

  • SpringBoot整合Quartz实现定时任务详解

    目录 Quartz简介 核心概念 Scheduler JobDetail Job Trigger SpringBoot整合Quartz 准备数据库表 Maven相关依赖 配置文件 quartz配置类 创建任务类 创建监听类 运行结果 Quartz简介 Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它来为执行一个作业而创建简单的或复杂的调度.它有很多特征,如:数据库支持,集群,插件,EJB

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java递归算法详解(动力节点整理)

    递归算法是一种直接或者间接调用自身函数或者方法的算法.Java递归算法是基于Java语言实现的递归算法.递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解.递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解.    递归算法解决问题的特点: 1)递归就是方法里调用自身.  2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口.  3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低.所以一般不提倡用递归算法设计程序.  4)在递

  • Java 匿名内部类详解及实例代码

    Java  匿名内部类详解 匿名内部类也就是没有名字的内部类 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口 实例1:不使用匿名内部类来实现抽象方法 abstract class Person { public abstract void eat(); } class Child extends Person { public void eat() { System.out.println("eat someth

  • Java设计模式详解之门面模式(外观模式)

    门面模式(Facade Pattern)也叫外观模式,它隐藏系统的复杂性,并向客户端提供一个可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性,为子系统中的一组接口提供了一个统一的高层访问接口,这个接口使得子系统更容易被访问或使用.这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用. 简而言之,就是把一堆复杂的流程封装成一个接口供给用户更简单的使用,这个设计模式里有三个角色: 1)门面角色( facade ):

  • Java Cache详解及简单实现

     Java Cache详解及简单实现 概要: 最近在做spring的项目,想做一个缓存,访问数据库,定期来做数据更新 要实现两个功能 可以通过http请求来立刻刷新缓存 缓存可以通过自己配置的时间间隔来定期刷新 通过Controller来做 因为需要通过http来刷新缓存,所以第一个想法就是把缓存做成一个Controller Controller的实现 Controller最大的优势,就是可以通过Spring的配置,注入很多依赖,比如对Service的依赖,对数据库的依赖等. 大量的访问数据库跟

随机推荐