第三方包
通过测试。一个简单任务只需要以下几个包:commons-beanutils.jar、commons-collections.jar、commons-logging.jar、commons-digester.jar、quartz.jar即可
名称 | 必须/备注 | 网址 |
activation.jar | 主要是 JavaMail 要用到 | http://java.sun.com/products/javabeans/glasgow/jaf.html |
commons-beanutils.jar | 是 | http://jakarta.apache.org/commons/beanutils |
commons-collections.jar | 是 | http://jakarta.apache.org/commons/collections |
commons-dbcp-1.1.jar | 是,假如用到数据库作为作业存储 | http://jakarta.apache.org/commons/dbcp |
commons-digester.jar | 是 | 假如你使用了某些插件,就需要它 |
commons-logging.jar | 是 | http://jakarta.apache.org/commons/logging/ |
commons-pool-1.1.jar | http://jakarta.apache.org/commons/pool/ | |
javamail.jar | 发送 e-mail 用 | http://java.sun.com/products/javamail/ |
jdbc2_0-stdext.jar | 是,假如用到数据库作为作业存储 | http://java.sun.com/products/jdbc/ |
jta.jar | 是,假如用到数据库作为作业存储 | http://java.sun.com/products/jta/database |
quartz.jar | 是 | Quart 框架核心包 |
servlet.jar | 假如使用了Servlet 容器,但容器中应该存在 | http://java.sun.com/products/servlet/ |
log4j.jar | 是,日志 | http://logging.apache.org/ |
流程:
在classes下配置quartz.properties文件,
# Main Quartz configuration
#是否跳过联网检查更新
#默认会联网检查是否有更新
org.quartz.scheduler.skipUpdateCheck = true
#调度器的实例名
#可以是你喜欢的任何字符串。它用来在用到多个调度器区分特定的调度器实例
org.quartz.scheduler.instanceName = DatabaseScheduler
#调度器的实例ID
#也允许任何字符串。这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中
#如果 Quartz 框架是运行在非集群环境中,那么自动产生的值将会是 NON_CLUSTERED
#假如是在集群环境下使用 Quartz,这个值将会是主机名加上当前的日期和时间。大多情况下,设置为 AUTO 即可
org.quartz.scheduler.instanceId = NON_CLUSTERED
#作业存储方式
#数据库存储
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = quartzDataSource
#配置数据库连接池
org.quartz.dataSource.quartzDataSource.connectionProvider.class = com.mt.framework.pub.quartz.QuartzDataSource
#调度器数据库表前缀
org.quartz.jobStore.tablePrefix = QRTZ_
#线程管理类
#Quartz 自带的线程池实现类
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#处理的线程个数
org.quartz.threadPool.threadCount = 10
# 作业存储数据库配置: JDBC jobStoreTX
#org.quartz.dataSource.quartzDataSource.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
#org.quartz.dataSource.quartzDataSource.URL = jdbc:sqlserver://192.168.1.69:1433;database=DGWEB
#org.quartz.dataSource.quartzDataSource.user = sa
#org.quartz.dataSource.quartzDataSource.password = matech
#org.quartz.dataSource.quartzDataSource.driver = oracle.jdbc.driver.OracleDriver
#org.quartz.dataSource.quartzDataSource.URL = jdbc:oracle:thin:@127.0.0.1:1521:MATECH
#org.quartz.dataSource.quartzDataSource.user = matech
#org.quartz.dataSource.quartzDataSource.password = matech
# 最大的数据库链接数:推荐 threadCount size + 3
#org.quartz.dataSource.quartzDataSource.maxConnections = 8
#在超过它的下次触发时多少毫秒才算是错过触发
org.quartz.jobStore.misfireThreshold = 60000
#同一时刻能处理错过触发 Trigger 的最大数量
org.quartz.jobStore.maxMisfiresToHandleAtATime = 10
连接池配置类
package com.mt.framework.pub.quartz;
import java.sql.Connection;
import java.sql.SQLException;
import org.quartz.utils.ConnectionProvider;
import com.mt.util.db.DBConnectPool;
public class QuartzDataSource implements ConnectionProvider {
private int maxConnections;
public void setMaxConnections(int maxConnections){
this.maxConnections=maxConnections;
}
@Override
public Connection getConnection() throws SQLException {
return DBConnectPool.getConnection();
}
@Override
public void shutdown() throws SQLException {
// TODO Auto-generated method stub
}
}
获取connection类:
package com.mt.util.db;
import java.sql.Connection;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* 数据库链接(供webservice使用)
*
*
*/
public class DBConnectPool {
private final static Log log = LogFactory.getLog(DBConnectPool.class);
/*数据源*/
private static DataSource dataSource=null;
public DBConnectPool(DataSource dataSource){
DBConnectPool.dataSource=dataSource;
}
/**
* 获取数据库连接
*
*/
public static Connection getConnection() {
Connection conn = null;
try{
conn=dataSource.getConnection();
}catch(Exception e){
log.error("执行方法getConnection()出错,无法从数据源中获取数据库连接!\n"+e.getMessage());
e.printStackTrace();
}
return conn;
}
}
/**
*
* 部署调度任务
*
* @param Task
* @return
*/
public void scheduleTask(QuartzTask task,CronInfo cronInfo) throws Exception {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("task", task);
JobDetail jobDetail = JobBuilder.newJob(QuartzTaskJobBean.class)
.withIdentity(task.getTaskName(),"sysGroup")
.usingJobData(jobDataMap)
.build();
String triggerName = task.getUuid();
String cronExpression =cronInfo.getCronStr();
if(!"".equals(cronExpression)){
SchedulerService.schedule(jobDetail,triggerName,"sysGroup",cronExpression);
}
}
}
调度任务:
*
* 数据采集任务执行接口
*
*/
public class GatherJobBean implements Job {
private Log log=new LogQuartz(GatherJobBean.class);
@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException {
GatherTask gatherTask = (GatherTask) jobexecutioncontext.getJobDetail().getJobDataMap().get("task");
LogQtzInfo logQtzInfo=new LogQtzInfo(jobexecutioncontext.getJobDetail(),jobexecutioncontext.getTrigger());
logQtzInfo.setLogType("GatherJobBean");
boolean isSuccess=false;
Connection conn = null;
try {
conn = new DBConnect().getConnect();
DataGather dataGather = (DataGather) Class.forName(gatherTask.getClassName()).newInstance();
if(dataGather.before(gatherTask, conn)){
isSuccess=dataGather.execute(gatherTask, conn);
if(isSuccess){
dataGather.after(gatherTask, conn);
logQtzInfo.setLogContent("【成功】执行数据采集任务调度");
}
};
} catch (Exception e) {
logQtzInfo.setLogContent("【失败】执行数据采集任务调度:"+e.getMessage());
} finally {
DbUtil.close(conn);
log.database(logQtzInfo);
}
}
}
转载:
这篇单单记录一下个人配置使用quartz的JDBC JobStoreTX的过程以及其中遇到的问题,这里的quartz是version2.2.1,数据库使用的mysql。
JDBCJobStore储存是速度比较慢的,但是也不至于很坏,通过JDBCJobStore储存于数据库的方式适用于Oracle,PostgreSQL, MySQL, MS SQLServer, HSQLDB, DB2等数据库。
1) 建表
在下载的文件的docs/dbTables目录下有对应建表语句,如果没有对应于应用的就自己改动来适应。这些个表都有"QRTZ"前缀,可以作为区别于别的命名。
2) 选定事务
如果你不需要绑定其他事务处理,你可以选择quartz的事务,其通过JobStoreTX来管理,这也是常用的选择,当然如果你要和你的应用容器一起管理,那你可以使用quartz的
JobStoreCMT,quartz通过JobStoreCMT来的使用来让你的应用容器管理quartz的事务。
3) 创建数据源
一个是提供一个connection,让quartz可以连接到数据库,另一个是提供的JNDI的方式,让quartz可以从所在容器中获取到。使用JDBC连接方式(假设你使用的是StdSchedulerFactory):
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
或者
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
这里当然选择JobStoreTX。
其次:
选定JDBC代理类,quartz里提供了StdJDBCDelegate,如果这个不能正常工作的,你可以选用其他代理类(在org.quar.impl.jdbcjobstore package或者其子包中可以找到),包括DB2v6Delegate (for DB2 version 6 and earlier), HSQLDBDelegate (for HSQLDB),MSSQLDelegate (for Microsoft SQLServer), PostgreSQLDelegate (for PostgreSQL),
WeblogicDelegate (for using JDBC drivers made by WebLogic), OracleDelegate (for using Oracle)等等。
并这样配置:
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
第三:
指定前缀
org.quartz.jobStore.tablePrefix = QRTZ_
第四:
指定数据源名称:
org.quartz.jobStore.dataSource = myDS
第五:定义ConnectionProvider的实现类
这里我找了一下,quartz提供了一个org.quartz.utils.PoolingConnectionProvider,于是,我就有了如下配置:
org.quartz.dataSource.myDS.connectionProvider.class:org.quartz.utils.PoolingConnectionProvider
第六:配置数据源属性
org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
org.quartz.dataSource.myDS.user: root
org.quartz.dataSource.myDS.password: root
org.quartz.dataSource.myDS.maxConnections = 30
完事,使用最简单的一个例子来跑跑,可是报错了……
Caused by: java.lang.InstantiationException: org.quartz.utils.PoolingConnectionProvider
at java.lang.Class.newInstance(Unknown Source)
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:936)
... 3 more
跟了一下源码得到详细一点的原因:
ConnectionProvider cp = null;
try {
cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();
} catch (Exception e) {
initException = new SchedulerException("ConnectionProvider class '" + cpClass
+ "' could not be instantiated.", e);
throw initException;
}
红色那行报的:
org.eclipse.debug.core.DebugException: com.sun.jdi.ClassNotLoadedException: Type has not been loaded occurred while retrieving component type of array.
百度了一把,没什么收获,看看文档,只说定义自己的这个类,但是为啥,也没有代码,为什么不告诉直接用上述的那个provider呢?
直接测试一下loadclass("org.quartz.utils.PoolingConnectionProvider");是没有问题的,那就是newInstance();的时候有问题咯。靠谱的还是JDK文档,立马去看一下,果然有收获:创建此Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new
表达式实例化该类。如果该类尚未初始化,则初始化这个类。
如同空参数……
肯定是那个provider没有提供无参构造……再去看看呢,果然没有,好吧,我承认我懒了那么一丢丢。
那我再找找有没有其他的用于设置这个的吧,居然没有找到(估计没有找仔细),还是得定义一个自己的provider,没事,就参考这个provider,还是用C3P0来定义呗。
定义好后,来试试,果然顶用。以下是我的可运行代码:
quartz.properties
- # Default Properties file for use by StdSchedulerFactory
- # to create a Quartz Scheduler Instance, if a different
- # properties file is not explicitly specified.
- #
- org.quartz.scheduler.instanceName: DefaultQuartzScheduler
- org.quartz.scheduler.rmi.export: false
- org.quartz.scheduler.rmi.proxy: false
- org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
- org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
- org.quartz.threadPool.threadCount: 10
- org.quartz.threadPool.threadPriority: 5
- org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: false
- org.quartz.jobStore.misfireThreshold: 60000
- org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
- org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
- org.quartz.jobStore.tablePrefix: QRTZ_
- org.quartz.jobStore.dataSource: myDS
- org.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProvider
- org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
- org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
- org.quartz.dataSource.myDS.user: root
- org.quartz.dataSource.myDS.password: root
- org.quartz.dataSource.myDS.maxConnections: 30
MyPoolingconnectionProvider.java
- package org.quartz.examples.example17;
- import java.beans.PropertyVetoException;
- import java.sql.Connection;
- import java.sql.SQLException;
- import org.quartz.SchedulerException;
- import org.quartz.utils.ConnectionProvider;
- import com.mchange.v2.c3p0.ComboPooledDataSource;
- /**
- *
- * @author wz
- *
- */
- public class MyPoolingconnectionProvider implements ConnectionProvider {
- /** Default maximum number of database connections in the pool. */
- public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;
- /** Default maximum number of database connections in the pool. */
- public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;
- private String driver;
- private String url;
- private String user;
- private String password;
- private int maxConnections;
- private int maxCachedStatementsPerConnection;
- private int maxIdleSeconds;
- private String validationQuery;
- private int idleConnectionValidationSeconds;
- private boolean validateOnCheckout;
- private String discardIdleConnectionsSeconds;
- private ComboPooledDataSource datasource;
- /**
- * 无参构造,必须要有[没有其他构造的话也可以不写]
- */
- public MyPoolingconnectionProvider() {
- }
- public Connection getConnection() throws SQLException {
- return datasource.getConnection();
- }
- public void shutdown() throws SQLException {
- datasource.close();
- }
- /**
- * 初始化方法,应该在调用其setter后调用
- */
- public void initialize() throws SQLException {
- if (this.url == null) {
- throw new SQLException("DBPool could not be created: DB URL cannot be null");
- }
- if (this.driver == null) {
- throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");
- }
- if (this.maxConnections < 0) {
- throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");
- }
- datasource = new ComboPooledDataSource();
- try {
- datasource.setDriverClass(this.driver);
- } catch (PropertyVetoException e) {
- try {
- throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);
- } catch (SchedulerException e1) {
- }
- }
- datasource.setJdbcUrl(this.url);
- datasource.setUser(this.user);
- datasource.setPassword(this.password);
- datasource.setMaxPoolSize(this.maxConnections);
- datasource.setMinPoolSize(1);
- datasource.setMaxIdleTime(maxIdleSeconds);
- datasource.setMaxStatementsPerConnection(this.maxCachedStatementsPerConnection);
- if (this.validationQuery != null) {
- datasource.setPreferredTestQuery(this.validationQuery);
- if (!validateOnCheckout)
- datasource.setTestConnectionOnCheckin(true);
- else
- datasource.setTestConnectionOnCheckout(true);
- datasource.setIdleConnectionTestPeriod(this.idleConnectionValidationSeconds);
- }
- }
- /*-------------------------------------------------
- *
- * setters 如果有必要,你可以添加一些getter
- * ------------------------------------------------
- */
- public void setDriver(String driver) {
- this.driver = driver;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public void setUser(String user) {
- this.user = user;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public void setMaxConnections(int maxConnections) {
- this.maxConnections = maxConnections;
- }
- public void setMaxCachedStatementsPerConnection(int maxCachedStatementsPerConnection) {
- this.maxCachedStatementsPerConnection = maxCachedStatementsPerConnection;
- }
- public void setMaxIdleSeconds(int maxIdleSeconds) {
- this.maxIdleSeconds = maxIdleSeconds;
- }
- public void setValidationQuery(String validationQuery) {
- this.validationQuery = validationQuery;
- }
- public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {
- this.idleConnectionValidationSeconds = idleConnectionValidationSeconds;
- }
- public void setValidateOnCheckout(boolean validateOnCheckout) {
- this.validateOnCheckout = validateOnCheckout;
- }
- public void setDiscardIdleConnectionsSeconds(String discardIdleConnectionsSeconds) {
- this.discardIdleConnectionsSeconds = discardIdleConnectionsSeconds;
- }
- public void setDatasource(ComboPooledDataSource datasource) {
- this.datasource = datasource;
- }
- protected ComboPooledDataSource getDataSource() {
- return datasource;
- }
- }
SimpleExample.java
- package org.quartz.examples.example17;
- import java.util.Date;
- import org.quartz.DateBuilder;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerFactory;
- import org.quartz.TriggerBuilder;
- import org.quartz.impl.StdSchedulerFactory;
- import org.quartz.impl.triggers.SimpleTriggerImpl;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class SimpleExample
- {
- public void run()
- throws Exception
- {
- Logger log = LoggerFactory.getLogger(SimpleExample.class);
- log.info("------- Initializing ----------------------");
- //通过调度器工厂获取调度器,初始化工程时须指定其使用我们自己的配置文件
- SchedulerFactory sf = new StdSchedulerFactory("org/quartz/examples/example17/quartz.properties");
- Scheduler sched = sf.getScheduler();
- //这儿clear一下,因为使用数据库储存方式时,shutdown的时候没有清除,第二次运行会报Job is already exist
- sched.clear();
- log.info("------- Initialization Complete -----------");
- Date runTime = DateBuilder.evenMinuteDate(new Date());
- log.info("------- Scheduling Job -------------------");
- //创建任务详情
- JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
- //创建触发器
- SimpleTriggerImpl trigger = (SimpleTriggerImpl)TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(new Date()).build();
- trigger.setRepeatCount(5);
- trigger.setRepeatInterval(3000);
- log.info("------- Starttime = "+trigger.getStartTime()+" -----------------");
- //调度器、触发器、任务,三者关联
- sched.scheduleJob(job, trigger);
- log.info(job.getKey() + " will run at: " + runTime);
- //调度启动
- sched.start();
- log.info("------- Started Scheduler -----------------");
- log.info("------- Waiting 1 minute... -------------");
- try
- {
- Thread.sleep(60000L);
- }
- catch (Exception e)
- {
- }
- log.info("------- Shutting Down ---------------------");
- //调度关闭
- sched.shutdown(true);
- log.info("------- Shutdown Complete -----------------");
- }
- public static void main(String[] args) throws Exception
- {
- SimpleExample example = new SimpleExample();
- example.run();
- }
- }
当然,运行example之前,得先添加mysql的driver的包,然后在mysql里建立一个叫“quartz”的database,并将 docs/dbTables下的tables_mysql.sql脚本运行一下以建表。
注意:
1) org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX,这个配置在这儿当然是用这个,
而org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate则根据你的数据,通常使用当前这个,如果这个不适用就去quartz里org.quar.impl.jdbcjobstore包或其子包下找找,如还是未能满足需求,就自己实现一个。
2) org.quartz.jobStore.tablePrefix: QRTZ_,这个是quartz默认的,tables_mysql.sql以及一些其他操作(比如clear等)的代码都这样写了,所以就不要去修改了。
3) org.quartz.jobStore.dataSource: myDS这个的“键”必须是org.quartz.jobStore.dataSource,而“值”随你取,但必须有。
4) dataSource的属性配置,如下几个(可以自己添加其他的对应修改provider):
- org.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProvider
- org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
- org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
- org.quartz.dataSource.myDS.user: root
- org.quartz.dataSource.myDS.password: root
- org.quartz.dataSource.myDS.maxConnections: 30
- org.quartz.dataSource."+yourdatasourcename+"."+yourProvider#datamembername
- String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);
- for (int i = 0; i < dsNames.length; i++) {
- PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(
- PROP_DATASOURCE_PREFIX + "." + dsNames[i], true));
- String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);
- // custom connectionProvider...
- if(cpClass != null) {
- ConnectionProvider cp = null;
- try {
- cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();
- } catch (Exception e) {
- initException = new SchedulerException("ConnectionProvider class '" + cpClass
- + "' could not be instantiated.", e);
- throw initException;
- }
- try {
- // remove the class name, so it isn't attempted to be set
- pp.getUnderlyingProperties().remove(
- PROP_CONNECTION_PROVIDER_CLASS);
- setBeanProps(cp, pp.getUnderlyingProperties());
- cp.initialize();
- } catch (Exception e) {
- initException = new SchedulerException("ConnectionProvider class '" + cpClass
- + "' props could not be configured.", e);
- throw initException;
- }
- dbMgr = DBConnectionManager.getInstance();
- dbMgr.addConnectionProvider(dsNames[i], cp);
- }