在日常工作中,经常会遇到一些定时任务,比如定时发邮件、异构数据库同步数据等。目前比较常用的是SpringBootQuartz实现动态定时任务的Web项目,这种模式通常需要建立定时任务相关的表。本例为SpringBootQuartz实现动态定时任务的非Web项目,可以根据项目启动的参数来决定执行配置文件中的某些任务,并且所有的任务都配置在配置文件中,从而避免建数据库的麻烦。 一、流程说明: 程序启动时注册QuartzConfig配置类(该配置类将读取quartz。properties中的配置、任务信息、初始化调度器、job实例工厂等),然后通过CommandLineRunner的实现类,重写其run()方法,该方法根据启动传入的参数判断哪些配置任务信息需要进行执行,并调用QuartzManager工具类启动相应任务。 二、代码实例: 1。引入相关依赖dependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootstarterartifactIddependency!quartz动态定时任务dependencygroupIdorg。springframework。bootgroupIdspringbootstarterquartzartifactIddependency!导入lombok组件简化代码dependencygroupIdorg。projectlombokgroupIdlombokartifactIdscopeprovidedscope!只在编译阶段生效,不需要打入包中dependency!导入常用辅助工具类dependencygroupIdcn。hutoolgroupIdhutoolallartifactIdversion5。1。0versiondependency!测试dependencygroupIdorg。springframework。bootgroupIdspringbootstartertestartifactIdscopetestscopedependencydependencies!将项目打包成可执行jar包buildpluginsplugingroupIdorg。springframework。bootgroupIdspringbootmavenpluginartifactId!如果没有配置fork属性,热部署不会起效configurationforktrueforkconfigurationpluginpluginsbuild 2。【必须】quartz框架配置文件quartz。properties,主要配置quartz线程池、任务列表等 说明:由于本例采用非Web项目,故application。yml配置文件可以不配。实际业务中可以配置些动态数据源,实现定时任务的业务逻辑〔非必须〕设置调度器实例名称,默认QuartzSchedulerorg。quartz。scheduler。instanceNamequartzscheduler〔非必须〕设置调度器实例ID,默认值NONCLUSTEREDorg。quartz。scheduler。instanceIdAUTO〔必须〕设置线程池实现类(一般使用SimpleThreadPool定长线程池)org。quartz。threadPool。classorg。quartz。simpl。SimpleThreadPool〔必须〕设置线程数(无默认值,一般设置为1100的整数)org。quartz。threadPool。threadCount5〔非必须〕设置线程的优先级(最大为9,最小为1,默认为5)org。quartz。threadPool。threadPriority5〔非必须〕设置是否为守护线程(默认为true)org。quartz。threadPool。threadsInheritContextClassLoaderOfInitializingThreadtrue〔非必须〕线程前缀(默认为调度器实例名称Worker)org。quartz。threadPool。threadNamePrefixquartzschedulerthread〔非必须〕设置schedule相关信息存储方法(默认存储在内存中)org。quartz。jobStore。classorg。quartz。simpl。RAMJobStore〔非必须〕最大能忍受的触发超时时间(默认为60秒)org。quartz。jobStore。misfireThreshold60000配置定时任务jobName:任务名称,建议英文或任务描述拼音码首拼〔必须〕jobDesc:任务中文描述〔必须〕classMethod:任务执行的方法〔必须〕jobCron:任务的Cron表达式〔必须〕第1个定时任务springboot。quartz。scheduledJobs〔0〕。jobNamejob1springboot。quartz。scheduledJobs〔0〕。jobDesc测试任务1springboot。quartz。scheduledJobs〔0〕。classMethodcom。wwu。jobs。FirstJobspringboot。quartz。scheduledJobs〔0〕。jobCron010?第2个定时任务springboot。quartz。scheduledJobs〔1〕。jobNamejob2springboot。quartz。scheduledJobs〔1〕。jobDesc测试任务2springboot。quartz。scheduledJobs〔1〕。classMethodcom。wwu。jobs。SecondJobspringboot。quartz。scheduledJobs〔1〕。jobCron015?第3个定时任务springboot。quartz。scheduledJobs〔2〕。jobNamejob3springboot。quartz。scheduledJobs〔2〕。jobDesc测试任务3springboot。quartz。scheduledJobs〔2〕。classMethodcom。wwu。jobs。ThirdJobspringboot。quartz。scheduledJobs〔2〕。jobCron00519?2 3。【非必须】slf4j日志分级切割配置文件logbackspring。?xmlversion1。0encodingUTF8?!scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。scanPeriod:设置监测配置文件是否有修改的时间间隔,默认的时间间隔为1分钟,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。debug:当此属性设置为true时,将打印出logback内部ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a信息,实时查看logback运行状态。默认值为false。configurationscanfalsescanPeriod60secondsdebugfalse!property标签用来定义变量值的标签,有两个属性变量名称name和变量值可以使{}来使用变量!定义ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a的根目录:在项目所在盘符的根目录下创建logs文件夹propertynamesysLog。logDirvalue。logs!定义ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件名称propertynamesysLog。logNamevaluesystem!保留最近n天的归档ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志apropertynamesysLog。maxHistoryvalue7!每个文件的大小propertynamesysLog。maxFileSizevalue50MB!异步缓冲队列的深度,该值会影响性能。默认值为256propertynamesysLog。queueSizevalue512!输出ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件编码propertynamesysLog。fileCharsetvalueUTF8!输出ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件格式propertynamesysLog。patternvalued{yyyyMMddHH:mm:ss。SSS}〔thread〕〔5level〕〔logger{50}:line〕msgn!控制台策略打印ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a的相关配置!ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a格式encoderpattern{sysLog。pattern}patternencoderappender!文件输出策略打印ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a的相关配置!切分Info级别ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a!过滤INFO级别ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志afilterclassch。qos。logback。classic。filter。LevelFilter!过滤INFOlevelINFOlevel!匹配到就输出onMatchACCEPTonMatch!没有匹配就禁止onMismatchDENYonMismatchfilter!该属性存在则表示当天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a路径及名称,若不存在则使用FileNamePattern属性之作为当天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a路径及名称如果同时有File和FileNamePattern则明天会自动把今天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a改名为今天的日期。file{sysLog。logDir}{sysLog。logName}info。txtfile!滚动策略,按照时间滚动TimeBasedRollingPolicyrollingPolicyclassch。qos。logback。core。rolling。TimeBasedRollingPolicy!滚动时产生的文件的存放位置及文件名称d{yyyyMMdd}:按天进行ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a滚动i:当文件大小超过maxFileSize时,按照i进行文件滚动fileNamePattern{sysLog。logDir}{sysLog。logName}infod{yyyyMMdd}i。txtfileNamePattern!只保留最近7天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a,超出数量就删除旧文件及为归档而创建的目录MaxHistory{sysLog。maxHistory}MaxHistory!当ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件超过maxFileSize指定的大小是,根据上面提到的i进行ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件滚动此处必须配置timeBasedFileNamingAndTriggeringPolicy,否则无法实现按文件大小进行滚动。timeBasedFileNamingAndTriggeringPolicyclassch。qos。logback。core。rolling。SizeAndTimeBasedFNATPmaxFileSize{sysLog。maxFileSize}maxFileSizetimeBasedFileNamingAndTriggeringPolicyrollingPolicy!ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a输出格式:encodercharset{sysLog。fileCharset}charsetpattern{sysLog。pattern}patternencoderappender!切分WARN级别以上ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a!过滤WARN级别以上ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志afilterclassch。qos。logback。classic。filter。ThresholdFilter!过滤ERRORlevelWARNlevelfilter!该属性存在则表示当天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a路径及名称,若不存在则使用FileNamePattern属性之作为当天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a路径及名称如果同时有File和FileNamePattern则明天会自动把今天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a改名为今天的日期。file{sysLog。logDir}{sysLog。logName}error。txtfile!滚动策略,按照时间滚动TimeBasedRollingPolicyrollingPolicyclassch。qos。logback。core。rolling。TimeBasedRollingPolicy!滚动时产生的文件的存放位置及文件名称d{yyyyMMdd}:按天进行ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a滚动i:当文件大小超过maxFileSize时,按照i进行文件滚动fileNamePattern{sysLog。logDir}{sysLog。logName}errord{yyyyMMdd}i。txtfileNamePattern!只保留最近7天的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a,超出数量就删除旧文件及为归档而创建的目录MaxHistory{maxHistory}MaxHistory!当ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件超过maxFileSize指定的大小是,根据上面提到的i进行ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a文件滚动此处必须配置timeBasedFileNamingAndTriggeringPolicy,否则无法实现按文件大小进行滚动。timeBasedFileNamingAndTriggeringPolicyclassch。qos。logback。core。rolling。SizeAndTimeBasedFNATPmaxFileSize{sysLog。maxFileSize}maxFileSizetimeBasedFileNamingAndTriggeringPolicyrollingPolicy!ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a输出格式:encodercharset{sysLog。fileCharset}charsetpattern{sysLog。pattern}patternencoderappender!异步ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a记录配置!不丢失ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a。默认的,如果队列的80已满,则会丢弃TRACT、DEBUG、INFO级别的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志adiscardingThreshold0discardingThreshold!更改默认的队列的深度,该值会影响性能。默认值为256queueSize{sysLog。queueSize}queueSizeappenderdiscardingThreshold0discardingThresholdqueueSize{sysLog。queueSize}queueSizeappender!下面配置一些第三方包的ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a过滤级别,用于避免刷屏loggernameorg。springframeworklevelWARNloggernameorg。thymeleaflevelWARNloggernameorg。apachelevelWARN!ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a输出级别rootlevelINFOroot!!测试环境和开发环境ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a输出级别为debug!springProfilenametest,dev!rootlevelDEBUG!!rootlevelDEBUG!!!!root!springProfile!!生产环境ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a输出级别为info!springProfilenameprod!rootlevelINFO!!!!root!springProfileconfiguration 4。创建任务实体类ScheduledJob。java,在初始化任务列表时创建任务明细(JobDetail)及触发器(Trigger)packagecom。wwu。importlombok。Ddescription:任务实体类author一蓑烟雨version1。0。0date2023041616:53DatapublicclassScheduledJob{任务IDprivateStringjobId;任务名称privateStringjobN任务描述privateStringjobD任务表达式privateStringjobC任务表达式中文privateStringjobCronZh;任务分组编码privateStringjobG任务分组名称privateStringjobGroupN执行方法privateStringclassM任务执行状态(Y,执行成功;N,执行失败;空,未执行)privateStringjobS任务可用状态(Y:可用;N:不可用)privateStringenabledF下次执行时间privateStringnextExecT} 5。创建quartz配置类quartzConfig。java,主要用来配置线程池、调度器、job实例工厂等packagecom。wwu。importcom。wwu。entity。ScheduledJimportlombok。Dimportorg。quartz。Simportorg。quartz。spi。JobFimportorg。springframework。beans。factory。config。PropertiesFactoryBimportorg。springframework。boot。context。properties。ConfigurationPimportorg。springframework。context。annotation。Bimportorg。springframework。context。annotation。Cimportorg。springframework。context。annotation。PropertySimportorg。springframework。core。io。ClassPathRimportorg。springframework。scheduling。quartz。SchedulerFactoryBimportjavax。annotation。Rimportjava。io。IOEimportjava。util。Limportjava。util。Pdescription:quartz配置类,配置线程池、调度器、job实例工厂等author一蓑烟雨version1。0。0date2023041618:08DataConfigurationPropertySource(classpath:quartz。properties)ConfigurationProperties(prefixspringboot。quartz)publicclassQuartzConfig{注入quartz。properties配置文件中的任务privateListScheduledJobscheduledJResourceprivateJobFactoryjobFdescription:SchedulerFactoryBean工厂returnorg。springframework。scheduling。quartz。SchedulerFactoryBeanauthor一蓑烟雨date202341618:10BeanpublicSchedulerFactoryBeanschedulerFactoryBean(){创建SchedulerFactoryBean实例SchedulerFactoryBeanschedulerFactoryBeannewSchedulerFactoryBean();try{设置是否覆盖已存在的job,为True表示有相同名称和分组的触发器和任务存在时则替换schedulerFactoryBean。setOverwriteExistingJobs(true);设置是否自动启动SchedulerschedulerFactoryBean。setAutoStartup(true);设置quartz属性schedulerFactoryBean。setQuartzProperties(quartzProperties());设置任务调度器schedulerFactoryBean。setJobFactory(jobFactory);}catch(Exceptione){e。printStackTrace();}returnschedulerFactoryB}description:读取quartz配置文件中配置相关属性returnjava。util。Propertiesauthor一蓑烟雨date202341717:18BeanpublicPropertiesquartzProperties()throwsIOException{PropertiesFactoryBeanpropertiesFactoryBeannewPropertiesFactoryBean();propertiesFactoryBean。setLocation(newClassPathResource(quartz。properties));在quartz。properties中的属性被读取并注入后再初始化对象propertiesFactoryBean。afterPropertiesSet();returnpropertiesFactoryBean。getObject();}description:初始化schedule任务调度器returnorg。quartz。Schedulerauthor一蓑烟雨date202341618:12BeanpublicSchedulerscheduler(){returnschedulerFactoryBean()。getScheduler();}} 6。创建job实例工厂JobFactory。javapackagecom。wwu。importorg。quartz。spi。TriggerFiredBimportorg。springframework。beans。factory。config。AutowireCapableBeanFimportorg。springframework。scheduling。quartz。AdaptableJobFimportorg。springframework。stereotype。Cimportjavax。annotation。Rdescription:创建job实例工厂author一蓑烟雨version1。0。0date2023041618:31ComponentpublicclassJobFactoryextendsAdaptableJobFactory{ResourceprivateAutowireCapableBeanFactorycapableBeanFOverrideprotectedObjectcreateJobInstance(TriggerFiredBundlebundle)throwsException{调用父类的方法ObjectjobInstancesuper。createJobInstance(bundle);进行注入capableBeanFactory。autowireBean(jobInstance);returnjobI}} 7。创建CommandLineRunner接口的实现类QuartzCommandRunner。java,作用为启动项目时预先加载配置文件中的所有定时任务,并根据启动参数启动相应任务packagecom。wwu。importcom。wwu。entity。ScheduledJimportlombok。extern。slf4j。Slf4j;importorg。quartz。SchedulerEimportorg。springframework。boot。CommandLineRimportorg。springframework。core。annotation。Oimportorg。springframework。stereotype。Cimportjavax。annotation。Rimportjava。util。ArrayLimportjava。util。Aimportjava。util。Ldescription:启动项目时预先加载配置文件中的所有定时任务,并根据启动参数启动相应任务CommandLineRunner中的Order表示在项目启动时预先加载的类author一蓑烟雨version1。0。0date2023041618:13Slf4jComponentOrder(1)publicclassQuartzCommandRunnerimplementsCommandLineRunner{ResourceprivateQuartzManagerquartzMResourceprivateQuartzConfigquartzCdescription:重写run方法param〔args〕returnvoidauthor一蓑烟雨date202341715:37Overridepublicvoidrun(String。。。args)throwsException{try{初始化需要启动的任务列表ListScheduledJobjobListinitSchedule(args);for(ScheduledJobscheduledJob:jobList){执行任务quartzManager。startJob(scheduledJob);}}catch(Exceptione){e。printStackTrace();}}description:初始化需要执行的任务列表param〔args〕returnjava。util。Listcom。wwu。entity。ScheduledJobauthor一蓑烟雨date202341715:37publicListScheduledJobinitSchedule(String。。。args)throwsSchedulerException{ListScheduledJobjobsnewArrayListScheduledJob();try{log。info(。。。根据参数加载配置文件quartz。properties中任务列表开始。。。);1。遍历启动程序时传入的接口类型参数String〔〕typePfor(Stringarg:args){if(arg。startsWith(type)){typeParamarg。substring(5)。split(,);}}2。遍历quartz。properties配置文件中任务列表for(ScheduledJobscheduledJob:quartzConfig。getScheduledJobs()){如果启动传入了参数,则按照参数加载启动任务if(typeParam!nulltypeParam。length0){遍历参数值和任务列表,若相同则加入到启动任务列表中Arrays。stream(typeParam)。forEach(param{if(param。trim()。equals(scheduledJob。getJobName())){jobs。add(scheduledJob);log。info(。。。。。。scheduledJob);}});}else{没有启动参数,默认启动配置文件中的所有任务jobs。add(scheduledJob);log。info(。。。。。。scheduledJob);}}log。info(。。。。。。共加载{}条任务需要执行。。。。。。,jobs。size());}catch(Exceptione){e。printStackTrace();}log。info(。。。根据参数加载配置文件quartz。properties中任务列表结束。。。);}} 8。创建quartz定时任务工具类QuartzManager。java,对任务进行管理(创建、启动、修改、删除、暂停)packagecom。wwu。importcom。wwu。entity。ScheduledJimportorg。quartz。;importorg。quartz。impl。matchers。GroupMimportorg。springframework。stereotype。Cimportjavax。annotation。Rimportjava。util。ArrayLimportjava。util。Limportjava。util。Sdescription:quartz定时任务工具类,对任务进行管理(创建、启动、修改、删除、暂停)author一蓑烟雨version1。0。0date2023041617:11ComponentpublicclassQuartzManager{注入QuartzConfig中定义的任务调度器schedulerResourceprivateSdescription:获取所有任务信息returnjava。util。Listcom。wwu。entity。ScheduledJobauthor一蓑烟雨date202341618:59publicListScheduledJobgetAllJobInfo()throwsSchedulerException{ListScheduledJobjobListnewArrayListScheduledJob();GroupMatcherJobKeymatcherGroupMatcher。anyJobGroup();SetJobKeyjobKeysscheduler。getJobKeys(matcher);for(JobKeyjobKey:jobKeys){L?extendsTriggertriggersscheduler。getTriggersOfJob(jobKey);for(Triggertrigger:triggers){ScheduledJobjobnewScheduledJob();job。setJobName(jobKey。getName());job。setJobGroup(jobKey。getGroup());job。setJobDesc(trigger。getDescription());Trigger。TriggerStatetriggerStatescheduler。getTriggerState(trigger。getKey());job。setJobStatus(triggerState。name());if(triggerinstanceofCronTrigger){CronTriggercronTrigger(CronTrigger)job。setJobCron(cronTrigger。getCronExpression());}jobList。add(job);}}returnjobL}description:获取某个任务的信息paramscheduledJobreturnjava。lang。Stringauthor一蓑烟雨date202341618:07publicStringgetJobInfo(ScheduledJobscheduledJob)throwsSchedulerException{TriggerKeytriggerKeynewTriggerKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());System。out。println(triggerKey:triggerKey);CronTriggercronTrigger(CronTrigger)scheduler。getTrigger(triggerKey);returnString。format(time:s,state:s,cronTrigger。getCronExpression(),scheduler。getTriggerState(triggerKey)。name());}description:获取任务数量returnjava。lang。Stringauthor一蓑烟雨date202341618:07publicintgetJobSize()throwsSchedulerException{GroupMatcherJobKeymatcherGroupMatcher。anyJobGroup();SetJobKeyjobKeysscheduler。getJobKeys(matcher);returnjobKeys。size();}description:获取触发器状态paramscheduledJobreturnNONE:不存在;NORMAL:正常;PAUSED:暂停;COMPLETE:完成;ERROR:错误;BLOCKED:阻塞author一蓑烟雨date202341718:56publicStringgetTriggerState(ScheduledJobscheduledJob)throwsSchedulerException{TriggerKeytriggerKeynewTriggerKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());Trigger。TriggerStatetriggerStatescheduler。getTriggerState(triggerKey);returntriggerState。name();}description:开启某个任务paramscheduledJobreturnvoidauthor一蓑烟雨date202341618:05publicvoidstartJob(ScheduledJobscheduledJob)throwsException{JobKeyjobKeyJobKey。jobKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());不存在则添加任务if(!scheduler。checkExists(jobKey)){addJobTask(scheduledJob);}启动scheduler。start();}description:添加某个任务paramscheduledJobreturnvoidauthor一蓑烟雨date202341618:01publicbooleanaddJobTask(ScheduledJobscheduledJob)throwsException{利用反射机制获取任务执行类C?extendsJobjobClass(C?extendsJob)(Class。forName(scheduledJob。getClassMethod())。newInstance()。getClass());设置任务明细,调用定义的任务逻辑JobDetailjobDetailJobBuilder。newJob(jobClass)添加认证信息(也可通过usingJobData传参数)。withIdentity(scheduledJob。getJobName(),scheduledJob。getJobGroup())执行。build();设置任务触发器,cornTrigger规则定义执行规则CronTriggercronTriggerTriggerBuilder。newTrigger()通过键值对方式向job实现业务逻辑传参数。usingJobData(jobDesc,scheduledJob。getJobDesc())。usingJobData(jobCron,scheduledJob。getJobCron())添加认证信息。withIdentity(scheduledJob。getJobName(),scheduledJob。getJobGroup())程序启动后间隔多久开始执行任务。startAt(DateBuilder。futureDate(5,DateBuilder。IntervalUnit。SECOND))执行Cron表达时。withSchedule(CronScheduleBuilder。cronSchedule(scheduledJob。getJobCron()))执行。build();把任务明细和触发器注册到任务调度中scheduler。scheduleJob(jobDetail,cronTrigger);}description:修改任务的Cron表达式paramscheduledJobreturnbooleanauthor一蓑烟雨date202341617:46publicbooleanmodifyJob(ScheduledJobscheduledJob)throwsSchedulerException{TriggerKeytriggerKeynewTriggerKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());CronTriggercronTrigger(CronTrigger)scheduler。getTrigger(triggerKey);StringoldTimecronTrigger。getCronExpression();if(!oldTime。equalsIgnoreCase(scheduledJob。getJobCron())){CronScheduleBuildercronScheduleBuilderCronScheduleBuilder。cronSchedule(scheduledJob。getJobCron());CronTriggertriggerTriggerBuilder。newTrigger()。withIdentity(scheduledJob。getJobName(),scheduledJob。getJobGroup())。withSchedule(cronScheduleBuilder)。build();scheduler。rescheduleJob(triggerKey,trigger);}else{}}description:暂停所有任务returnvoidauthor一蓑烟雨date202341617:41publicvoidpauseAllJob()throwsSchedulerException{scheduler。pauseAll();}description:暂停某个任务paramscheduledJobreturnvoidauthor一蓑烟雨date202341617:41publicvoidpauseJob(ScheduledJobscheduledJob)throwsSchedulerException{JobKeyjobKeyJobKey。jobKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());JobDetailjobDetailscheduler。getJobDetail(jobKey);if(jobDetailnull){}scheduler。pauseJob(jobKey);}description:恢复所有任务returnvoidauthor一蓑烟雨date202341617:38publicvoidresumeAllJob()throwsSchedulerException{scheduler。resumeAll();}description:恢复某个任务paramscheduledJobreturnvoidauthor一蓑烟雨date202341617:39publicvoidresumeJob(ScheduledJobscheduledJob)throwsSchedulerException{JobKeyjobKeyJobKey。jobKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());JobDetailjobDetailscheduler。getJobDetail(jobKey);if(jobDetailnull){}scheduler。resumeJob(jobKey);}description:删除任务paramscheduledJobreturnvoidauthor一蓑烟雨date202341617:32publicvoiddeleteJob(ScheduledJobscheduledJob)throwsSchedulerException{JobKeyjobKeyJobKey。jobKey(scheduledJob。getJobName(),scheduledJob。getJobGroup());JobDetailjobDetailscheduler。getJobDetail(jobKey);if(jobDetailnull){}scheduler。deleteJob(jobKey);}} 8。依次创建quartz中对应任务的job业务类FirstJob。java、SecondJob。java和ThirdJob。java,这些job业务类需要实现Job接口packagecom。wwu。importlombok。extern。slf4j。Slf4j;importorg。quartz。;description:定义任务逻辑,需要实现Job接口并重写execute()方法DisallowConcurrentExecution注解用来避免同一个任务由于执行时间过长导致并发执行author一蓑烟雨version1。0。0date2023041619:51Slf4jDisallowConcurrentExecutionpublicclassFirstJobimplementsJob{Overridepublicvoidexecute(JobExecutionContextcontext)throwsJobExecutionException{获取触发器cronTrigger传递的参数JobDataMapdataMapcontext。getTrigger()。getJobDataMap();log。info(【{}】任务执行开始,执行频率为:{},dataMap。get(jobDesc),dataMap。get(jobCron));try{Thread。sleep(30000);}catch(InterruptedExceptione){e。printStackTrace();}log。info(【{}】任务执行结束,dataMap。get(jobDesc));}} 9。在IDEA开发工具配置参数或将项目打包成jar并通过命令行传参执行(如typejob1,job2),即可看到传入参数对应的任务已开始执行