项目ITP(七) javaWeb 整合 Quartz 实现动态调度 并且 持久化

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

Written In The Font

需要:

  1. 导入WEB-INF/lib/quartz-2.2.1.jar
  2. 然后数据库建相关表格,可以去quartz-2.2.1\docs\dbTables目录下找到对应的数据库表格.(我这边Mysql , 导入 tables_mysql.sql 即可)
  3. 配置quartz.properties
    #============================================================================
    # Configure Main Scheduler Properties  
    #============================================================================
    org.quartz.scheduler.instanceName: wmuitpScheduler
    org.quartz.scheduler.instanceId: AUTO
    
    org.quartz.scheduler.skipUpdateCheck: true
    
    
    #============================================================================
    # Configure ThreadPool  
    #============================================================================
    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
    org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    org.quartz.jobStore.useProperties=false
    org.quartz.jobStore.dataSource=myDS
    org.quartz.jobStore.tablePrefix=qrtz_
    org.quartz.jobStore.isClustered=true
    
    
    #============================================================================
    # Configure Datasources  
    #============================================================================
    
    org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
    org.quartz.dataSource.myDS.URL: jdbc:mysql://localhost:3307/itp
    org.quartz.dataSource.myDS.user: root
    org.quartz.dataSource.myDS.password: 123456
    org.quartz.dataSource.myDS.maxConnections: 5
    org.quartz.dataSource.myDS.validationQuery: select 0

    web.xml注册监听器ScheduleStartListener

    注册quartz监听器,监听项目是否启动或者重启.保证项目启动或重启时,所有任务会被重新安排到任务调度中.

    web.xml添加一个Listener:

    
    
    <!-- quartz监听器 -->  
    <listener>
        <listener-class>sedion.jeffli.wmuitp.listener.ScheduleStartListener</listener-class>
    </listener>
    

    监听器类sedion.jeffli.wmuitp.listener.ScheduleStartListener实现

    监听器类主要是实现recovery各个任务,重新恢复在triggerGroups组中所有的触发器,按新的trigger重新设置job执行.顺便说下,这个异常自定义(不需要删除即可): sedion.jeffli.wmuitp.exception.QuartzException;

    package sedion.jeffli.wmuitp.listener;
    
    import java.util.List;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    import org.quartz.Scheduler;
    import org.quartz.SchedulerFactory;
    import org.quartz.Trigger;
    import org.quartz.TriggerKey;
    import org.quartz.impl.StdSchedulerFactory;
    
    import sedion.jeffli.wmuitp.exception.QuartzException;
    
    public class ScheduleStartListener implements ServletContextListener
    {
    
        public void contextDestroyed(ServletContextEvent sce) 
        {
            
        }
    
        public void contextInitialized(ServletContextEvent sce) 
        {
            try 
            {
                recovery();
            } 
            catch (Exception e)
            {
                throw new QuartzException(" ScheduleStartListener contextInitialized ERROR!!",e);
            }
        }
        
    
        public void recovery() 
        {
            
            Scheduler scheduler = null;
            
            try {
                
                SchedulerFactory schedulerFactory = new StdSchedulerFactory();
                scheduler = schedulerFactory.getScheduler();//可以通过SchedulerFactory创建一个Scheduler实例
                List<String> triggerGroups = scheduler.getTriggerGroupNames();//获取调度器中所有的触发器组
                System.out.println("调度器中所有的触发器组 size():"+triggerGroups.size());
                
                if(triggerGroups != null && triggerGroups.size() != 0)//重新恢复在triggerGroups组中所有的触发器
                {
                    for (int i = 0; i < triggerGroups.size(); i++) 
                    {
                            TriggerKey triggerKey = TriggerKey.triggerKey(triggerGroups.get(i), triggerGroups.get(i));
                            System.out.println("triggerKey:"+triggerKey);
                            
                            Trigger tg = scheduler.getTrigger(triggerKey);//获取trigger
                            System.out.println(triggerKey+" -> 执行时间 :"+tg.getNextFireTime());
                            
                            scheduler.rescheduleJob(triggerKey, tg);//按新的trigger重新设置job执行
                    }
                }
                
                scheduler.start();
                
            } 
            catch (Exception e) 
            {
                throw new QuartzException("ScheduleStartListener  recovery() Error!", e);
            }
        }
    }

     

    测试案例第一步: Job 接口实现类JobTest

    顾名思义,用于自定义任务,方法的实现.你可以在其中写入任意你想要在那个点上干的事情(操作数据库,前台显示等).在下面那处地方写入你想要写的:System.out.println("添入需要加入任务的具体操作"); .顺便说下,这个异常自定义(不需要删除即可):

    package test.quartz;
    
    
    import org.quartz.Job;
    import org.quartz.JobDataMap;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.JobKey;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.TriggerKey;
    import org.quartz.impl.StdSchedulerFactory;
    
    import sedion.jeffli.wmuitp.exception.QuartzException;
    
    
    public class JobTest implements Job{
        
        public JobTest() {}    
      
        public void execute(JobExecutionContext context)throws JobExecutionException
        {  
            
            JobDataMap data = context.getJobDetail().getJobDataMap();
            System.out.println("data.testId : "+data.getInt("testId")); //不需要可删除
            
            try
            {
                System.out.println("添入需要加入任务的具体操作");
            }
            catch (Exception e) 
            {
                throw new QuartzException("JobTest execute() ERROR !!", e);
            }
        }  
        
        public static void removeJob(JobKey jobKey, TriggerKey tiKey)throws SchedulerException
        { 
            
            SchedulerFactory sf     = new StdSchedulerFactory();
            Scheduler          sched     = sf.getScheduler();  
            
            sched.pauseTrigger(tiKey);            //停止触发器  
            sched.unscheduleJob(tiKey);            //移除触发器  
            sched.deleteJob(jobKey);            //删除任务  
            
        } 
    }

    测试案例第二步:QuartzTest

    顾名思义,用于实现,检验.可以通过SchedulerFactory创建一个Scheduler实例,把触发器在集群节点实例命名的组只是为了区分(伐木)从什么地方定问调度重新执行此作业,如果它是正在进行时调度下去.

    package test.quartz;
    
    import static org.quartz.JobBuilder.newJob;
    import static org.quartz.TriggerBuilder.newTrigger;
    
    import java.util.Date;
    
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerFactory;
    import org.quartz.SimpleTrigger;
    import org.quartz.impl.StdSchedulerFactory;
    
    
    public class QuartzTest
    {
    
        public void run(String date, int id)throws Exception 
        {
    
            
            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();//可以通过SchedulerFactory创建一个Scheduler实例
            
            //设置工作详情
            JobDetail job = newJob(JobTest.class) 
                .withIdentity("job_"+id, "test"+id)         // (String name, String group)把触发器在集群节点实例命名的组只是为了区分(伐木)从什么地方定问调度重新执行此作业,如果它是正在进行时调度下去...
                .requestRecovery()                             
                .build();
           
            job.getJobDataMap().put("testId", id);        //设置存储参数(不需要可删除)
            
           
            Date startDate = FormatDate.stringToDateAll(date);//Date转String
            //设置触发器
            SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                    .withIdentity("overdue"+id, "overdue"+id)//withIdentity("trigger", "group")
                    .startAt(startDate)
                    .build();
            
            scheduler.scheduleJob(job, trigger);
            scheduler.start();
            System.out.println("------- Start Scheduler ----------------");
        }
        
        public static void main(String[] args) throws Exception 
        {
            QuartzTest quartzOverdue = new QuartzTest();
            quartzOverdue.run("2014-07-02 00:30:00",666);//666,随便的吉祥数字
        }
    }

     

    这边,项目tomcat启动.这边我的主机时间是:
    image

     

    然后我们运行:

    public static void main(String[] args) throws Exception 
        {
            QuartzTest quartzOverdue = new QuartzTest();
            quartzOverdue.run("2014-07-02 00:30:00",666);//666,随便的吉祥数字
        }

     

    看控制台:

    先输出

    
    
    ------- Start Scheduler ----------------
    

    然后时间到了

    
    
    添入需要加入任务的具体操作
    

     

    然后测试 quartz的持久化.(持久化测试就是 先开启任务,然后 中间断开重启服务器),之间你会发现控制台:

    今天我重写了下,:

    
    
    public static void main(String[] args) throws Exception 
        {
            QuartzTest quartzOverdue = new QuartzTest();
            quartzOverdue.run("2014-07-02 10:00:00",6666);
        }
    


    调度器中所有的触发器组 size():1
    triggerKey:test6666.test6666
    test6666.test6666 -> 执行时间 :Wed Jul 02 10:00:00 CST 2014

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
10天前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
6天前
|
存储 Java BI
java怎么统计每个项目下的每个类别的数据
通过本文,我们详细介绍了如何在Java中统计每个项目下的每个类别的数据,包括数据模型设计、数据存储和统计方法。通过定义 `Category`和 `Project`类,并使用 `ProjectManager`类进行管理,可以轻松实现项目和类别的数据统计。希望本文能够帮助您理解和实现类似的统计需求。
42 17
|
29天前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
126 26
|
2月前
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
65 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
2月前
|
Java
Java项目中高精度数值计算:为何BigDecimal优于Double
在Java项目开发中,涉及金额计算、面积计算等高精度数值操作时,应选择 `BigDecimal` 而非 `Double`。`BigDecimal` 提供任意精度的小数运算、多种舍入模式和良好的可读性,确保计算结果的准确性和可靠性。例如,在金额计算中,`BigDecimal` 可以精确到小数点后两位,而 `Double` 可能因精度问题导致结果不准确。
|
2月前
|
Java Android开发
Eclipse 创建 Java 项目
Eclipse 创建 Java 项目
52 4
|
2月前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
53 3
|
2月前
|
NoSQL Java 调度
Java调度任务如何保证相同任务在一个周期里只执行一次?
【10月更文挑战第29天】Java调度任务如何保证相同任务在一个周期里只执行一次?
104 6
|
2月前
|
前端开发 Java 数据库
如何实现一个项目,小白做项目-java
本教程涵盖了从数据库到AJAX的多个知识点,并详细介绍了项目实现过程,包括静态页面分析、数据库创建、项目结构搭建、JSP转换及各层代码编写。最后,通过通用分页和优化Servlet来提升代码质量。
73 1
|
2月前
|
存储 NoSQL Java
Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
【10月更文挑战第29天】Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
108 1