新闻详细
新闻当前位置:新闻详细

任务调度小程序怎么做,怎么自己制作小程序

专业小程序设计开发——助力新电商新零售

电话+V: 152079-09430 ,欢迎咨询任务调度小程序怎么做,[小程序设计与开发],[小程序投流与推广],[小程序后台搭建],[小程序整套源码打包],[为个体及小微企业助力],[电商新零售模式],[小程序运营推广及维护]

一、任务调度小程序怎么做

关于如何制作一个任务调度小程序,以下是一些重要的步骤:

1.确定需求:首先,你需要明确你的小程序需要完成什么任务。这可能涉及到用户管理、任务分配、进度跟踪等多个方面。明确需求是开发过程中的关键步骤,它决定了你的小程序的功能和设计。

2.设计界面:设计一个直观易用的界面是非常重要的。用户应该能够轻松地看到他们的任务,以及任务的状态。你也需要考虑如何在界面上展示优先级、截止日期等信息。

3.数据库设计:你的小程序需要一个数据库来存储任务信息。你需要设计一个数据库模型,以便于存储和检索任务信息。你可能需要考虑如何设计表,以及如何选择适合的数据库系统。

4.编写代码:在确定了需求、设计了界面和数据库之后,你就可以开始编写代码了。你需要选择一个适合的编程语言和框架,然后开始编写代码。在编写代码的过程中,你需要不断地测试和调试,以确保代码的正确性。

5.测试:在编写完代码之后,你需要进行测试。你需要测试你的小程序在各种情况下的表现,包括正常情况和异常情况。你也需要测试你的小程序的性能,以确保它能够在大量用户和大量任务的情况下正常工作。

二、怎么自己制作小程序

自己做一个小程序的方法有明确小程序的主题、注册小程序账号、找一个简单的小程序制作工具、生成小程序。

一、明确小程序的主题

在制作小程序之前,你需要考虑你打算用这个小程序做什么,销售产品,展示公司信息,或者写文章和积累粉丝?不同类型的小程序必须有不同的模板。稍后,您还希望将其提交给精确的小程序服务类别,否则将无法审查。

另外,需要注意的是,我不能做一个有支付功能的小程序,所以电子商务和订单类与我不兼容,只有企业才能形成。因此,在制作小程序之前,你必须事先考虑要做什么样的工作。

二、注册小程序账号

在微信公众平台开通微信官方账号,点击“立即注册”选择账号申请类型:小程序。

然后设置电子邮件,密码,系统将推送电子邮件,您可以登录到相应的电子邮件来激活帐户。在激动人心的小程序后,选择主要类型。如果您是主要类型,您不需要提交其他材料;如果是公司类型,您需要提交营业执照和其他信息。

再次登录您刚刚注册的小程序账号,在【设置】中填写小程序名称、头像、服务类别等信息,然后再进行审核。

三、找一个简单的小程序制作工具

新手不能用太难的操作系统来挑战自己。这需要很多时间,而且很容易做得不好。试着找一个简单、信誉好的小程序制作平台,这样你就可以在不浪费太多时间的情况下快速形成小程序。

四、生成小程序

想快速发布你自己的小程序,使用第三方开发环境更方便。最后一个程序是页面设置,再加上各个板块的快捷方式,完成自己开发小程序。

最后,点击发布后然后按流程进行小程序账号授权即可。

一文快速入门任务调度框架-Quartz

2023-04-0313:53·晾干的红领巾前言还不会Quartz?如果你还没有接触过Quartz,那么你可能错过了一个很棒的任务调度框架!Quartz提供了一种灵活、可靠的方式来管理和执行定时任务,让咱们的定时任务更加优雅。本篇文章将为你介绍Quartz框架的核心概念、API和实战技巧,让你轻松上手。也不用担心,作为过来人,我会把难懂的概念和术语解释清楚,让你看完本篇文章后,就知道该如何操作Quartz。那废话少说,下面我们开始吧!

什么是Quartz?Quartz是一个功能丰富的开源任务调度框架(jobschedulinglibrary)。从最小的独立的Java应用程序到最大的电子商务系统,它几乎都可以集成。Quartz可用于创建简单或复杂的调度,以执行数十、数百个甚至数万个任务;这些任务被定义为标准Java组件,这些组件可以执行你想让他做的任何事情。Quartz调度程序包括许多企业级特性,例如支持JTA事务(JavaTransactionAPI,简写JTA)和集群。

注意:Job==任务

JTA,即JavaTransactionAPI,JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据。

为什么学习Quartz?定时任务直接用Spring提供的@Schedule不行吗?为什么还要学习Quartz?有什么好处?

是的,一开始我也是这么想的,但是某些场景,单靠@Schedule你就实现不了了。

比如我们需要对定时任务进行增删改查,是吧,@Schedule就实现不了,你不可能每次新增一个定时任务都去手动改代码来添加吧。而Quartz就能够实现对任务的增删改查。当然,这只是Quartz的好处之一。

Quartz的特性运行时环境

Quartz可以嵌入另一个独立的应用程序中运行Quartz可以在应用程序服务器(比如Tomcat)中实例化,并参与XA事务(XA是一个分布式事务协议)Quartz可以作为一个独立程序运行(在其自己的Java虚拟机中),我们通过RMI(RemoteMethodInvocation,远程方法调用)使用它Quartz可以实例化为一个独立程序集群(具有负载平衡和故障转移功能),用于执行任务任务的调度(JobScheduling)

当一个触发器(Trigger)触发时,Job就会被调度执行,触发器就是用来定义何时触发的(也可以说是一个执行计划),可以有以下任意的组合:

在一天中的某个时间(毫秒)在一周中的某些日子在一个月的某些日子在一年中的某些日子重复特定次数重复直到特定的时间/日期无限期重复以延迟间隔重复Job由我们自己去命名,也可以组织到命名组(namedgroups)中。Trigger也可以被命名并分组,以便在调度器(Scheduler)中更容易地组织它们。

Job只需在Scheduler中添加一次,就可以有多个Trigger进行注册。

任务的执行(JobExecution)

实现了Job接口的Java类就是Job,习惯称为任务类(Jobclass)。当Trigger触发时,Scheduler就会通知0个或多个实现了JobListener和TriggerListener接口的Java对象。当然,这些Java对象在Job执行后也会被通知到。当Job执行完毕时,会返回一个码——JobCompletionCode,这个JobCompletionCode能够表示Job执行成功还是失败,我们就能通过这个Code来判断后续该做什么操作,比如重新执行这个Job。任务的持久化(JobPersistence)

Quartz的设计包括了一个JobStore接口,该接口可以为存储Job提供各种机制。通过JDBCJobStore,可以将Job和Trigger持久化到关系型数据库中。通过RAMJobStore,可以将Job和Trigger存储到内存中(优点就是无须数据库,缺点就是这不是持久化的)。事务

Quartz可以通过使用JobStoreCMT(JDBCJobStore的一个子类)参与JTA事务。Quartz可以围绕任务的执行来管理JTA事务(开始并且提交它们),以便任务执行的工作自动发生在JTA事务中。集群

故障转移负载均衡Quartz的内置集群功能依赖于JDBCJobStore实现的数据库持久性。Quartz的Terracotta扩展提供了集群功能,而无需备份数据库。监听器和插件

应用程序可以通过实现一个或多个监听器接口来捕获调度事件以监听或控制Job/Trigger的行为。插件机制,我们可向Quartz添加功能,例如保存Job执行的历史记录,或从文件加载Job和Trigger的定义。Quartz提供了许多插件和监听器。初体验引入Quartz依赖项

创建一个SpringBoot项目,然后引入如下依赖,就可以体验Quartz了。

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version></dependency>复制代码示例

现在知道Quartz有这么几个概念,分别是Job、Trigger、Scheduler。在它的设计实现上,分别是Job接口、JobDetail接口、Trigger接口、Scheduler接口。除了Job接口的实现类需要我们自己去实现,剩下的都由Quartz实现了。

Quartz中的调度器(Scheduler)的主要作用就是调度Job和Trigger的执行。在Quartz中,Job代表需要执行的任务,Trigger代表触发Job执行的条件和规则。调度器会根据Trigger的配置来确定Job的执行时机。

下面的代码包含了一个Scheduler的实例对象,接着是调用start方法,最后调用shutdown方法。

importorg.quartz.*;importorg.quartz.impl.StdSchedulerFactory;publicclassQuartzTest{publicstaticvoidmain(String[]args){try{//从Factory中获取Scheduler实例Schedulerscheduler=StdSchedulerFactory.getDefaultScheduler();//开始并关闭scheduler.start();scheduler.shutdown();}catch(SchedulerExceptionse){se.printStackTrace();}}}复制代码一旦我们使用
StdSchedulerFactory.getDefaultScheduler()获取Scheduler对象后,那么程序就会一直运行下去,不会终止,直到我们调用了scheduler.shutdown()方法才会停止运行。这是因为获取Scheduler对象后,就有许多线程在运行着,所以程序会一直运行下去。

与此同时,控制台会输出相应的日志:

10:14:02.442[main]INFOorg.quartz.impl.StdSchedulerFactory-UsingdefaultimplementationforThreadExecutor10:14:02.445[main]INFOorg.quartz.simpl.SimpleThreadPool-Jobexecutionthreadswilluseclassloaderofthread:main10:14:02.452[main]INFOorg.quartz.core.SchedulerSignalerImpl-InitializedSchedulerSignalleroftype:classorg.quartz.core.SchedulerSignalerImpl10:14:02.452[main]INFOorg.quartz.core.QuartzScheduler-QuartzSchedulerv.2.3.2created.10:14:02.453[main]INFOorg.quartz.simpl.RAMJobStore-RAMJobStoreinitialized.10:14:02.453[main]INFOorg.quartz.core.QuartzScheduler-Schedulermeta-data:QuartzScheduler(v2.3.2)'DefaultQuartzScheduler'withinstanceId'NON_CLUSTERED'Schedulerclass:'org.quartz.core.QuartzScheduler'-runninglocally.NOTSTARTED.Currentlyinstandbymode.Numberofjobsexecuted:0Usingthreadpool'org.quartz.simpl.SimpleThreadPool'-with10threads.Usingjob-store'org.quartz.simpl.RAMJobStore'-whichdoesnotsupportpersistence.andisnotclustered.10:14:02.453[main]INFOorg.quartz.impl.StdSchedulerFactory-Quartzscheduler'DefaultQuartzScheduler'initializedfromdefaultresourcefileinQuartzpackage:'quartz.properties'10:14:02.453[main]INFOorg.quartz.impl.StdSchedulerFactory-Quartzschedulerversion:2.3.2复制代码从日志中也能看出Quartz的一些信息,比如版本、使用的线程池、使用的任务存储机制(这里默认是RAMJobStore)等等信息。

我们想要执行任务的话,就需要把任务的代码放在scheduler.start()和scheduler.shutdown()之间。

QuartzTest:

importcn.god23bin.demo.quartz.job.HelloJob;importorg.quartz.*;importorg.quartz.impl.StdSchedulerFactory;//这里导入了static,下面才能直接newJob,newTriggerimportstaticorg.quartz.JobBuilder.newJob;importstaticorg.quartz.SimpleScheduleBuilder.simpleSchedule;importstaticorg.quartz.TriggerBuilder.newTrigger;publicclassQuartzTest{publicstaticvoidmain(String[]args){try{//从Factory中获取Scheduler实例Schedulerscheduler=StdSchedulerFactory.getDefaultScheduler();//开始并关闭scheduler.start();//定义一个Job(用JobDetail描述的Job),并将这个Job绑定到我们写的HelloJob这个任务类上JobDetailjob=newJob(HelloJob.class).withIdentity("job1","group1")//名字为job1,组为group1.build();//现在触发任务,让任务执行,然后每5秒重复执行一次Triggertrigger=newTrigger().withIdentity("trigger1","group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();//告知Quartz使用我们的Trigger去调度这个Jobscheduler.scheduleJob(job,trigger);//为了在shutdown之前让Job有足够的时间被调度执行,所以这里当前线程睡眠30秒Thread.sleep(30000);scheduler.shutdown();}catch(SchedulerException|InterruptedExceptionse){se.printStackTrace();}}}复制代码HelloJob:实现Job接口,重写execute方法,实现我们自己的任务逻辑。

importorg.quartz.Job;importorg.quartz.JobExecutionContext;importorg.quartz.JobExecutionException;importjava.text.SimpleDateFormat;publicclassHelloJobimplementsJob{@Overridepublicvoidexecute(JobExecutionContextjobExecutionContext)throwsJobExecutionException{SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");System.out.println("HelloJob!!!时间:"+sdf.format(jobExecutionContext.getFireTime()));}}复制代码运行程序,输出如下信息:

10:25:40.069[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.simpl.PropertySettingJobFactory-ProducinginstanceofJob'group1.job1',class=cn.god23bin.demo.quartz.job.HelloJob10:25:40.071[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.core.QuartzSchedulerThread-batchacquisitionof1triggers10:25:40.071[DefaultQuartzScheduler_Worker-1]DEBUGorg.quartz.core.JobRunShell-Callingexecuteonjobgroup1.job1HelloJob!!!时间:2023-03-2810:25:4010:25:45.066[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.simpl.PropertySettingJobFactory-ProducinginstanceofJob'group1.job1',class=cn.god23bin.demo.quartz.job.HelloJob10:25:45.066[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.core.QuartzSchedulerThread-batchacquisitionof1triggers10:25:45.066[DefaultQuartzScheduler_Worker-2]DEBUGorg.quartz.core.JobRunShell-Callingexecuteonjobgroup1.job1HelloJob!!!时间:2023-03-2810:25:45#省略后面输出的信息,都是一样的复制代码API有哪些?QuartzAPI的关键接口如下:

Scheduler:最主要的API,可以使我们与调度器进行交互,简单说就是让调度器做事。Job:一个Job组件,你自定义的一个要执行的任务类就可以实现这个接口,实现这个接口的类的对象就可以被调度器进行调度执行。JobDetail:Job的详情,或者说是定义了一个Job。JobBuilder:用来构建JobDetail实例的,然后这些实例又定义了Job实例。Trigger:触发器,定义Job的执行计划的组件。TriggerBuilder:用来构建Trigger实例。Quartz涉及到的设计模式:

FactoryPattern://从Factory中获取Scheduler实例Schedulerscheduler=StdSchedulerFactory.getDefaultScheduler();复制代码BuilderPattern:JobDetailjob=newJob(HelloJob.class).withIdentity("job1","group1")//名字为job1,组为group1.build();复制代码这里的newJob方法是JobBuilder类中的一个静态方法,就是通过这个来构建JobDetail的。/***CreateaJobBuilderwithwhichtodefinea<code>JobDetail</code>,*andsettheclassnameofthe<code>Job</code>tobeexecuted.**@returnanewJobBuilder*/publicstaticJobBuildernewJob(Class<?extendsJob>jobClass){JobBuilderb=newJobBuilder();b.ofType(jobClass);returnb;}/***Producethe<code>JobDetail</code>instancedefinedbythis*<code>JobBuilder</code>.**@returnthedefinedJobDetail.*/publicJobDetailbuild(){JobDetailImpljob=newJobDetailImpl();job.setJobClass(jobClass);job.setDescription(description);if(key==null)key=newJobKey(Key.createUniqueName(null),null);job.setKey(key);job.setDurability(durability);job.setRequestsRecovery(shouldRecover);if(!jobDataMap.isEmpty())job.setJobDataMap(jobDataMap);returnjob;}复制代码同样,构建Trigger对象是使用TriggerBuilder类以及SimpleScheduleBuilder类构建的,Schedule主要是一个时间安排表,就是定义何时执行任务的时间表。当然,除了上面说的两种设计模式外,还有其他的设计模式,这里就不细说了。比如单例模式,观察者模式。简单理解Job、Trigger、Scheduler每天中午12点唱、跳、Rap、篮球

Job:唱、跳、Rap、篮球Trigger:每天中午12点为一个触发点Scheduler:自己,我自己调度Trigger和Job,让自己每天中午12点唱、跳、Rap、篮球关于JobJob接口源码:

packageorg.quartz;publicinterfaceJob{voidexecute(JobExecutionContextcontext)throwsJobExecutionException;}复制代码当该任务的Trigger触发时,那么Job接口的execute方法就会被Scheduler的某一个工作线程调用。JobExecutionContext对象就会作为参数传入这个方法,该对象就提供Job实例的一些关于任务运行时的信息。

我们知道,写完一个Job类后,需要将定义一个JobDetail绑定到我们的Job类:

//定义一个Job(用JobDetail描述的Job),并将这个Job绑定到我们写的HelloJob这个任务类上JobDetailjob=newJob(HelloJob.class).withIdentity("job1","group1")//名字为job1,组为group1.build();复制代码在这个过程中,有许多属性是可以设置的,比如JobDataMap,这个对象能够存储一些任务的状态信息数据,这个后面说。

Trigger对象用于触发任务的执行。当我们想要调度某个任务时,可以实例化Trigger并设置一些我们想要的属性。Trigger也可以有一个与之相关的JobDataMap,这对于特定的触发器触发时,传递一些参数给任务是很有用。Quartz有几种不同的Trigger类型,但最常用的类型是SimpleTriggerCronTrigger

关于SimpleTrigger和CronTrigger如果我们想要在某个时间点执行一次某个任务,或者想要在给定时间启动一个任务,并让它重复N次,执行之间的延迟为T,那么就可以使用SimpleTrigger。

如果我们想根据类似日历的时间表来执行某个任务,例如每天晚上凌晨4点这种,那么就可以使用CronTrigger。

为什么会设计出Job和Trigger这两个概念?在官网上是这样说的:

WhyJobsANDTriggers?Manyjobschedulersdonothaveseparatenotionsofjobsandtriggers.Somedefinea‘job’assimplyanexecutiontime(orschedule)alongwithsomesmalljobidentifier.OthersaremuchliketheunionofQuartz’sjobandtriggerobjects.WhiledevelopingQuartz,wedecidedthatitmadesensetocreateaseparationbetweenthescheduleandtheworktobeperformedonthatschedule.Thishas(inouropinion)manybenefits.

Forexample,Jobscanbecreatedandstoredinthejobschedulerindependentofatrigger,andmanytriggerscanbeassociatedwiththesamejob.Anotherbenefitofthisloose-couplingistheabilitytoconfigurejobsthatremaininthescheduleraftertheirassociatedtriggershaveexpired,sothatthatitcanberescheduledlater,withouthavingtore-defineit.Italsoallowsyoutomodifyorreplaceatriggerwithouthavingtore-defineitsassociatedjob.

简而言之,这有许多好处:

任务可以独立于触发器,它可以在调度器中创建和存储,并且许多触发器可以与同一个任务关联。这种松耦合能够配置任务,在其关联的触发器已过期后仍然保留在调度器中,以便之后重新安排,而无需重新定义它。这也允许我们修改或替换触发器的时候无需重新定义其关联的任务。Job和Trigger的身份标识(Identities)在上面的代码中我们也看到了,Job和Trigger都有一个withIdentity方法。

JobBuilder中的withIdentity方法:

privateJobKeykey;publicJobBuilderwithIdentity(Stringname,Stringgroup){key=newJobKey(name,group);returnthis;}复制代码TriggerBuilder中的withIdentity方法:

privateTriggerKeykey;publicTriggerBuilder<T>withIdentity(Stringname,Stringgroup){key=newTriggerKey(name,group);returnthis;}复制代码当Job和Trigger注册到Scheduler中时,就会通过这个key来标识Job和Trigger。

任务和触发器的key(JobKey和TriggerKey)允许将它们放入「组」中,这有助于将任务和触发器进行分组,或者说分类。而且任务或触发器的key的名称在组中必须是唯一的,他们完整的key(或标识符)是名称和组的组合。从上面的代码中也可以看到,构造方法都是两个参数的,第一个参数是name,第二个参数是group,构造出来的就是整个key了。

关于JobDetail和JobDataMap我们通过写一个Job接口的实现类来编写我们等待执行的任务,而Quartz需要知道你将哪些属性给了Job。那Quartz是如何知道的呢?Quartz就是通过JobDetail知道的。

注意,我们向Scheduler提供了一个JobDetail实例,Scheduler就能知道要执行的是什么任务,只需在构建JobDetail时提供任务的类即可(即newJob(HelloJob.class))。

每次调度程序执行任务时,在调用其execute方法之前,它都会创建该任务类的一个新实例。执行完成任务后,对任务类实例的引用将被丢弃,然后该实例将被垃圾回收。

那我们如何为作业实例提供属性或者配置?我们如何在执行的过程中追踪任务的状态?这两个问题的答案是一样的:关键是JobDataMap,它是JobDetail对象的一部分。

JobDataMap可以用来保存任意数量的(可序列化的)数据对象,这些对象在任务实例执行时需要使用的。JobDataMap是Java中Map接口的一个实现,具有一些用于存储和检索原始类型数据的方法。

示例:

PlayGameJob:

publicclassPlayGameJobimplementsJob{@Overridepublicvoidexecute(JobExecutionContextcontext)throwsJobExecutionException{JobKeykey=context.getJobDetail().getKey();//获取JobDataMap,该Map在创建JobDetail的时候设置的JobDataMapjobDataMap=context.getJobDetail().getJobDataMap();StringgameName=jobDataMap.getString("gameName");floatgamePrice=jobDataMap.getFloat("gamePrice");System.out.println("我玩的"+gameName+"才花费了我"+gamePrice+"块钱");}}复制代码接着使用usingJobData设置该任务需要的数据,最后调度该任务:

Schedulerscheduler=StdSchedulerFactory.getDefaultScheduler();scheduler.start();JobDetailjob=newJob(PlayGameJob.class).withIdentity("myJob","group1").usingJobData("gameName","GTA5").usingJobData("gamePrice",55.5f).build();Triggertrigger=newTrigger().withIdentity("myJob","group1").build();scheduler.scheduleJob(job,trigger);Thread.sleep(10000);scheduler.shutdown();复制代码控制台输出:

14:18:43.295[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.simpl.PropertySettingJobFactory-ProducinginstanceofJob'group1.myJob',class=cn.god23bin.demo.quartz.job.PlayGameJob14:18:43.299[DefaultQuartzScheduler_QuartzSchedulerThread]DEBUGorg.quartz.core.QuartzSchedulerThread-batchacquisitionof0triggers14:18:43.300[DefaultQuartzScheduler_Worker-1]DEBUGorg.quartz.core.JobRunShell-Callingexecuteonjobgroup1.myJob我玩的GTA5才花费了我55.5块钱复制代码当然,也可以这样写:

JobDataMapjobDataMap=newJobDataMap();jobDataMap.put("gameName","GTA5");jobDataMap.put("gamePrice",55.5f);JobDetailjob=newJob(PlayGameJob.class).withIdentity("myJob","group1").usingJobData(jobDataMap).build();复制代码之前还说过,Trigger也是可以有JobDataMap的。当你有这种情况,就是在调度器中已经有一个Job了,但是想让不同的Trigger去触发执行这个Job,每个不同的Trigger触发时,你想要有不同的数据传入这个Job,那么就可以用到Trigger携带的JobDataMap了

噢对了!对于我们上面自己写的PlayGameJob,还可以换一种写法,不需要使用通过context.getJobDetail().getJobDataMap()获取JobDataMap对象后再根据key获取对应的数据,直接在这个任务类上写上我们需要的属性,提供getter和setter方法,这样Quartz会帮我们把数据赋值到该对象的属性上。

PlayGameJob:

//使用Lombok的注解,帮我们生成getter和setter方法以及无参的构造方法@Data@NoArgsConstructorpublicclassPlayGameJobimplementsJob{//Quartz会把数据注入到任务类定义的属性上,直接用就可以了privateStringgameName;privatefloatgamePrice;@Overridepublicvoidexecute(JobExecutionContextcontext)throwsJobExecutionException{JobKeykey=context.getJobDetail().getKey();System.out.println("我玩的"+gameName+"才花费了我"+gamePrice+"块钱");}}复制代码这样的效果,就是减少了execute方法中的代码量。

如何理解Job实例?这个确实会有一些困惑,比如一开始说的Job接口,还有JobDetail接口,而且为什么会说成JobDetail对象是Job的实例?是吧。

想要理解,举个例子:

现在我们写了一个发送消息的Job实现类——SendMessageJob。

接着我们创建了多个JobDetail对象,这些对象都有不同的定义,比如有叫做SendMessageToLeBron的JobDetail、有SendMessageToKobe的JobDetail,这两个JobDetail都有它各自的JobDataMap传递给我们的Job实现类。

当Trigger触发时,Scheduler将加载与其关联的JobDetail(任务定义),并通过Scheduler上配置的JobFactory实例化它所引用的任务类(SendMessageJob)。默认的JobFactory只是在任务类上调用newInstance(),然后尝试在与JobDataMap中键的名称匹配的类中的属性名,进而调用setter方法将JobDataMap中的值赋值给对应的属性。

在Quartz的术语中,我们将每个JobDetail对象称为「Job定义或者JobDetail实例」,将每个正在执行的任务称为「Job实例或Job定义的实例」。

一般情况下,如果我们只使用「任务」这个词,我们指的是一个名义上的任务,简而言之就是我们要做的事情,也可以指JobDetail。当我们提到实现Job接口的类时,我们通常使用术语「任务类」。

两个需要知道的注解JobDataMap可以说是任务状态的数据,这里的数据和并发也有点关系。Quartz提供了几个注解,这几个注解会影响到Quartz在这方面的动作。

@
DisallowConcurrentExecution
注解是用在任务类上的。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceDisallowConcurrentExecution{}复制代码
DisallowConcurrentExecution这个注解的作用就是告知Quartz这个任务定义的实例(JobDetail实例)不能并发执行,举个例子,就上面的SendMessageToLeBron的JobDetail实例,是不能并发执行的,但它是可以与SendMessageToKobe的JobDetail的实例同时执行。需要注意的是它指的不是任务类的实例(Job实例)。

@
PersistJobDataAfterExecution
注解也是用在任务类上的。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfacePersistJobDataAfterExecution{}复制代码@
PersistJobDataAfterExecution这个注解的作用是告知Quartz在execute方法成功完成后更新JobDetail的JobDataMap的存储副本(没有引发异常),以便同一任务的下一次执行能接收更新后的值,而不是最初存储的值。

与@
DisallowConcurrentExecution注解一样,这是适用于任务定义实例(JobDetail实例),而不是任务类实例(Job实例)。

关于Trigger我们需要了解Trigger有哪些属性可以去设置,从最开始的初体验中,我们给Trigger设置了一个TriggerKey用来标识这个Trigger实例,实际上,它还有好几个属性给我们设置。

共用的属性上面也说过Trigger有不同的类型(比如SimpleTrigger和CronTrigger),不过,即使是不同的类型,也有相同的属性。

jobKey:作为Trigger触发时应执行的任务的标识。startTime:记录下首次触发的时间;对于某些触发器,它是指定触发器应该在何时触发。endTime:触发器不再生效的时间...还有更多,下面说一些重要的。

priority优先级,这个属性可以设置Trigger触发的优先级,值越大则优先级越高,就优先被触发执行任务。当然这个是在同一时间调度下才会有这个优先级比较的,如果你有一个A任务在6点触发,有一个B任务在7点触发,即使你的B任务的优先级比A任务的高,也没用,6点的A任务总是会比7点的B任务先触发。

misfireInstructionmisfireinstruction,错失触发指令,也就是说当某些情况下,导致触发器没有触发,那么就会执行这个指令,默认是一个「智能策略」的指令,它能够根据不同的Trigger类型执行不同的行为。

当Scheduler启动的时候,它就会先搜寻有没有错过触发的Trigger,有的话就会基于Trigger配置的错失触发指令来更新Trigger的信息。

calendarQuartz中也有一个Calendar对象,和Java自带的不是同一个。

在设置Trigger的时候,如果我们想排除某些日期时间,那么就可以使用这个Calendar对象。

SimpleTrigger如果我们想在特定的时间点执行一次任务,或者在特定的时刻执行一次,接着定时执行,那么SimpleTrigger就能满足我们的需求。

SimpleTrigger包含了这么几个属性:

startTime:开始时间endTime:结束时间repeatCount:重复次数,可以是0,正整数,或者是一个常量SimpleTrigger.REPEAT_INDEFINITELYrepeatInterval:重复的时间间隔,必须是0,或者是一个正的长整型的值(long类型的值),表示毫秒,即多少毫秒后重复触发SimpleTrigger的实例对象可以由TriggerBuilder和SimpleScheduleBuilder来创建。

示例下面举几个例子:

构建一个给定时刻触发任务的Trigger,不会重复触发://今天22点30分0秒DatestartAt=DateBuilder.dateOf(22,30,0);//通过强转构建一个SimpleTriggerSimpleTriggertrigger=(SimpleTrigger)newTrigger().withIdentity("trigger1","group1").startAt(startAt)//开始的日期时间.forJob("job1","group1")//通过job的name和group识别job.build();复制代码构建一个给定时刻触发任务的Trigger,每十秒重复触发十次:trigger=newTrigger().withIdentity("trigger3","group1").startAt(startAt)//如果没有给定开始时间,那么就默认现在开始触发.withSchedule(SimpleScheduleBuilder.simpleSchedule()//通过simpleSchedule方法构建SimpleTrigger.withIntervalInSeconds(10).withRepeatCount(10))//每隔10秒重复触发10次.forJob(job)//通过JobDetail本身来识别Job.build();复制代码构建一个给定时刻触发任务的Trigger,在未来五分钟内触发一次:DatefutureDate=DateBuilder.futureDate(5,DateBuilder.IntervalUnit.MINUTE);JobKeyjobKey=job.getKey();trigger=(SimpleTrigger)newTrigger().withIdentity("trigger5","group1").startAt(futureDate)//使用DateBuilder创建一个未来的时间.forJob(jobKey)//通过jobKey识别job.build();复制代码构建一个给定时刻触发任务的Trigger,然后每五分钟重复一次,直到晚上22点:trigger=newTrigger().withIdentity("trigger7","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(5).repeatForever()).endAt(DateBuilder.dateOf(22,0,0)).build();复制代码构建一个给定时刻触发任务的Trigger,然后每下一个小时整点触发,然后每2小时重复一次,一直重复下去:trigger=newTrigger().withIdentity("trigger8")//这里没有指定group的话,那么"trigger8"就会在默认的group中.startAt(DateBuilder.evenHourDate(null))//下一个整点时刻(分秒为零("00:00")).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(2).repeatForever()).forJob("job1","group1").build();复制代码错失触发指令比如我在要触发任务的时候,机器宕机了,当机器重新跑起来后怎么办呢?

当Trigger错失触发时间去触发任务时,那么Quartz就需要执行MisfireInstruction,SimpleTrigger有如下的以常量形式存在的Misfire指令:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICYMISFIRE_INSTRUCTION_FIRE_NOWMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNTMISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNTMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNTMISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT我们知道,所有的Trigger,SimpleTrigger也好,CronTrigger也好,不管是什么类型,都有一个
Trigger.MISFIRE_INSTRUCTION_SMART_POLICY可以使用,如果我们使用这个指令,那么SimpleTrigger就会动态地在上面6个指令中选择,选择的行为取决于我们对于SimpleTrigger的设置。

当我们在构建Trigger的时候,就可以给Trigger设置上Misfire指令:

trigger=newTrigger().withIdentity("trigger7","group1").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(5).repeatForever().withMisfireHandlingInstructionNextWithExistingCount()).build();复制代码CronTrigger使用CronTrigger,我们可以指定触发任务的时间安排(schedule),例如,每周五中午,或每个工作日和上午9:30,甚至每周一,周三上午9:00到上午10:00之间每隔5分钟和1月的星期五

CronTrigger也有一个startTime,用于指定计划何时生效,以及一个(可选的)endTime,用于指定何时停止这个任务的执行。

cron表达式cron表达式有6位,是必须的,从左到右分别表示:秒、分、时、日、月、周。

当然也可以是7位,最后一位就是年(可选项):秒、分、时、日、月、周、年。

取值说明:正常认识,秒分都是0-59,则是0-23,则是1-31,在这边则是0-11,则是1-7(这里的1指的是星期日)。则只有1970-2099

月份可以指定为0到11之间的值,或者使用字符串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC

星期几可以使用字符串SUN,MON,TUE,WED,THU,FRI和SAT来表示

详细可参考这里:简书-Cron表达式的详细用法

Cron生成工具:cron.qqe2.com/

示例构建一个Trigger,每天上午8点到下午5点之间每隔一分钟触发一次:Triggertrigger=newTrigger().withIdentity("trigger3","group1").withSchedule(cronSchedule("00/18-17**?")).forJob("myJob","group1").build();复制代码构建一个Trigger,每天上午10:42触发:JobKeymyJobKey=job.getKey();trigger=newTrigger().withIdentity("trigger3","group1").withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(10,42)).forJob(myJobKey).build();复制代码构建一个触发器,该触发器将在星期三上午10点42分在TimeZone中触发,而不是系统的默认值:JobKeymyJobKey=job.getKey();trigger=newTrigger().withIdentity("trigger3","group1").withSchedule(CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY,10,42).inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))).forJob(myJobKey).build();复制代码错失触发指令对于CronTrigger,它有3个Misfire指令

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICYMISFIRE_INSTRUCTION_DO_NOTHINGMISFIRE_INSTRUCTION_FIRE_NOW我们在构建Tirgger的时候就可以给这个Trigger指定它的Misfire指令:

trigger=newTrigger().withIdentity("trigger3","group1").withSchedule(cronSchedule("00/28-17**?").withMisfireHandlingInstructionFireAndProceed()).forJob("myJob","group1").build();复制代码关于CRUD存储定时任务存储定时任务,方便后续使用,通过Scheduler的addJob方法

voidaddJob(JobDetailjobDetail,booleanreplace)throwsSchedulerException;该方法会添加一个没有与Trigger关联的Job到Scheduler中,然后这个Job是处于休眠的状态直到它被Trigger触发进行执行,或者使用Scheduler.triggerJob()指定了这个Job,这个Job才会被唤醒。

JobDetailjob1=newJob(MyJobClass.class).withIdentity("job1","group1").storeDurably()//Job必须被定义为durable的.build();scheduler.addJob(job1,false);复制代码更新已存储的定时任务addJob方法的第二个参数-replace,就是用在这里,设置为true,那么就是更新操作。

JobDetailjob1=newJob(MyJobClass.class).withIdentity("job1","group1").build();//store,andsetoverwriteflagto'true'scheduler.addJob(job1,true);复制代码更新触发器替换已存在的Trigger:

//定义一个新的TriggerTriggertrigger=newTrigger().withIdentity("newTrigger","group1").startNow().build();//让Scheduler根据Key去移除旧的Trigger,然后将新的Trigger放上去scheduler.rescheduleJob(newTriggerKey("oldTrigger","group1"),trigger);复制代码更新已存在的Trigger:

//根据Key检索已存在的TriggerTriggeroldTrigger=scheduler.getTrigger(newTriggerKey("oldTrigger","group1");//获取TriggerBuilderTriggerBuildertb=oldTrigger.getTriggerBuilder();//更新触发动作,并构建新的Trigger//(otherbuildermethodscouldbecalled,tochangethetriggerinanydesiredway)TriggernewTrigger=tb.withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10).build();//重新用新的Trigger调度Jobscheduler.rescheduleJob(oldTrigger.getKey(),newTrigger);复制代码取消定时任务使用Scheduler的deleteJob方法,入参为一个TriggerKey,即Trigger标识,这样就能取消特定的Trigger去触发对应的任务,因为一个Job可能有多个Trigger。

scheduler.unscheduleJob(newTriggerKey("trigger1","group1"));复制代码使用Scheduler的deleteJob方法,入参为一个JobKey,即Job标识,这样就能删除这个Job并取消对应的Trigger进行触发。

scheduler.deleteJob(newJobKey("job1","group1"));复制代码获取调度器中的所有定时任务思路:通过scheduler获取任务组,然后遍历任务组,进而遍历组中的任务。

//遍历每一个任务组for(Stringgroup:scheduler.getJobGroupNames()){//遍历组中的每一个任务for(JobKeyjobKey:scheduler.getJobKeys(GroupMatcher.groupEquals(group))){System.out.println("通过标识找到了Job,标识的Key为:"+jobKey);}}复制代码获取调度器中的所有触发器思路:同上。

//遍历每一个触发器组for(Stringgroup:scheduler.getTriggerGroupNames()){//遍历组中的每一个触发器for(TriggerKeytriggerKey:scheduler.getTriggerKeys(GroupMatcher.groupEquals(group))){System.out.println("通过标识找到了Trigger,标识的Key为:"+triggerKey);}}复制代码获取某一个定时任务的触发器列表因为一个任务可以有多个触发器,所以是获取触发器列表。

List<Trigger>jobTriggers=scheduler.getTriggersOfJob(newJobKey("jobName","jobGroup"));复制代码总结想要使用Quartz,那么就引入它的依赖。

从使用上来说:

对于一个任务,我们可以写一个任务类,即实现了Job接口的Java类,并重写execute方法。接着需要一个JobDetail来描述这个Job,或者说把这个Job绑定到这个JobDetail上。然后我们就需要一个Trigger,这个Trigger是用来表示何使触发任务的,可以说是一个执行计划,在何时如何触发,Trigger是有好几种类型的,目前常用的就是SimpleTrigger和CronTrigger。最后,在把JobDetail和Trigger扔给Scheduler,让它去组织调度;对于一个触发器,它有对应的类型,以及对应的Misfire指令,一般在创建Trigger的时候,就指定上这些信息;对于它们的CRUD,都是使用调度器进行操作的,比如往调度器中添加任务,更新任务。从Quartz的设计上来说,它有涉及到多种设计模式,包括Builder模式,Factory模式等等。

【GSFAI BANK FINANCING】尊享直接对接老板

电话+V: 152079-09430

专注于小程序推广配套流程服务方案。为企业及个人客户提供了高性价比的运营方案,解决小微企业和个体拓展客户的问题

任务调度小程序怎么做
Copyright2023未知推广科技