Quartz+Spring 分布式定时任务调度(二)- 集群配置

写的不好的地方请大家多多指正

      上一篇讲解的环境的搭建,接着我们继续来讲集群,quartz的集群配置是在quartz.properties文件中,我们来修改一下quartz.properties 文件:

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# 调度器实例的名字,使用默认的DefaultQuartzScheduler就好
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
# 调度器实例的ID, 选择AUTO
org.quartz.scheduler.instanceId:AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
# 跳过更新检查
org.quartz.scheduler.skipUpdateCheck:true
# 配置线程池
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#
# quartz默认的是将job信息存储在内存中,quartz集群必须将job信息持久化到数据库中
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold:60000
############
org.quartz.jobStore.useProperties:true
#quartz数据表的前缀,quartz的数据表在 quartz-2.2.3\docs\dbTables 文件夹中,
#选择对应的数据库版本,将数据库创建出来
org.quartz.jobStore.tablePrefix:QRTZ_
# 最关键的  是否支持集群 选择true
org.quartz.jobStore.isClustered:true
org.quartz.jobStore.clusterCheckinInterval:15000
# dataSource
#org.quartz.jobStore.dataSource:myDS
#org.quartz.dataSource.myDS.connectionProvider.class:com.abc.util.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: 10

quartz.properties 配置完成,注意事项就是,需要创建数据库(推荐大家还是去官网下载quartz的包)。

这个配置文件中我将数据库连接的配置注释掉了,因为如果要在这里配置数据库连接的话,需要一个数据库连接的类,quartz本身的数据库连接类是有bug的,需要我们自己写一个数据库连接池的类 。就是这行配置:

org.quartz.dataSource.myDS.connectionProvider.class:com.abc.util.MyPoolingconnectionProvider

MyPoolingconnectionProvider.java 是安利的别人的,会在文章末尾贴出。
所以我不建议在quartz的配置文件中配置数据库连接,最好将数据库的连接配置放到Spring的配置文件中:


 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
        <property name="driverClass">  
            <value>com.mysql.jdbc.Drivervalue>  
        property>  
        <property name="jdbcUrl">  
            <value>jdbc:mysql://localhost:3306/quartzvalue>  
        property>  
        <property name="user">  
            <value>rootvalue>  
        property>  
        <property name="password">  
            <value>rootvalue>  
        property>  
        <property name="maxPoolSize">  
            <value>20value>  
        property>  
        <property name="minPoolSize">  
            <value>2value>  
        property>  
        <property name="initialPoolSize">  
            <value>2value>  
        property>  
        <property name="maxIdleTime">  
            <value>20value>  
        property>  
    bean>  

    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="configLocation" value="classpath:/quartz.properties" />
        <property name="dataSource" ref="dataSource" />
        
        <property name="overwriteExistingJobs" value="true" />
        
        <property name="jobFactory">
            <bean class="com.abc.util.JobFacotry" />
        property>
       
        <property name="startupDelay" value="1"/>
    bean>

       上面还有一个需要注意的地方就是,SchedulerFactoryBean 配置configLocation后,会覆盖quartz本身的配置文件,然后使用我们自定义的配置文件(就是我们修改好的那份)。
       配置jobFactory的作用主要是为了在job任务类中可以注入其他的属性,如果不配置的话,job任务类中的属性将无法注入成功。JobFacotry.java也会在文章末尾贴出。


到了这里,quartz的集群配置已经完成,下一步就可以自己写job类,然后来调用了。

1.自定义Job类

这里写图片描述 自定义三个JobTest类,需要实现Quartz的Job接口。

Quartz+Spring 分布式定时任务调度(二)- 集群配置_第1张图片

2.创建Quartz 工具类

       Quartz工具类的作用就是用来将 任务和 触发器 添加到 调度器中,从而执行调度工作;

public class QuartzUtil {
    // 将配置文件中定义的SchedulerFactoryBean 注入到工具类中 
    @Autowired
    @Qualifier("scheduler")
    private Scheduler scheduler;

    public void addJob(String name, String group, Classextends Job> clazz,String cronExpression) {                 
        try {       
            //构造任务
            JobDetail job = newJob(clazz)
                    .withIdentity(name, group)                  
                    .build();

            //构造任务触发器
            Trigger trg = newTrigger()
                    .withIdentity(name, group)
                    .withSchedule(cronSchedule(cronExpression))
                    .build();      

            //将作业添加到调度器
            scheduler.scheduleJob(job, trg);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

}

该工具类,这里我只写了最简单的添加,关于移除,修改等更多的操作,请看这里

关于Cron表达式,请移步

3.工具类的使用

        QuartzUtil创建完成之后,就可以通过SpringMVC进行调用了。

创建页面:
Quartz+Spring 分布式定时任务调度(二)- 集群配置_第2张图片

创建Controller:

@Controller
@RequestMapping("show")
public class TestController {

    @Autowired
    @Qualifier("quartz")
    private QuartzUtil quartz;

    @RequestMapping(value="quartz")
    public String quartz(){

        return "quartz";
    }

    @RequestMapping(value="start")
    public void start(){
        quartz.start();
    }

    @RequestMapping(value="newA")
    public void newA(){
        quartz.schedJob("jobA", null, com.abc.job.JobTest1.class, "*/3 * * * * ?");
    }

    @RequestMapping(value="modifyA")
    public void modifyA(){
        quartz.modifyTime("jobA", null, "*/5 * * * * ?");
    }

    @RequestMapping(value="removeA")
    public void removeA(){
        quartz.removeJob("jobA", null);
    }
}

篇幅的原因,controller 做了省略,其他的直接调用QuartzUtil里面的方法即可。

全部完成之后,就可以将项目放在Tomcat上,运行成功后,便可以在Console中看到结果。

Quartz+Spring 分布式定时任务调度(二)- 集群配置_第3张图片

当然这个只是单个Tomcat节点,我们可以将项目打包,放在多个Tomcat下运行,Quartz自己实现了负载均衡和容错,当你的某一个tomcat挂掉之后,任务会在别的tomcat节点运行。接下来的内容大家可以自行测试!

小结:
      Quartz集群配置注意的事项就是
1. 首先将Job信息实例化至数据库,所以需要Quartz的Sql文件来创建数据库(sql文件在quartz的包中 quartz-x.x.x \docs\dbTables 文件夹)。
2. 配置quartz.properties文件(可以在这里配置数据库连接,也可以在Spring的配置文件中配置)
3. 写QuartzUtil 类,实现任务调度。

//JobFacotry.java 
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;

public class JobFacotry extends AdaptableJobFactory{

  @Autowired
  private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle)
            throws Exception {

        Object jobInstance = super.createJobInstance(bundle);

        capableBeanFactory.autowireBean(jobInstance);

        return jobInstance;
    }
}
//MyPoolingconnectionProvider.java
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;  
    }  
}  

你可能感兴趣的:(九阳真经)