Spring integrates Quartz framework timing tasks

   The integration application of queues, timed tasks and threads is often used in recent projects. The scenario involved is how to reduce server pressure and handle business needs when multiple people access the system and need to call back the processing results of the client system. Here, the queue reduction server is used. The pressure is added to the timing task sending mechanism, using the spring framework to integrate the timing tasks implemented by the Quartz framework, so I learned about the causes and consequences of Quartz and recorded it here.

1. Introduction

      Have you ever needed an app to perform a task? This task is executed every day or every Tuesday at 11:30 pm, or maybe only on the last day of every month. If a fatal error occurs during the execution of a task that is executed automatically without intervention, can the application know that its execution failed and try to execute it again? Are you and your team programming in Java ? If you answered yes to any of these questions, then you should use the Quartz scheduler.

2. Why the R&D team chooses quartz

The open source job scheduling framework written in java is designed for easy integration of J2SE and J2EE applications.

Senior enough, founded in 1998, earlier than struts1, and has been updated (24 Sept 2013: Quartz 2.2.1 Released), complete documentation.

Clear and simple design: core concepts scheduler, trigger, job, jobDetail, listener, calendar 

Support for clustering: org.quartz.jobStore.isClustered The most important reason is that quartz supports clustering. Otherwise, JDK comes with Timer to achieve the same function.

Support task recovery: requestsRecovery 

The popularity is very wide, and JAVA developers are more familiar with it.

Apache2.0 open source agreement, allowing code modification and commercial release.

 

3. How to make the development of timed tasks convenient and easy to manage.


Alibaba's open source project easySchedule builds a simple management platform on the basis of quartz cluster. It solves the functions of visualization, easy configuration, and unified monitoring and alarming.
The separation of scheduling and execution is realized, so that the task no longer needs to pay attention to timing, and only needs to implement the task interface.
Schedule calls to execute tasks over HTTP.

easySchedule system features:

1. Server and Client support cluster and distributed deployment respectively

2. Separation of task execution and scheduling

3. Visually manage all tasks

4. The task status is persisted in DB

5. Perfect log tracking and alarm strategy

6. Tasks support asynchronous scheduling

7. Flexible support for various custom tasks, easy to expand

 

1. Job: It is an interface with only one method void execute(JobExecutionContext context). Developers implement this interface to define running tasks. The JobExecutionContext class provides various information about the scheduling context. Job runtime information is stored in the JobDataMap instance;

2. JobDetail: Quartz recreates a Job instance every time it executes a Job, so it does not directly accept a Job instance. Instead, it accepts a Job implementation class so that the job can be instantiated at runtime through the reflection mechanism of newInstance(). . Therefore, a class needs to be used to describe the implementation class of the Job and other related static information, such as the Job name, description, associated listeners and other information. JobDetail assumes this role.

3. Trigger: is a class that describes the time triggering rules that trigger Job execution. There are mainly two subclasses of SimpleTrigger and CronTrigger. When it only needs to be triggered once or executed at a fixed time interval, SimpleTrigger is the most suitable choice; while CronTrigger can define scheduling schemes for various complex time rules through Cron expressions: such as execution at 9:00 every morning, Monday, Wednesday , Friday at 5:00 pm, etc.;

4. Calendar: org.quartz.Calendar is different from java.util.Calendar, it is a collection of some calendar specific time points (you can simply think of org.quartz.Calendar as a collection of java.util.Calendar - java.util .Calendar represents a calendar time point, without special instructions, the following Calendar refers to org.quartz.Calendar). A Trigger can be associated with multiple Calendars to exclude or include certain points in time. Suppose we schedule the task to be executed every Monday at 10:00 am, but if there is a legal holiday, the task will not be executed. At this time, we need to use Calendar to perform fixed-point exclusion based on the Trigger triggering mechanism.

5. Scheduler: represents an independent running container of Quartz. Trigger and JobDetail can be registered in Scheduler. Both have their own groups and names in Scheduler. Groups and names are the basis for Scheduler to locate an object in the container. Trigger's The group and name must be unique, as should the group and name of the JobDetail (but can be the same as the group and name of the Trigger, since they are of different types). Scheduler defines a number of interface methods, allowing external access and control of Trigger and JobDetail in the container by group and name.

 6. The Scheduler can bind the Trigger to a JobDetail, so that when the Trigger is triggered, the corresponding Job will be executed. A Job can correspond to multiple Triggers, but a Trigger can only correspond to one Job. A Scheduler instance can be created through SchedulerFactory. The Scheduler has a SchedulerContext, which is similar to the ServletContext and holds the Scheduler context information. Both Job and Trigger can access the information in the SchedulerContext. SchedulerContext maintains these context data in the form of key-value pairs through a Map internally. SchedulerContext provides multiple put() and getXxx() methods for saving and obtaining data. You can get the corresponding SchedulerContext instance through Scheduler# getContext();

7. ThreadPool: Scheduler uses a thread pool as the infrastructure for task running, and tasks improve operating efficiency by sharing threads in the thread pool.

 

Quartz Internal Architecture

  In terms of scale, Quartz is similar to most open source frameworks. There are about 300 Java classes and interfaces organized into 12 packages. This is comparable to Apache Struts, which organizes about 325 classes and interfaces into 11 packages. While scale is rarely used as a feature to measure the quality of a framework, the key here is that quarts contain a lot of functionality, and whether those functionality and feature sets are, or should be, factors in judging the quality of an open source or non-open source framework.

Quartz Scheduler

At the heart of the Quartz framework is the scheduler. The scheduler is responsible for managing the Quartz application runtime environment. Instead of doing all the work on its own, the scheduler relies on some very important parts of the framework. Quartz is more than just threads and thread management. To ensure scalability, Quartz uses a multi-threaded architecture .

  At startup, the framework initializes a set of worker threads that are used by the scheduler to perform scheduled jobs. This is how Quartz can run multiple jobs concurrently. Quartz relies on a set of loosely coupled thread pool management components to manage the threading environment. In this article, we will refer to thread pool management several times, but every object in Quartz is configurable or customizable. So, for example, if you want to plug in your own thread pool management facilities, I guess you can!

Jobs and Triggers

The Quartz designers made a design choice to separate jobs from scheduling. Triggers in Quartz are used to tell the scheduler when a job should fire. The framework provides a handful of trigger types, but the two most commonly used are SimpleTrigger and CronTrigger. SimpleTrigger is designed for simple spark scheduling.

  Typically, if you need to fire a job for a given time and number of repetitions or seconds to wait between firings, SimpleTrigger is for you. On the other hand, if you have many complex job schedulers, then CronTrigger might be needed.

 

Cron expressions

CronTrigger is based on Calendar-like scheduling. CronTrigger should be used when you need to execute a job at 10:30 am every day except Saturday and Sunday. As its name suggests, CronTrigger is based on Unix clone expressions.

  As an example, the following Quartz clone expression will execute a job at 10:15 am every Monday through Friday.

0 15 10 ? * MON-FRI

the following expression

0 15 10 ? * 6L 2002-2005

  The assignment will be executed at 10:15 am on the last Friday of each month from 2002 to 2005. You can't do these things with SimpleTrigger. You can use either, but which one is appropriate depends on your scheduling needs.

 

Quartz has two major triggers, in addition to the SimpleTrigger used above, the CronTrigger. CronTrigger can provide support for complex trigger expressions. CronTrigger is based on the Unix Cron daemon, which is a scheduler that supports a simple yet powerful trigger syntax.
 
The main thing to use CronTrigger is to master Cron expressions. Cron expressions contain 6 required components and one optional component, as shown in the following table.


Meaning of special characters


Cron expression example:
 
"30 * * * * ?" triggers the task every half minute
"30 10 * * * ?" triggers the task every hour at 10 minutes and 30 seconds
"30 10 1 * * ?" triggers the task at 1:10:30 every day
"30 10 1 20 * ?" Trigger the task at 1:10:30 on the 20th of every month
"30 10 1 20 10 ? *" Every year on October 20th at 1:10:30 to trigger the task
"30 10 1 20 10 ? 2011" 1:10:30 on October 20, 2011 to trigger the task
"30 10 1 ? 10 * 2011" The task is triggered at 1:10:30 every day in October 2011
"30 10 1 ? 10 SUN 2011" Trigger the task every Sunday at 1:10:30 in October 2011
"15,30,45 * * * * ?" Trigger the task every 15 seconds, 30 seconds, 45 seconds
"15-45 * * * * ?" 15 to 45 seconds, trigger the task every second
"15/5 * * * * ?" triggers every 15 seconds of every minute and every 5 seconds
"15-30/5 * * * * ?" triggers every minute between 15 and 30 seconds, every 5 seconds
"0 0/3 * * * ?" starts at the 0th minute and 0th second of every hour and fires every three minutes
"0 15 10 ? * MON-FRI" triggers the task at 10:15:00 from Monday to Friday
"0 15 10 L * ?" triggers the task at 10:15:00 on the last day of each month
"0 15 10 LW * ?" triggers the task at 10:15:00 on the last working day of every month
"0 15 10 ? * 5L" triggers the task at 10:15:00 on the last Thursday of every month
"0 15 10 ? * 5#3" Trigger the task at 10:15:00 on Thursday of the third week of each month
 

miss fire

Trigger also has an important attribute misfire; if the scheduler is closed, or there are no available threads in the Quartz thread pool to execute the job, the persistent trigger will miss its trigger time, that is, miss the trigger (misfire). Different types of triggers have different misfire mechanisms. They all use a " smart policy" by default , which dynamically adjusts behavior based on trigger type and configuration. When the scheduler starts, query all persistent triggers that miss fire. Then update the trigger information according to their respective misfire mechanisms. When you use Quartz in your project, you should be familiar with the misfire mechanism of various types of triggers, which are described in the JavaDoc. The details of the misfire mechanism will be introduced when the specific trigger is mentioned.

 

 5. Spring integrates Quartz

     There are two ways of timed tasks. Spring encapsulates the details of Quartz very well. The first way is to use the Quartz class encapsulated by SPring to implement specific methods. The second way is to use Quartz transparently to achieve the purpose of timed task development. Say the second is more convenient for developers!

   Configuring Spring's task scheduling abstraction layer simplifies task scheduling and provides better scheduling objects on the basis of Quartz. Spring uses the Quartz framework to complete task scheduling and create a Quartz job bean (JobDetail). There are two methods:

   1: Use JobDetailBean to wrap an instance of a QuartzJobBean subclass (ie, the Job class).

   2: Use the MethodInvokingJobDetailFactoryBean factory Bean to wrap ordinary Java objects (ie, the Job class).

   Instructions:

      1: To use the first method to create a job class, you must inherit QuartzJobBean and implement the executeInternal(JobExecutionContext
jobexecutioncontext) method, which is the executor of the scheduled task, and then configure the instance of this Job class directly into the JobDetailBean . This approach is the same as in normal Quartz programming.

      2: Use the second method to create the Job class, without inheriting the parent class, directly configure the MethodInvokingJobDetailFactoryBean. But you need to specify the following two properties:

        targetObject: Specifies the Bean instance that contains the task executor.

        targetMethod: Specifies to wrap the method of the specified bean instance into the executor of the task. 

Here we introduce the second: directly on the code

package com.test.quartz;  

 

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Service;

 

@Service

public class QuartzJob  

{  

@Scheduled(cron="0/5 * * * * ? ")

    public void work()  

    {  

    System.out.println("Quartz task scheduling!!!");  

    }  

}  

 

 

 

   <listener>    

   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    

 </listener>    

 

    web.xml

<servlet>

<servlet-name>hello</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

 

<init-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>WEB-INF/applicationContext.xml</param-value>

    </init-param> 

</servlet> 

 

 

applicationContext.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"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:mvc="http://www.springframework.org/schema/mvc"

    xmlns:task="http://www.springframework.org/schema/task"    

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans 

        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

        http://www.springframework.org/schema/context 

        http://www.springframework.org/schema/context/spring-context-3.0.xsd

        http://www.springframework.org/schema/mvc 

        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

        http://www.springframework.org/schema/task            

        http://www.springframework.org/schema/task/spring-task-3.0.xsd"

          

        >

        <!-- component scan -->

        <context:component-scan base-package="com.test.controller,com.test.quartz"/>

        

         <task:executor id="executor" pool-size="5" />        

         <task:scheduler id="scheduler" pool-size="10" />      

         <task:annotation-driven executor="executor" scheduler="scheduler" />    

        

        

        <!-- Annotation driver-->

        <mvc:annotation-driven/>

        <!-- Map static resources -->

<mvc:resources mapping="/resources/**" location="/resources/" />

        <!-- Internal resource view resolver -->

        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <!-- It is used by the introduction of the jstl tag library. It is recommended to add it in the help document, and it should be added without it -->

        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

        <!-- prefix -->

        <property name="prefix" value="/WEB-INF/jsp/"/>

        <!-- suffix -->

        <property name="suffix" value=".jsp"/>

        </bean>

        

        

        

        

        

        

          <!-- Work class to call -->  

        <bean id="quartzJob" class="com.test.quartz.QuartzJob"></bean>  

        <!-- Define the calling object and the method of calling the object -->  

        <bean id="jobtask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  

            <!-- Called class -->  

            <property name="targetObject">  

                <ref bean="quartzJob"/>  

            </property>  

            <!-- call a method in the class -->  

            <property name="targetMethod">  

                <value>work</value>  

            </property>  

        </bean>  

        <!-- define trigger time-->  

        <bean id="doTime" class="org.springframework.scheduling.quartz.CronTriggerBean">  

            <property name="jobDetail">  

                <ref bean="jobtask"/>  

            </property>  

            <!-- cron expression-->  

            <property name="cronExpression">  

                <value>1,5,10,15,20,25,30,35,40,45,50,55 * * * * ?</value>  

            </property>  

        </bean>  

        

        <!-- If the general management class sets lazy-init='false', the scheduler will be executed when the container starts -->  

        <bean id="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  

            <property name="triggers">  

                <list>  

                    <ref bean="doTime"/>  

                </list>  

            </property>  

        </bean>  

        

 

        

        <!-- Global exception configuration-->

        <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

        <!-- Inject Properties -->

        <property name="exceptionMappings">

        <props>

        <!-- error is a jsp page -->

        <prop key="com.test.exception.UserException">error</prop>

        </props>

        </property>

        </bean>

        

        

        <!-- File upload resolver, id must be multipartResolver-->

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<!-- Set the maximum upload 5M -->

<property name="maxUploadSize" value="5000000" />

</bean>

 

 

 

 

</beans>

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326264264&siteId=291194637