spring3+quartz1集群配置、分布式集群配置
2017-03-27 23:01
796 查看
spring3+quartz1集群配置、分布式集群配置
因为最近项目需要重复部署,而且保证quartz定时任务不会重复执行,所以需要是quartz支持分布式,查阅资料后发现,quartz本身支持基于数据库的集群配置。大功告成之后写博客分享记录。spring3quartz1集群配置分布式集群配置
大致流程
建表语句 tables_mysql_innodbsql
定义一个任务
webxml
quartzproperty
MyDetailQuartzJobBean
quartzxml
测试
大致流程
1.把 QUARTZ 的 TASK 实例化进数据库, QUARTZ 只有实例化进入数据库后才能做集群,把quartz-1.8.4/docs/dbTables/tables_mysql_innodb.sql(因为我的mysql是innodb引擎) 在 mysql 中执行一下会生成 12 张表;但是需要注意的是这个sql文件需要修改,直接执行会报错,我在这里提供了修改正确后的sql。2.生成 quartz.properties 文件,把它放在工程的 src 目录下,使其能够被编译时纳入 class path 。
3.自己实现反序列化类,在quartz.xml中指定此类和quartz.properties路径
4.配置quartz.xml
5.配置web.xml能够读取quartz.xml
6.测试
一般我们的开发人员都喜欢使用 SPRING+QUARTZ ,因此这个 quartz.properties 都不用怎么去写,但是在集群方案中 quartz.properties 必写,如果不写 quartz 会调用自身 jar 包中的 quartz.properties 作为默认属性文件,同时修改 quartz.xml 文件。
建表语句 tables_mysql_innodb.sql
DROP TABLE IF EXISTS QRTZ_JOB_LISTENERS; DROP TABLE IF EXISTS QRTZ_TRIGGER_LISTENERS; DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; DROP TABLE IF EXISTS QRTZ_LOCKS; DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; DROP TABLE IF EXISTS QRTZ_TRIGGERS; DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; DROP TABLE IF EXISTS QRTZ_CALENDARS; CREATE TABLE QRTZ_JOB_DETAILS( JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250) NULL, JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE VARCHAR(1) NOT NULL, IS_VOLATILE VARCHAR(1) NOT NULL, IS_STATEFUL VARCHAR(1) NOT NULL, REQUESTS_RECOVERY VARCHAR(1) NOT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (JOB_NAME,JOB_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_JOB_LISTENERS ( JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, JOB_LISTENER VARCHAR(200) NOT NULL, PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER), INDEX (JOB_NAME, JOB_GROUP), FOREIGN KEY (JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_TRIGGERS ( TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, IS_VOLATILE VARCHAR(1) NOT NULL, DESCRIPTION VARCHAR(250) NULL, NEXT_FIRE_TIME BIGINT(13) NULL, PREV_FIRE_TIME BIGINT(13) NULL, PRIORITY INTEGER NULL, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT(13) NOT NULL, END_TIME BIGINT(13) NULL, CALENDAR_NAME VARCHAR(200) NULL, MISFIRE_INSTR SMALLINT(2) NULL, JOB_DATA BLOB NULL, PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), INDEX (JOB_NAME, JOB_GROUP), FOREIGN KEY (JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, REPEAT_COUNT BIGINT(7) NOT NULL, REPEAT_INTERVAL BIGINT(12) NOT NULL, TIMES_TRIGGERED BIGINT(10) NOT NULL, PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), INDEX (TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_CRON_TRIGGERS ( TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, CRON_EXPRESSION VARCHAR(120) NOT NULL, TIME_ZONE_ID VARCHAR(80), PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), INDEX (TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_BLOB_TRIGGERS ( TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, BLOB_DATA BLOB NULL, PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), INDEX (TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_TRIGGER_LISTENERS ( TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, TRIGGER_LISTENER VARCHAR(200) NOT NULL, PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER), INDEX (TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_CALENDARS ( CALENDAR_NAME VARCHAR(200) NOT NULL, CALENDAR BLOB NOT NULL, PRIMARY KEY (CALENDAR_NAME)) engine=InnoDB; CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( TRIGGER_GROUP VARCHAR(200) NOT NULL, PRIMARY KEY (TRIGGER_GROUP)) engine=InnoDB; CREATE TABLE QRTZ_FIRED_TRIGGERS ( ENTRY_ID VARCHAR(95) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, IS_VOLATILE VARCHAR(1) NOT NULL, INSTANCE_NAME VARCHAR(200) NOT NULL, FIRED_TIME BIGINT(13) NOT NULL, PRIORITY INTEGER NOT NULL, STATE VARCHAR(16) NOT NULL, JOB_NAME VARCHAR(200) NULL, JOB_GROUP VARCHAR(200) NULL, IS_STATEFUL VARCHAR(1) NULL, REQUESTS_RECOVERY VARCHAR(1) NULL, PRIMARY KEY (ENTRY_ID)) engine=InnoDB; CREATE TABLE QRTZ_SCHEDULER_STATE ( INSTANCE_NAME VARCHAR(200) NOT NULL, LAST_CHECKIN_TIME BIGINT(13) NOT NULL, CHECKIN_INTERVAL BIGINT(13) NOT NULL, PRIMARY KEY (INSTANCE_NAME)) engine=InnoDB; CREATE TABLE QRTZ_LOCKS ( LOCK_NAME VARCHAR(40) NOT NULL, PRIMARY KEY (LOCK_NAME)) engine=InnoDB; INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS'); INSERT INTO QRTZ_LOCKS values('JOB_ACCESS'); INSERT INTO QRTZ_LOCKS values('CALENDAR_ACCESS'); INSERT INTO QRTZ_LOCKS values('STATE_ACCESS'); INSERT INTO QRTZ_LOCKS values('MISFIRE_ACCESS'); commit;
定义一个任务
public class OrderTaskPrimary { protected void execute() { System.out.println("gogogogo!!!!!!"); } }
web.xml
添加如下配置,使其启动时读取quartz.xml<servlet> <servlet-name>annomvcZrongPipe</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application-servlet.xml classpath:quartz.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
quartz.property
注意:打开集群模式org.quartz.jobStore.isClustered = true
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName = EventScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX # mysql org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate # Oracle #org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.maxMisfiresToHandleAtATime=10 org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000
这个 MethodInvokingJobDetailFactoryBean 类中的 methodInvoking 方法,是不支持序列化的,因此在把 QUARTZ 的 TASK 序列化进入数据库时就会抛错。网上有说把 SPRING 源码拿来,修改一下这个方案,然后再打包成 SPRING.jar 发布,这些都是不好的方法,是不安全的。
必须根据 QuartzJobBean 来重写一个自己的类,然后使用 SPRING 把这个重写的类(我们就名命它为: MyDetailQuartzJobBean )注入 appContext 中后,再使用 AOP 技术反射出原有的 quartzJobx( 就是开发人员原来已经做好的用于执行 QUARTZ 的 JOB 的执行类 ) 。
MyDetailQuartzJobBean
import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; public class MyDetailQuartzJobBean extends QuartzJobBean { protected final Log logger = LogFactory.getLog(getClass()); private String targetObject; private String targetMethod; private ApplicationContext ctx; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { logger.info("execute [" + targetObject + "] at once>>>>>>"); Object otargetObject = ctx.getBean(targetObject); Method m = null; try { m = otargetObject.getClass().getMethod(targetMethod, new Class[] {JobExecutionContext.class}); m.invoke(otargetObject, new Object[] {context}); } catch (SecurityException e) { logger.error(e); } catch (NoSuchMethodException e) { logger.error(e); } } catch (Exception e) { throw new JobExecutionException(e); } } public void setApplicationContext(ApplicationContext applicationContext) { this.ctx = applicationContext; } public void setTargetObject(String targetObject) { this.targetObject = targetObject; } public void setTargetMethod(String targetMethod) { this.targetMethod = targetMethod; } }
quartz.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- =====================主扫描下单任务========================== --> <!-- 定义目标bean和bean中的方法 --> <bean id="Test" class="com.zr.pipe.quartz.OrderTaskPrimary" > </bean> <bean id="OrderTaskPrimaryQtzJobMethod" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass"> <value>com.zr.pipe.quartz.MyDetailQuartzJobBean</value> </property> <property name="jobDataAsMap"> <map> <entry key="targetObject" value="Test" /> <entry key="targetMethod" value="execute" /> </map> </property> </bean> <bean id="OrderTaskPrimaryCronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"> <ref bean="OrderTaskPrimaryQtzJobMethod" /> </property> <property name="cronExpression"> <value>0/5 * * * * ?</value> </property> </bean> <!-- ======================== 调度工厂 ======================== --> <!-- 总管理类如果将lazy-init='false'那么容器启动就会执行调度程序 --> <bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" > <property name="configLocation" value="classpath:quartz.properties" /> <property name="dataSource"> <ref bean="dataSource1" /> </property> <property name="applicationContextSchedulerContextKey" value="applicationContext" /> <property name="triggers"> <list> <ref local="OrderTaskPrimaryCronTriggerBean"/> </list> </property> </bean> </beans>
测试:
几个节点都带有 quartz 任务,此时只有一台 quartz 在运行,另几个节点上的 quartz 没有运行。此时手动 shutdown 那台运行 QUARTZ (在程序里加 system.out.println(“execute”), 运行 quartz 的那个节点在后台会打印 execute )的节点,过了 几 秒左右,另一个节点的 quartz 自动监测到了集群中运行着的 quartz 的 instance 已经 shutdown ,因此 quartz 集群会自动把任一台可用的 APP 上启动起一个 quartz job 的任务。
相关文章推荐
- Quartz+Spring 分布式定时任务调度(二)- 集群配置
- Spring中定时任务Quartz集群配置学习
- (4) Spring中定时任务Quartz集群配置学习
- Spring+quartz 实现定时任务job集群配置【原】
- Spring中定时器Quartz 集群配置
- quartz分布式集群部署并且可视化配置job定时任务
- 教你如何利用分布式的思想处理集群的参数配置信息——spring的configurer妙用
- quartz集群分布式(并发)部署解决方案-Spring
- Spring中定时任务Quartz集群配置学习
- quartz集群分布式(并发)部署解决方案-Spring
- dubbo2.5-spring4-mybastis3.2-springmvc4-mongodb3.4-redis3.2整合(十一)之 spring中定时器quartz的整合续集(Quartz集群配置)
- Spring&Quartz使用数据库集群配置(MySQL/SQLServer/Oracle)
- Spring集成quartz集群配置总结
- Quartz+Spring的集群配置
- quartz-scheduler集群分布式(并发)部署解决方案-Spring
- Spring3.2.0和Quartz1.8.6集群配置
- quartz集成spring下的集群配置
- Spring之——quartz的配置方式(集群与不集群)
- Spring中定时任务Quartz集群配置学习
- Spring整合Quartz定时任务 在集群、分布式系统中的应用