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

来源:互联网 发布:淘宝扣24分怎么办 编辑:程序博客网 时间:2024/04/30 15:13

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

      上一篇讲解的环境的搭建,接着我们继续来讲集群,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, 选择AUTOorg.quartz.scheduler.instanceId:AUTOorg.quartz.scheduler.rmi.export: falseorg.quartz.scheduler.rmi.proxy: false# 跳过更新检查org.quartz.scheduler.skipUpdateCheck:true# 配置线程池org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount: 10org.quartz.threadPool.threadPriority: 5org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true## quartz默认的是将job信息存储在内存中,quartz集群必须将job信息持久化到数据库中org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegateorg.quartz.jobStore.misfireThreshold:60000############org.quartz.jobStore.useProperties:true#quartz数据表的前缀,quartz的数据表在 quartz-2.2.3\docs\dbTables 文件夹中,#选择对应的数据库版本,将数据库创建出来org.quartz.jobStore.tablePrefix:QRTZ_# 最关键的  是否支持集群 选择trueorg.quartz.jobStore.isClustered:trueorg.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的配置文件中:

<!--放入 applicationContext.xml 中--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">          <property name="driverClass">              <value>com.mysql.jdbc.Driver</value>          </property>          <property name="jdbcUrl">              <value>jdbc:mysql://localhost:3306/quartz</value>          </property>          <property name="user">              <value>root</value>          </property>          <property name="password">              <value>root</value>          </property>          <property name="maxPoolSize">              <value>20</value>          </property>          <property name="minPoolSize">              <value>2</value>          </property>          <property name="initialPoolSize">              <value>2</value>          </property>          <property name="maxIdleTime">              <value>20</value>          </property>      </bean>      <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">        <property name="configLocation" value="classpath:/quartz.properties" />        <property name="dataSource" ref="dataSource" />        <!-- 如果这个覆盖配置为false,quratz启动以后将以数据库的数据为准,配置文件的修改不起作用。-->        <property name="overwriteExistingJobs" value="true" />        <!-- 为了在Job中进行属性的注入,所必需的类 -->        <property name="jobFactory">            <bean class="com.abc.util.JobFacotry" />        </property>       <!--<property name="autoStartup" value="false" />-->        <property name="startupDelay" value="1"/>    </bean>

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


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

1.自定义Job类

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

这里写图片描述

2.创建Quartz 工具类

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

public class QuartzUtil {    // 将配置文件中定义的SchedulerFactoryBean 注入到工具类中     @Autowired    @Qualifier("scheduler")    private Scheduler scheduler;    public void addJob(String name, String group, Class<? extends 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进行调用了。

创建页面:
这里写图片描述

创建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中看到结果。

这里写图片描述

当然这个只是单个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.javaimport 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;      }  }  
0 0
原创粉丝点击