Foreword
In order to ensure high availability and high concurrency applications, usually deploy multiple nodes; for regular tasks, if each node to perform their regular tasks, while consuming system resources,
On the other hand some tasks multiple times, may lead to application logic issues, so they need a distributed scheduling system to coordinate each node to perform regular tasks.
Spring Quartz integration
Quartz is a sophisticated task scheduling system, Spring of Quartz made compatible for easy development, the following specific look at how to integrate:
1.Maven dependent files
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.29</version> </dependency> </dependencies>
Mainly Spring related libraries, quartz and mysql database driver library, NOTE: distributed scheduling needs a database, where the choice of mysql;
2. Configure job
It provides two ways to configure job, namely: MethodInvokingJobDetailFactoryBean and JobDetailFactoryBean
2.1MethodInvokingJobDetailFactoryBean
To call a specific a method used when the bean, the specific configuration is as follows:
<bean id="firstTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="firstService" /> <property name="targetMethod" value="service" /> </bea>
2.2JobDetailFactoryBean
This approach is more flexible and can pass parameters set as follows:
<bean id="firstTask" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="zh.maven.SQuartz.task.FirstTask" /> <property name="jobDataMap"> <map> <entry key="firstService" value-ref="firstService" /> </map> </property> </bean>
jobClass defined task classes, inheritance QuartzJobBean, implement a method executeInternal; JobDataMap used to transfer data to the job
3. triggers used to configure the scheduler
Also it offers two types of triggers: SimpleTriggerFactoryBean and CronTriggerFactoryBean
Look at the focus CronTriggerFactoryBean, this type is more flexible, as follows:
<bean id="firstCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="firstTask" /> <property name="cronExpression" value="0/5 * * ? * *" /> </bean>
jobDetail configuration is specified in step 2 job, cronExpression arranged Job performed once every 5 seconds;
4. Quartz scheduler configured SchedulerFactoryBean
Also provides two ways: memory RAMJobStore and database mode
4.1 Memory RAMJobStore
job-related information is stored in memory, each node stores a respective, mutually isolated, configured as follows:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="firstCronTrigger" /> </list> </property> </bean>
4.2 database mode
The job information stored in the database, a common database for all the nodes, each node communicate via a database, at the same time to ensure that a job will be executed on one node, and
If a node hang, Job will be assigned to the other node to perform the specific configuration is as follows:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/quartz" /> <property name="user" value="root" /> <property name="password" value="root" /> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:quartz.properties" /> <property name="triggers"> <list> <ref bean="firstCronTrigger" /> </list> </property> </bean>
dataSource source for configuration data, information related to data tables, may be downloaded to the official website gz package, sql file path: \ at dbTables docs, which provides a mainstream sql file database;
configLocation quartz.properties file configured under the quartz.jar org.quartz package, which provides some default data, such as org.quartz.jobStore.class
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
It should be quartz.properties copy out to make some changes, specific changes are as follows:
org.quartz.scheduler.instanceId: AUTO org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.isClustered: true org.quartz.jobStore.clusterCheckinInterval: 1000
5. Class
public class FirstTask extends QuartzJobBean { private FirstService firstService; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { firstService.service(); } public void setFirstService(FirstService firstService) { this.firstService = firstService; } }
FirstTask inheritance QuartzJobBean, achieve executeInternal method, call FirstService
public class FirstService implements Serializable { private static final long serialVersionUID = 1L; public void service() { System.out.println(new SimpleDateFormat("YYYYMMdd HH:mm:ss").format(new Date()) + "---start FirstService"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(new SimpleDateFormat("YYYYMMdd HH:mm:ss").format(new Date()) + "---end FirstService"); } }
FirstService desirable to provide serial interfaces, because of the need to save in a database;
public class App { public static void main(String[] args) { AbstractApplicationContext context = new ClassPathXmlApplicationContext("quartz.xml"); } }
Class is used to load the main quartz profile;
Testing distributed scheduling
1. Start App while twice observed logs:
20180405 14:48:10---start FirstService 20180405 14:48:12---end FirstService 20180405 14:48:15---start FirstService 20180405 14:48:17---end FirstService
Wherein A1, log output, A2 no; When stopped A1, A2 have a log output;
2. Add a new job are new: SecondTask and SecondService, while adding the relevant configuration file, start the App twice observed logs:
A1日志如下:
20180405 15:03:15---start FirstService 20180405 15:03:15---start SecondService 20180405 15:03:17---end FirstService 20180405 15:03:17---end SecondService 20180405 15:03:20---start FirstService 20180405 15:03:22---end FirstService 20180405 15:03:25---start FirstService 20180405 15:03:27---end FirstService
A2日志如下:
20180405 15:03:20---start SecondService 20180405 15:03:22---end SecondService 20180405 15:03:25---start SecondService 20180405 15:03:27---end SecondService
Can be found in A1 and A2 have a mission, but only in the same task at the same time a node to perform, and there may only be assigned to other nodes after the end of execution;
3. If the time interval is less than the execution time of the task, such as here into sleep (6000)
A1日志如下:
20180405 15:14:40---start FirstService 20180405 15:14:45---start FirstService 20180405 15:14:46---end FirstService 20180405 15:14:50---start FirstService 20180405 15:14:50---start SecondService 20180405 15:14:51---end FirstService
A2日志如下:
20180405 15:14:40---start SecondService 20180405 15:14:45---start SecondService 20180405 15:14:46---end SecondService 20180405 15:14:51---end SecondService
Interval time is 5 seconds, 6 seconds and task execution, observation logs can be found, the task is not over, has started a new job, this may lead to the application of logical problems, in fact, the task can not support serial issues;
4. @ DisallowConcurrentExecution annotation task to ensure the serial
In the Add FirstTask and SecondTask respectively @DisallowConcurrentExecution annotation log results are as follows:
A1日志如下:
20180405 15:32:45---start FirstService 20180405 15:32:51---end FirstService 20180405 15:32:51---start FirstService 20180405 15:32:51---start SecondService 20180405 15:32:57---end FirstService 20180405 15:32:57---end SecondService 20180405 15:32:57---start FirstService 20180405 15:32:57---start SecondService
A2日志如下:
20180405 15:32:45---start SecondService
20180405 15:32:51---end SecondService
Observe the log can be found only in the task after the end, we will start a new task, to achieve a serialization tasks;
to sum up
This paper aims Spring + Quartz distributed scheduling have an intuitive understanding, to solve the problem by actual use, of course, there may be a lot of questions such as how it is scheduling, database and so what would happen if hung up, needs to be done more in-depth understanding.
https://mp.weixin.qq.com/s/vkvYJnKfQyuUeD_BDQy_1g
For more learning materials, can be added to the group: 473 984 645 or under the Fanger Wei code scanning