96SEO 2026-02-20 01:59 0
{System.out.println(定时任务执行了......

LocalDateTime.now().format(DateTimeFormatter.ofPattern(yyyy-MM-dd
HH:mm:ss)));}};//执行定时任务timer.schedule(task,new
【1】搭建SpringBoot工程导入spring-boot-starter-web即可不需导入任何其他依赖,pom如下
xmlnshttp://maven.apache.org/POM/4.0.0
xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.6/versionrelativePath/
--/parentgroupIdtop.psjj/groupIdartifactIdtask-study/artifactIdversion0.0.1-SNAPSHOT/versionnametask-study/namedescriptiontask-study/descriptionpropertiesjava.version8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project
org.springframework.boot.SpringApplication;
org.springframework.boot.autoconfigure.SpringBootApplication;
org.springframework.scheduling.annotation.EnableScheduling;SpringBootApplication
{SpringApplication.run(TaskStudyApplication.class,
{System.out.println(Thread.currentThread().getName()task1--LocalDateTime.now());}
{System.out.println(Thread.currentThread().getName()task1--LocalDateTime.now());Thread.sleep(5000);}
执行任务按照单线程执行并合理执行不会因为第一个执行任务时间过长而去执行第二个任务
2.Spring-task是单线程的处理任务处理任务能力有限不建议处理分布式架构的任务调度
{System.out.println(Thread.currentThread().getName():task2---
LocalDateTime.now());}Scheduled(cron
{System.out.println(Thread.currentThread().getName():task1---
LocalDateTime.now());Thread.sleep(5000);}
字符可以用在日和周几字段,它用来指定不明确的值。
这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。
在后面的例子中可以看到其含义。
字符被用来指定一个值的范。
比如在小时字段中设为10-12表示10
字符指定数个值。
比如在周几字段中设为MON,WED,FRI,表示the
字符用来指定一个值的的增加幅度。
比如在秒字段中设置为0/15表示第
秒开始。
每个字段都有一系列可以开始或结束的数值。
对于秒和分字段来说其数值范围为
字符可用在日和周几这两个字段。
它是last的缩写,但是在这两个字段中有不同的含义。
日字段中的L表示一个月中的最后一天,对于一月就是
SAT。
但是如果在周几字段中使用时跟在某个数字之后,它表示该月最后一个星期×。
比如6L表示该月最后一个周五。
当使用L选项时,指定确定的列表或者范围非常重要否则你会被结果搞糊涂的。
可用于日字段。
用来指定历给定日期最近的工作日(周一到周五)。
比如将日字段设为15W意为:
号为周二,那么当天就会触发。
如果日字段设为1W,而一号是周六,会于下周一即当月的
号触发,它不会越过当月的值的范围边界。
W字符只能用于日字段的值为单独的一天而不是一系列值的时候。
L和W可以组合用于“日”字段表示为LW意为该月最后一个工作日。
字符可用于周几字段。
该字符表示该月第几个周×。
比如6#3表示该月第三个周五(
该月第五个周三。
注意如果你指定#5该月没有第五个周×该月是不会触发的。
字符可用于日和周几字段它是calendar的缩写。
它表示为基于相关的日历所计算出的值如果有。
如果没有关联的日历,那它等同于包含全部日历。
日字段值为5C表示日历中的第一天或者
号以后。
周几字段值为1C则表示日历中的第一天或者周日以后。
对于月份字段和周几字段来说合法的字符都不是大小写敏感的。
scheduling领域又一个开源项目完全由Java开发可以用来执行定时任务类似于java.util.Timer。
但是相较于Timer
需要实现的任务类实现execute方法执行后完成任务触发器Trigger
CronTrigger调度器Scheduler任务调度器负责基于Trigger触发器来执行job任务
xmlnshttp://maven.apache.org/POM/4.0.0
xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.6/versionrelativePath/
--/parentgroupIdtop.psjj/groupIdartifactIdquartz-study/artifactIdversion0.0.1-SNAPSHOT/versionnamequartz-study/namedescriptionquartz-study/descriptionpropertiesjava.version8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-quartz/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project
StdSchedulerFactory();Scheduler
factory.getScheduler();//2.创建JobDetail实例并与MyJob类绑定JobDetail
JobBuilder.newJob(MyJob.class)//指定任务名组名.withIdentity(job1,group1).build();//3.构建Trigger实例每隔3s执行一次Trigger
TriggerBuilder.newTrigger()//指定触发器名字组名.withIdentity(trigger1,group1)//从现在触发.startNow()//触发规则3s触发一次.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();//4.执行
开启任务调度器scheduler.scheduleJob(job,trigger);System.out.println(System.currentTimeMillis());scheduler.start();}
主要字段含义name任务名称group任务分组默认分组DEFAULTjobClass要执行的Job实现类jobDataMap任务参数信息JobDetail、Trigger都可以使用JobDataMap来设置一些参数或者信息
每次Scheduler调度执行一个Job的时候首先会拿到对应的Job然后创建该Job实例再去执行Job中的execute()的内容任务执行结束后关联的Job对象实例会被释放且会被JVM
这是因为任务是有可能并发执行如果Scheduler直接使用Job就会存在对同一个Job实例并发访问的问题。
方式Sheduler每次执行都会根据JobDetail创建一个新的Job实例这样就可以
org.quartz.impl.StdSchedulerFactory;
org.springframework.scheduling.annotation.Scheduled;/***
{//test方法之后执行一次所以使用main方法public
StdSchedulerFactory();Scheduler
factory.getScheduler();//创建JobDataMap,可携带的参数JobDataMap
JobDataMap();jobDataMap.put(param1,value1);jobDataMap.put(param2,value2);//2.创建JobDetail实例与MyJob类绑定JobDetail
JobBuilder.newJob(MyJob.class)//指定任务名组名.withIdentity(job1,group1)//携带参数JobDataMap.setJobData(jobDataMap).build();//3.构建Trigger实例每个3s执行一次Trigger
TriggerBuilder.newTrigger()//指定触发器名字组名.withIdentity(trigger1,group1)//什么时候触发.startNow()//触发规则3秒触发一次//简单的SimpleScheduleBuilder构建起.withSchedule(SimpleScheduleBuilder.simpleSchedule()//每3s触发一次.withIntervalInSeconds(3)//永远触发.repeatForever()).build();//4.调度器执行任务//把job和trigger给schedulescheduler.scheduleJob(job,trigger);System.out.println(System.currentTimeMillis());//启动任务scheduler.start();}
jobExecutionContext.getJobDetail().getJobDataMap();System.out.println(任务被执行了jobDataMap.get(param1)jobDataMap.get(param2));}
这是比较简单的一类触发器用它能实现很多基础的应用。
使用它的主要场景包括
TriggerBuilder.newTrigger().withIdentity(trigger2,group1).startNow().withSchedule(//使用简单触发器SimpleScheduleBuilder.simpleSchedule().//3s间隔执行withIntervalInSeconds(3).//执行6次
count1withRepeatCount(5)).build();
是基于日历的任务调度器在实际应用中更加常用。
虽然很常用但是知识点都一样只是可以通过表达式来设置时间而已。
使用方式就是绑定调度器时换一下
TriggerBuilder.newTrigger().withIdentity(trigger2,group1).startNow().withSchedule(//使用日历触发器CronScheduleBuilder.cronSchedule(0/1
接下来实现SpringBoot整合Quartz动态实现任务调度动态任务调度ui参考
xmlnshttp://maven.apache.org/POM/4.0.0
xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.6/versionrelativePath/
--/parentgroupIdtop.psjj/groupIdartifactIdquartz-study/artifactIdversion0.0.1-SNAPSHOT/versionnamequartz-study/namedescriptionquartz-study/descriptionpropertiesjava.version8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-quartz/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.26/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.60/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project2编写application.yml配置文件内容如下
spring:datasource:driver-class-name:
com.mysql.cj.jdbc.Driverusername:
jdbc:mysql://127.0.0.1:3306/quartz?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai#
数据源dataSource:globalJobDataSource:#
jdbc:mysql://127.0.0.1:3306/quartz?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghaidriver:
com.mysql.cj.jdbc.DrivermaxConnections:
hikaricpscheduler:instanceName:
com.alibaba.druid.pool.DruidDataSourcejobStore:#
JobStoreTX将用于独立环境提交和回滚都将由这个类处理class:
org.quartz.impl.jdbcjobstore.JobStoreTX#
org.quartz.impl.jdbcjobstore.StdJDBCDelegate#
失效阈值(只有配置了这个时间超时策略根据这个时间才有效)misfireThreshold:
org.quartz.simpl.SimpleThreadPool#
这里面有quartz的数据源线程池集群和misfire相关配置简单配置更多的配置可以到官网查看。
spring.quartz.jdbc.initialize-schema:
DisallowConcurrentExecution这个注解的作用就是同一个任务必须在上一次执行完毕之后再按照corn时间执行不会并行执行*
PersistJobDataAfterExecution这个注解的作用就是下一个任务用到上一个任务的修改数据定时任务里面的jobData数据流转*/DisallowConcurrentExecution
executeInternal(JobExecutionContext
{Thread.sleep(9000);System.out.println(任务1执行完毕...
}这个类就是继承的QuartzJobBean当然也可以实现Job接口这个类就是任务需要具体执行的业务操作类类上面添加了两个注解这两个注解的目的就是让同一个任务必须在上一个任务执行完毕之后再按照触发后续执行以及定时任务里面的JobDataMap能够在任务中流转以及修改更新不添加注解的情况下JobDataMap里面的数据不能在任务之间流转以及任务的触发不会参照上一任务是否执行完毕。
添加任务*/SuppressWarnings(unchecked)public
{Objects.requireNonNull(jobInfo,
JobKey.jobKey(jobInfo.getJobName(),
(!scheduler.checkExists(jobKey))
(ClassJob)Class.forName(jobInfo.getClassName());//
JobBuilder.newJob(jobClass).withIdentity(jobKey).withIdentity(jobInfo.getJobName(),
jobInfo.getJobGroup()).withDescription(jobInfo.getJobName()).build();//
配置信息jobDetail.getJobDataMap().put(config,
TriggerKey.triggerKey(jobInfo.getTriggerName(),
TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCron()).withMisfireHandlingInstructionDoNothing()).build();scheduler.scheduleJob(jobDetail,
SchedulerException(jobInfo.getJobName()
(scheduler.checkExists(jobKey))
{scheduler.pauseJob(jobKey);}}/***
(scheduler.checkExists(jobKey))
{scheduler.resumeJob(jobKey);}}/***
(scheduler.checkExists(jobKey))
TriggerKey.triggerKey(jobInfo.getTriggerName(),
jobInfo.getTriggerGroup());//scheduler.getTrigger()//scheduler.rescheduleJob()return
scheduler.deleteJob(jobKey);}return
(!scheduler.checkExists(jobKey))
scheduler.getTriggersOfJob(jobKey);if
SchedulerException(未获取到触发器信息);}TriggerKey
triggers.get(0).getKey();Trigger.TriggerState
scheduler.getTriggerState(triggerKey);JobDetail
scheduler.getJobDetail(jobKey);JobInfo
JobInfo();jobInfo.setJobName(jobGroup);jobInfo.setJobGroup(jobName);jobInfo.setTriggerName(triggerKey.getName());jobInfo.setTriggerGroup(triggerKey.getGroup());jobInfo.setClassName(jobDetail.getJobClass().getName());jobInfo.setStatus(triggerState.toString());if
(Objects.nonNull(jobDetail.getJobDataMap()))
{jobInfo.setConfig(JSONObject.toJSONString(jobDetail.getJobDataMap()));}CronTrigger
triggers.get(0);jobInfo.setCron(theTrigger.getCronExpression());return
查询所有的任务*/RequestMapping(/all)public
scheduler.getTriggerGroupNames();for
scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName));for
scheduler.getTrigger(triggerKey);JobKey
jobHandler.getJobInfo(jobKey.getGroup(),
jobKey.getName());jobInfos.add(jobInfo);}}return
{jobHandler.addJob(jobInfo);return
暂停任务*/RequestMapping(/pause)public
pauseJob(RequestParam(jobGroup)
继续任务*/RequestMapping(/continue)public
continueJob(RequestParam(jobGroup)
{jobHandler.continueJob(jobGroup,
删除任务*/RequestMapping(/delete)public
deleteJob(RequestParam(jobGroup)
JobInfo();jobInfo.setJobGroup(group1);jobInfo.setJobName(job2);jobInfo.setCron(0/1
?);jobInfo.setClassName(com.sh.task.MyTask);jobInfo.setTriggerName(trigger1);jobInfo.setTriggerGroup(triggerGroup1);this.addJob(jobInfo);}
结论单线程运行任务不同任务之间串行任务A运行时间会响应任务B运行间隔
executeInternal(JobExecutionContext
init(){addMyTask();addMyTask2();
JobInfo();jobInfo.setJobName(job1);jobInfo.setJobGroup(group1);jobInfo.setTriggerName(trigger1);jobInfo.setTriggerGroup(triggerGroup1);jobInfo.setClassName(top.psjj.task.MyTask);jobInfo.setCron(0/1
JobInfo();jobInfo.setJobName(job2);jobInfo.setJobGroup(group1);jobInfo.setTriggerName(trigger2);jobInfo.setTriggerGroup(triggerGroup1);jobInfo.setClassName(top.psjj.task.MyTask2);jobInfo.setCron(0/1
显然任务2还是1s执行一次没有收到任务1执行时间干扰这是任务2和任务1用的线程不同。
如果任务调度没有持久化而任务又是基于动态设置不是开机自启的会有一个问题服务重启之后设置的任务都会失效了。
如果任务整合持久化之后设置的动态任务信息就会保存到数据库开机自启就会加载这些数据库信息就会按照原来的设置运行任务。
#spring.quartz.jdbc.initialize-schema:
Quartz是一个开源的作业调度框架用于在Java应用程序中调度任务。
Quartz集群和非集群的区别主要体现在以下几个方面
高可用性Quartz集群可以提供高可用性即使其中一个节点出现故障其他节点仍然可以继续工作。
而非集群模式下如果应用程序所在的服务器出现故障任务调度将会停止。
负载均衡Quartz集群可以通过将任务分配给不同的节点来实现负载均衡。
这意味着任务将在集群的各个节点上分布从而提高系统整体的性能和吞吐量。
非集群模式下所有的任务将在单个节点上运行可能会导致性能瓶颈。
数据共享Quartz集群可以共享任务调度的数据包括作业和触发器等。
这意味着当一个节点添加或删除任务时其他节点也能够感知到。
非集群模式下每个节点都有自己独立的任务调度数据可能导致数据不一致。
需要注意的是Quartz集群需要配置和管理多个节点可能需要更多的系统资源和维护工作。
非集群模式则相对简单适用于小规模的应用程序。
选择使用哪种模式应根据具体的需求和系统要求来决定。
答任务调度就是按照特定时间规则执行系统某个固定的业务逻辑。
任务调度底层是使用jdk的Timer实现的。
单体项目建议使用Spring-task任务调度技术分布式架构建议使用quartz任务调度框架。
Spring-task是单线程运行旳Quartz是多线程运行的且功能更为丰富支持作业管理。
答Spring-task是单线程且功能简单。
执行任务只需开启开关EnableScheduling在要执行的任务方法上加
任务A的执行时间会影响任务B的执行间隔但是任务A和任务B是两个任务不应该相互影响。
Quartz是多线程的高可用的任务调度框架支持持久化多线程集群模式且有固定组件结构Job、Trigger、scheduler。
他的优点一一说明
有固定组件有持久化功能这样就能基于Quartz开发一个任务调度系统通过UI界面去管理任务调度。
任务支持集群模式如果任务调度模块是一个集群n个节点那么任务调度不会因为一个节点挂掉而挂掉且任务在集群之间形成负载均衡。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback