任务调度概述

作者: 墨迹嘿嘿 | 来源:发表于2019-01-21 22:10 被阅读5次

    在企业级应用当中,经常会绘制一些“任务计划”,即在某个时间点做某点事情,比如:在用户没有使用软件3个月的时候发送短信,召回沉默客户;在早上一点的时候对数据进行同步处理;在早上三点的时候对昨天的营业额进行统计汇总;凌晨十二点半统计某个互联网金融公司借款APP前一天的借款,还款以及逾期情况等等;核心是以时间为关注点,系统固定时间制定执行一个任务,任务调度涉及多线程并发,线程池维护,运行时间规则解析,运行现场的保护以及恢复等方面。Quartz框架是一个开源级任务调度服务,已被作为任务调度的良好解决方案

    Quartz框架核心概念

    image
    Job:

    是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中

    JobDetail:

    Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。

    Trigger:

    是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;

    Calendar:

    org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。

    Scheduler:

    代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

    Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例;
    ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

    为什么不简单的使用java.util.Timer就行了呢?
    从JDK1.3开始,Java通过java.util.Timer和java.util.TimerTask可以实现定时器。为什么要使用Quartz而不是使用Java中的这些标准功能呢?

    原因太多了,这里列举几个:
    Timers没有持久化机制.
    Timers不灵活 (只可以设置开始时间和重复间隔,不是基于时间、日期、天等(秒、分、时)的)
    Timers 不能利用线程池,一个timer一个线程
    Timers没有真正的管理计划

    Quartz框架的使用流程

    3.1:首先了解一下Quartz使用的Jar包

    <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.3</version>
    </dependency>
    

    3.2:现在建立spring-quartz 的项目结构,建立一个Job的项目,结构如图所示:

    image

    首先我们建立一个测试类名为TestController

    public class TestController {
        public void execute1(){
            System.out.println("我被调用了========================");
        }
    }
    

    然后在pom文件中引入Quartz的Jar包

    <!-- 任务调度 -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.3</version>
    </dependency>
    

    在resource中建立applicationContext-secheduler.xml

    image.gif
    <?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:task="http://www.springframework.org/schema/task"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                             http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
    
       <!-- 定时job(每分钟执行一次) -->
       <bean id="testController" class="com.supermap.mds.job.web.controller.TestController" />
       <task:scheduled-tasks>
          <task:scheduled ref="testController" method="execute1" cron="0 0/1 * * * ?"/>
       </task:scheduled-tasks>
    
    </beans>
    

    在web.xml中添加spring的配置信息

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
    
        <!-- 强制进行转码 -->
        <filter>
            <filter-name>CharacterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>CharacterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
    
        <!-- 默认的spring配置文件是在WEB-INF下的applicationContext.xml -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath*:applicationContext*.xml
            </param-value>
        </context-param>
    
        <!-- 日志配置文件 -->
        <context-param>
            <param-name>log4jConfigLocation</param-name>
            <param-value>classpath:log4j.properties</param-value>
        </context-param>
    
        <!-- springMVC的核心控制器 -->
        <servlet>
            <servlet-name>springMVC</servlet-name>
            <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value> classpath*:springMVC-servlet.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!-- 欢迎页面 -->
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    
        <!-- 错误页面 -->
        <error-page>
            <error-code>403</error-code>
            <location>/WEB-INF/jsp/403.jsp</location>
        </error-page>
        <error-page>
            <error-code>404</error-code>
            <location>/WEB-INF/jsp/404.jsp</location>
        </error-page>
        <error-page>
            <error-code>500</error-code>
            <location>/WEB-INF/jsp/500.jsp</location>
        </error-page>
        <error-page>
            <exception-type>java.lang.Throwable</exception-type>
            <location>/WEB-INF/jsp/error.jsp</location>
        </error-page>
    </web-app>
    

    启动项目:

    image.gif

    一分钟后:

    image

    两分钟后:

    image

    Cron表达式

    要使用CronTrigger,必须掌握Cron表达式

    Cron表达式由6~7个由空格分隔的时间元素组成。第7个元素可选

    image
    Cron表达式有几个特殊的字符,说明如下:
    image
    Cron表达式案例:
    image image
    1.jpg

    相关文章

      网友评论

        本文标题:任务调度概述

        本文链接:https://www.haomeiwen.com/subject/kuahjqtx.html