Spring定时任务的几种实现

时间:2020-12-24 07:53:36

一.分类

从实现的技术上来分类,目前主要有三种技术(或者说有三种产品):

  • Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少,这篇文章将不做详细介绍。
  • 使用Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂,稍后会详细介绍。
  • Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多,稍后会介绍。

从作业类的继承方式来讲,可以分为2类:

  1. 作业类需要继承自特定的作业类基类,如Quartz中需要继承自org.springframework.scheduling.quartz.QuartzJobBean;java.util.Timer中需要继承自java.util.TimerTask。
  2. 作业类即普通的java类,不需要继承自任何基类。

注:个人推荐使用第二种方式,因为这样所以的类都是普通类,不需要事先区别对待。

从任务调度的触发时机来分,这里主要是针对作业使用的触发器,主要有以下两种:

  1. 每隔指定时间则触发一次,在Quartz中对应的触发器为:org.springframework.scheduling.quartz.SimpleTriggerBean
  2. 每到指定时间则触发一次,在Quartz中对应的调度器为:org.springframework.scheduling.quartz.CronTriggerBean

注:并非每种任务都可以使用这两种触发器,如java.util.TimerTask任务就只能使用第一种。Quartz和spring task都可以支持这两种触发条件。

二.用法说明

详细介绍每种任务调度工具的使用方式,包括Quartz和spring task两种。

三、比较

Quartz拥有TimerTask所有的功能,而TimerTask则没有。

Quartz每次执行任务都创建一个新的任务类对象,而TimerTask则每次使用同一个任务类对象。

Quartz的某次执行任务过程中抛出异常,不影响下一次任务的执行,当下一次执行时间到来时,定时器会再次执行任务;而TimerTask则不同,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务。

Spring-Task

Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种

项目结构

Spring定时任务的几种实现

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.task</groupId>
<artifactId>springTask</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<spring.version>4.2.4.RELEASE</spring.version>
<slf4j.version>1.6.4</slf4j.version>
</properties>

<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- 日志处理 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>

<profiles>
    <profile>
        <id>jdk-1.7</id>
        <activation>
            <activeByDefault>true</activeByDefault>
            <jdk>1.7</jdk>
        </activation>
        <properties>
         <!-- 将maven发布的代码编译成和IDE一样的版本 -->
            <maven.compiler.source>1.7</maven.compiler.source>
            <maven.compiler.target>1.7</maven.compiler.target>
   <maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion>
        </properties>
    </profile>
  </profiles>
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<!--将所有请求的数据在spring中指定为utf8编码 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 配置监听器后,启动Tomcat服务器的时候就可启动Spring容器,从而执行applicationContext.xml配置文件信息 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring 配置文件路径,此处可将Spring MVC的相关配置内容配置到Spring的配置文件applicationContext.xml中,共享同一个配置文件即可 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>

 

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:context
="http://www.springframework.org/schema/context"
xmlns:aop
="http://www.springframework.org/schema/aop"
xmlns:tx
="http://www.springframework.org/schema/tx"
xmlns:dubbo
="http://code.alibabatech.com/schema/dubbo"
xmlns:task
="http://www.springframework.org/schema/task"
xsi:schemaLocation
="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
">


<!-- 开启spring注解 -->
<context:component-scan base-package="com.task "/>

<!--spring定时任务 使用配置文件方式 -->
<!-- <task:scheduled-tasks>
<task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/>
</task:scheduled-tasks> -->
<!-- spring定时任务采用注解方式
如果你同时执行多个任务,且某些任务耗时较长,要配线程池哦
假如你设置了12:00触发A任务、
12:05触发B任务,如果A任务需耗时10分钟,并且没设置线程池,那么B任务有可能会被推迟到12:10以后再执行哦。
具体池的大小,视项目情况而定
-->
<task:annotation-driven scheduler="myScheduler" mode="proxy"/>
<task:scheduler id="myScheduler" pool-size="100"/>
</beans>

log4j.properties

### 设置###
log4j.rootLogger
= info,stdout,D,E

### 输出信息到控制台###
log4j.appender.stdout
= org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target
= System.out
log4j.appender.stdout.layout
= org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern
= [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志文件设置 ###
log4j.appender.D
= org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File
= vincent_player_debug.log
log4j.appender.D.Append
= true
log4j.appender.D.Threshold
= DEBUG
log4j.appender.D.layout
= org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern
= %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

### 输出ERROR 级别以上的日志文件设置 ###
log4j.appender.E
= org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File
= vincent_player_error.log
log4j.appender.E.Append
= true
log4j.appender.E.Threshold
= ERROR
log4j.appender.E.layout
= org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern
= %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

作业类

package com.task;

import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class TaskJob {
private static Logger logger = Logger.getLogger(TaskJob.class);
//注解方式
@Scheduled(cron = "0 * * * * ?")
public void job1(){
logger.info(
"任务进行中。。。");
try {
Thread.sleep(
10*1000l);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Scheduled(cron
= "5 * * * * ?")
public void job2(){
logger.info(
"任务进行中。。。");
}
}

 Quartz

Spring定时任务的几种实现

在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法可以是普通类。很显然,第二种方式远比第一种方式来的灵活。

这里采用的就是第二种方式

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.quartz</groupId>
<artifactId>springQuartz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.1.6.RELEASE</spring.version>
<slf4j.version>1.6.4</slf4j.version>
</properties>

<dependencies>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>

<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>

<!-- 日志处理 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<finalName>springQuartz</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!-- 将maven发布的代码编译成和IDE一样的版本 -->
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<!--将所有请求的数据在spring中指定为utf8编码 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- 配置监听器后,启动Tomcat服务器的时候就可启动Spring容器,从而执行applicationContext.xml配置文件信息 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring 配置文件路径,此处可将Spring MVC的相关配置内容配置到Spring的配置文件applicationContext.xml中,共享同一个配置文件即可 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>

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:context
="http://www.springframework.org/schema/context"
xmlns:aop
="http://www.springframework.org/schema/aop"
xmlns:tx
="http://www.springframework.org/schema/tx"
xmlns:dubbo
="http://code.alibabatech.com/schema/dubbo"
xmlns:task
="http://www.springframework.org/schema/task"
xsi:schemaLocation
="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
">

<!--配置作业类JobDetailBean -->
<bean id="job1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="com.task.TaskJob2" />
</property>
<property name="targetMethod" value="job1" />
<property name="concurrent" value="false" /><!-- false表示job不会并发执行,默认为true-->
</bean>
<!-- 配置作业调度的触发方式(触发器) -->
<!-- <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="job1" />
<property name="startDelay" value="0" />调度工厂实例化后,经过0秒开始执行调度
<property name="repeatInterval" value="2000" />每2秒调度一次
</bean> -->

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="job1" />
<property name="cronExpression" value="0 * * * * ?" />
</bean>

<!-- 配置调度工厂 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>

TaskJob2.java

package com.task;

import org.apache.log4j.Logger;

public class TaskJob2 {

private Logger logger = Logger.getLogger(TaskJob2.class);

public void job1(){
logger.info(
"任务1已开始。。。");
}
}

log4j.properties

### 设置###
log4j.rootLogger
= info,stdout,D,E

### 输出信息到控制台###
log4j.appender.stdout
= org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target
= System.out
log4j.appender.stdout.layout
= org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern
= [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志文件设置 ###
log4j.appender.D
= org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File
= vincent_player_debug.log
log4j.appender.D.Append
= true
log4j.appender.D.Threshold
= DEBUG
log4j.appender.D.layout
= org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern
= %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

### 输出ERROR 级别以上的日志文件设置 ###
log4j.appender.E
= org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File
= vincent_player_error.log
log4j.appender.E.Append
= true
log4j.appender.E.Threshold
= ERROR
log4j.appender.E.layout
= org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern
= %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

junit测试方法

package springQuartz;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


@RunWith(SpringJUnit4ClassRunner.
class) //使用junit4进行测试
@ContextConfiguration(locations="classpath:applicationContext.xml") //加载配置文件
public class Test1 {
private Logger logger = LoggerFactory.getLogger(Test1.class);

@Test
public void demo(){
logger.info(
"应用开始启动。。。");
}
}