1.Quartz是一个完全由java编写的开源作业调度框架,Quartz的主要三个核心类为Scheduler(调度器)、Trigger(触发器)、Job(任务)。
1)Scheduler:调度器就相当于一个容器,装载着任务和触发器。该类是一个接口,代表一个Quartz的独立运行容器。Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组和名称,组及名称是Scheduler查找定位容器中某一对象的依据。Trigger的组及名称必须唯一,JobDetail的组及名称必须唯一。SchedulerFactory则是Scheduler工厂,负责生成Scheduler。
2)Trigger::负责设置调度策略,该类是一个接口,描述触发job执行的时间触发规则。最常用的是SimpleTrigger和CronTrigger。如果你需要在一个固定的时间和重复次数或一个固定的间隔时间,那么SimpleTrigger比较合适;如果你有许多复杂的作业调度,那么CronTrigger比较合适。CronTrigger和Unix的cron机制基本一致,需要的只是一个cron表达式,比如"0 0 12 * * ?"会在每天中午12点触发执行;"0 15 10 ? * 6L"会在每个月的最后一个星期五的早上10:15触发Job执行。
3)Job:定义需要执行的任务,该类是一个接口,只定义一个方法execute(JobExecutionContext context),在实现类的execute方法中编写所需要定时执行的Job,JobExecutionContext类提供了调度应用的一些信息,Job运行时的信息保存在JobDataMap中。
4)JobDetail:描述Job的实现类及其他相关的静态信息,如:Job名字,关联监听器,Quartz每次调度Job时,都重新创建一个Job。
5)ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
6)Listener:事件和监听器体系,大部分组件都拥有事件。 下面搭建SSM框架,Quartz定时调度查询MySQL数据库中的数据。
2.Cron表达式:
'*'可以用于所有字段,在'分'字段中设为"*"表示每一分钟的含义
'?'可以用在'日'和'周几'字段,指定不明确的值
'-'被用来指定一个值的范围,如在小时字段中设为'10-12'表示10点-12点
','指定数个值,如'MON,WED,FRI'表示'the days Monday,Wednesday,and Friday'
'/'用来指定一个值的增加幅度,如在'秒'字段中设置为'0/15'表示'第0,15,30和45s'
'L'用在日和周几这两个字段,是'last'缩写,'日'字段中的'L'表示'一个月中的最后一天',在'周几'字段中,它简单的表示'7'
'W'可用于'日'字段,用来指定给定日期最近的工作日
'L'和'W'可以组合用于'日'字段表示为'LW',该月最后一个工作日
'#'可用于周几字段,表示'该月第几个周x',
"0 0 17 * * ?" 每天傍晚17点触发
"0 15 17 ? * *" 每天傍晚17点15分触发
"0 15 17 * * ?" 每天傍晚17点15分触发
"0 15 17 * * ? *" 每天傍晚17点15分触发
"0 15 17 * * ? 2017" 2017年的每天傍晚17点15分触发
"0 * 17 * * ?" 每天傍晚17点开始至17点59分每分钟触发一次
"0 0/5 17 * * ?" 每天傍晚17点开始至17点55分每隔5分钟触发一次
"0 0/5 17,19 * * ?" 每天傍晚17点开始至17点55和19点至19点55两个时间段内分每隔5分钟触发一次
"0 0-5 17 * * ?" 每天傍晚17至17点05每分钟触发一次
"0 0 17 ? * MON-FRI" 每个周一至周五的17:00:00触发
"0 0 17 15 * ?" 每月15号的17点触发
"0 0 17 L * ?" 每月的最后一天的17点触发
"0 0 17 * ? 6" 每月的最后一一个周五的17点触发
"0 0 17 ? * 6#3" 每月的第三个周五的17点触发
以上都是Quartz作业调度框架的基础知识,作为一个开发人员,我的学习方式是以项目例子推动对所学知识的理解。下面为搭建一个SSM框架,定时触发对MySQL数据库相关数据的查询。
1)整个package结构:
2)applicationContext-core.xml为Spring相关配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 1.把属性资源文件的信息加载到Spring环境中进行利用 -->
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/db.properties</value>
<value>classpath:config/quartz.properties</value>
</list>
</property>
</bean>
<!-- 2.创建数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<!-- 最大并发连接数 -->
<property name="maxActive" value="10" />
<!-- 最小空闲连接数 -->
<property name="maxIdle" value="5" />
</bean>
<!-- 3.配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 自动扫描com.mybatis.assess.pojo, 指定包名称来为该包下的pojo类声明别名,默认的别名就是类名(首字母大小写都行) -->
<property name="typeAliasesPackage" value="com.ssm.quartz.pojo" />
<!-- 指定mybatis的全局配置文件的路径 -->
<property name="mapperLocations" value="classpath:com/ssm/quartz/mybatis/*DaoMapper.xml" />
</bean>
<!-- 4.扫描com.mybatis.assess.dao包下接口 自动生成代理实现类 -->
<mybatis:scan base-package="com.ssm.quartz.dao" factory-ref="sqlSessionFactory" />
<!-- 5.事务管理 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 加载定时器 配置文件-->
<import resource="spring-quartz.xml"/>
</beans>
2)applicationContext-mvc.xml为SpringMVC相关配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:component-scan base-package="com.ssm.quartz" />
<mvc:annotation-driven />
<!-- 配置资源映射
mapping:代表映射路径
location:代表文件路径,必须是webapp根目录下的路径才行
cache-period:浏览器缓存时间
-->
<mvc:resources location="/css/" mapping="/css/**" cache-period="31536000"/>
<mvc:resources location="/js/" mapping="/js/**" cache-period="31536000"/>
<mvc:resources location="/image/" mapping="/image/**" cache-period="31536000"/>
<!-- 配置视图解析器
当Controller返回XXX字符串时,先通过拦截器,然后该类就会在jsp/目录下,
查找XXX.jsp文件 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
3)db.properties为数据库相关配置文件
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useSSL=true
db.username=root
db.password=123456
#db.driver = oracle.jdbc.driver.OracleDriver
#db.url = jdbc:oracle:thin:@localhost:1521:orcl
#db.username = root
#db.password = 123456
4)quartz.properties为Cron表达式相关配置文件
#查询日期是否变化表达式意思(10/10 * * * * ? 10秒后每隔10秒运行)
qzExcutTimer=5/5 * * * * ?
#日终启动时间(0 0 18 * * ?表示每天下午6点执行)
qzRunDataTimer=0 32 11 * * ?
5)spring-quartz.xml为Quartz框架相关配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<bean id="quartzJob" class="com.ssm.quartz.job.QuartzJob"></bean>
<!-- 使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job借口,通过targetMethod指定调用方法 -->
<bean id="JobTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 要调度的对象 -->
<property name="targetObject" ref="quartzJob" />
<!-- 要执行的方法名称 -->
<property name="targetMethod" value="excutor" />
<!-- 将并发设置为false -->
<property name="concurrent" value="false"></property>
</bean>
<!-- 调度触发器 -->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="JobTask" />
<!-- 表达式 -->
<property name="cronExpression" value="${qzExcutTimer}" />
</bean>
<!-- 调度工厂:如果将lazy-init="false",那么容器启动就会执行调度程序 -->
<bean id="startQuartz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- 作业调度器,list下可加入其它的调度器 -->
<ref bean="trigger" />
</list>
</property>
</bean>
</beans>
6)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">
<!-- 配置Spring上下文监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/config/applicationContext-core.xml</param-value>
</context-param>
<!-- 配置Log4j日志上下文监听器 -->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>quartz.root</param-value>
</context-param>
<!-- Spring编码过滤器 -->
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置前端控制器DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
默认加载方式:默认加载文件必须规范
文件命名:servlet-name-servlet.xml======springmvc-servlet.xml
路径规范:必须在WEB-INF目录下面
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/config/applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
7)log4j.properties配置文件
#全局日志配置
#log4j.appender.syslog.encoding=UTF-8
log4j.rootLogger=info, stdout, R
#包下所有类的日志级别
#日志输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.encoding=UTF-8
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.sss} [%-5p] %c [%t] - %m%n
#日志输出到文件
log4j.appender.R=org.apache.log4j.RollingFileAppender
#log4j.appender.R.encoding=UTF-8
log4j.appender.R.File=${quartz.root}/logs/server.log
log4j.appender.R.MaxFileSize=2048KB
log4j.appender.R.MaxBackupIndex=50
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.sss} [%-5p] %c [%t]- %m%n
#关闭Spring日志
log4j.category.org.springframework =OFF
8)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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.quartz.test</groupId>
<artifactId>quartz</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<properties>
<!-- spring版本号 -->
<spring.version>3.2.0.RELEASE</spring.version>
<!-- mybatis版本号 -->
<mybatis.version>3.2.7</mybatis.version>
<!-- log4j日志文件管理包版本 -->
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<!-- spring所需jar -->
<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-beans</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-core</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-tx</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-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</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-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis所需jar -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<!-- 定时器Quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.6</version>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.0-rc1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.0-rc1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>test</scope>
</dependency>
<!-- commons依赖包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.17.1-GA</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
9)数据访问层DAO,作业调度Job及Mybatis的Mapper代理代码如下
@Repository("userDao")
public interface IUserDao {
List<User> queryAllUser() throws Exception;
}
public class QuartzJob implements IQuartz {
private Logger logger = Logger.getLogger(QuartzJob.class);
@Resource(name="userDao")
private IUserDao userDao;
public void excutor() {
List<User> list = null;
String date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
date = sdf.format(new Date());
list = userDao.queryAllUser();
} catch (Exception e) {
e.printStackTrace();
}
logger.info(date + "定时触发查询:" + list);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.quartz.dao.IUserDao">
<resultMap type="User" id="userMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</resultMap>
<select id="queryAllUser" resultMap="userMap">
select * from user
</select>
</mapper>
这个例子希望大家能够受益,项目例子最终运行效果为:
学习Quartz作业调度框架遇见的问题:
1)java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class
异常原因:Spring 3.0版本中内置的Quartz版本是<2.0的,在使用最新的Quartz包(>2.0)之后,接口不兼容。
2)java.lang.ClassNotFoundException:org.springframework.web.util.Log4jConfigListener
异常分析:ContextLoaderListener类位于spring-web-3.2.0.RELEASE.jar包中。检查了maven的pom.xml,依赖引入正常。在工程Maven Dependencies视图中也能看到spring-web-3.1.0.RELEASE.jar包被正常引入进来了。
异常原因:进入到tomcat的部署路径.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\下检查了一下,发现工程部署后在WEB-INF文件夹下没有生成lib目录,正常情况下,会生成lib目录并把工程的所有依赖jar包都部署到该目录下。
解决方法:1.右键点击项目--选择Properties,选择Deployment Assembly,在右边点击Add按钮,在弹出的窗口中选择Java Build Path Entries。2.点击Next,选择Maven Dependencies。3.点击Finish,然后可以看到已经把Maven Dependencies添加到Web应用结构中了。
以上分析和解决方法参照http://blog.sina.com.cn/s/blog_7fb5109d0101o48g.html