城市直播房产教育博客汽车
投稿投诉
汽车报价
买车新车
博客专栏
专题精品
教育留学
高考读书
房产家居
彩票视频
直播黑猫
投资微博
城市上海
政务旅游

SpringBoot结合XXLJOB实现定时任务

8月24日 寒霜坞投稿
  前言
  上篇文章我们介绍了Quartz的使用,当时实现了两个简单的需求,不过最后我们总结的时候也提到Quartz有不少缺点,代码侵入太严重,所以本篇将介绍xxljob这个定时任务框架。Quartz的不足
  Quartz的不足:Quartz作为开源任务调度中的佼佼者,是任务调度的首选。但是在集群环境中,Quartz采用API的方式对任务进行管理,这样存在以下问题:通过调用API的方式操作任务,不人性化。需要持久化业务的QuartzJobBean到底层数据表中,系统侵入性相当严重。调度逻辑和QuartzJobBean耦合在同一个项目中,这将导致一个问题,在调度任务数量逐渐增多,同时调度任务逻辑逐渐加重的情况下,此时调度系统的性能将大大受限于业务。Xxljob介绍
  官方说明:XXLJOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
  通俗来讲:XXLJOB是一个任务调度框架,通过引入XXLJOB相关的依赖,按照相关格式撰写代码后,可在其可视化界面进行任务的启动,执行,中止以及包含了日志记录与查询和任务状态监控。
  更多详细介绍推荐阅读官方文档。项目实践SpringBoot集成XXLJOB
  SpringBoot集成XXLJOB主要分为以下两步:配置运行调度中心(xxljobadmin)配置运行执行器项目
  xxljobadmin可以从源码仓库中下载代码,代码地址有两个:GitHub:github。comxuxuelixxlGitee:gitee。comxuxueli0323
  下载完之后,在docdb目录下有数据库脚本tablesxxljob。sql,执行下脚本初始化调度数据库xxljob,如下图所示:
  配置调度中心
  将下载的源码解压,用IDEA打开,我们需要修改一下xxljobadmin中的一些配置。(我这里下载的是最新版2。3。1)
  1、修改application。properties,主要是配置一下datasource以及email,其他不需要改变。xxljob,datasourcespring。datasource。urljdbc:mysql:127。0。0。1:3306xxljob?useUnicodetruecharacterEncodingUTF8autoReconnecttrueserverTimezoneAsiaShanghaispring。datasource。usernamerootspring。datasource。passwordrootspring。datasource。driverclassnamecom。mysql。cj。jdbc。Driverxxljob,emailspring。mail。hostsmtp。qq。comspring。mail。port25spring。mail。username1739468244qq。comspring。mail。from1739468244qq。com此处不是邮箱登录密码,而是开启SMTP服务后的授权码spring。mail。passwordxxxxx复制代码
  2、修改logback。xml,配置日志输出路径,我是在解压的xxljob2。3。1项目包中新建了一个logs文件夹。propertynamelog。pathvalueUsersxxxxxljob2。3。1logsxxljobadmin。log复制代码
  然后启动项目,正常启动后,访问地址为:http:localhost:8080xxljobadmin,默认的账户为admin,密码为123456,访问后台管理系统后台。
  这样就表示调度中心已经搞定了,下一步就是创建执行器项目。创建执行器项目
  本项目与Quartz项目用的业务表和业务逻辑都一样,所以引入的依赖会比较多。环境配置
  1、引入依赖:parentgroupIdorg。springframework。bootgroupIdspringbootstarterparentartifactIdversion2。6。3versionrelativePathparentpropertiesjava。version1。8java。versionfastjson。version1。2。73fastjson。versionhutool。version5。5。1hutool。versionmysql。version8。0。19mysql。versionorg。mapstruct。version1。4。2。Finalorg。mapstruct。versionorg。projectlombok。version1。18。20org。projectlombok。versiondruid。version1。1。18druid。versionspringdoc。version1。6。9springdoc。versionpropertiesdependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependencydependencygroupIdorg。springframework。bootgroupIdspringbootstarteraopartifactIddependencydependencygroupIdcom。xuxueligroupIdxxljobcoreartifactIdversion2。3。1versiondependencydependencygroupIdcom。baomidougroupIdmybatisplusbootstarterartifactIdversion3。5。1versiondependencydependencygroupIdcom。baomidougroupIdmybatisplusartifactIdversion3。5。1versiondependencydependencygroupIdmysqlgroupIdmysqlconnectorjavaartifactIdversion{mysql。version}versionscoperuntimescopedependencydependencygroupIdcom。alibabagroupIddruidspringbootstarterartifactIdversion{druid。version}versiondependencydependencygroupIdorg。projectlombokgroupIdlombokartifactIdversion1。18。20versiondependencydependencygroupIdcom。alibaba。fastjson2groupIdfastjson2artifactIdversion2。0。12versiondependencydependencygroupIdorg。mapstructgroupIdmapstructartifactIdversion{org。mapstruct。version}versiondependencydependencygroupIdorg。mapstructgroupIdmapstructprocessorartifactIdversion{org。mapstruct。version}versiondependencydependencygroupIdcn。hutoolgroupIdhutoolallartifactIdversion{hutool。version}versiondependencydependencygroupIdorg。springdocgroupIdspringdocopenapiuiartifactIdversion{springdoc。version}versiondependencydependenciesbuildpluginsplugingroupIdorg。springframework。bootgroupIdspringbootmavenpluginartifactIdpluginpluginsbuild复制代码
  2、application。yml配置文件server:port:9090xxljobxxl:job:admin:addresses:http:127。0。0。1:8080xxljobadmin调度中心部署跟地址〔选填〕:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行执行器心跳注册和任务结果回调;为空则关闭自动注册;executor:appname:hreshjobexecutor执行器AppName〔选填〕:执行器心跳注册分组依据;为空则关闭自动注册ip:执行器IP〔选填〕:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于执行器注册和调度中心请求并触发任务;port:6666执行器端口号〔选填〕:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;logpath:Usersxxxxxljob2。3。1logsxxljob执行器运行日志文件存储磁盘路径〔选填〕:需要对该路径拥有读写权限;为空则使用默认路径;logretentiondays:30执行器日志文件保存天数〔选填〕:过期日志自动清理,限制值大于等于3时生效;否则,如1,关闭自动清理功能;accessToken:defaulttoken执行器通讯TOKEN〔选填〕:非空时启用;spring:application:name:xxljobpracticedatasource:type:com。alibaba。druid。pool。DruidDataSourcedriverclassname:com。mysql。cj。jdbc。Driverurl:jdbc:mysql:localhost:3306xxljob?serverTimezoneHongkongcharacterEncodingutf8useSSLfalseusername:rootpassword:rootmybatis:mapperlocations:classpath:mapperMapper。xmlconfiguration:logimpl:org。apache。ibatis。logging。stdout。StdOutImpllazyloadingenabled:true复制代码
  上述xxljob的logpath配置与调度中心的输出日志用的是同一个目录,accessToken也与调度中心的xxl。job。accessToken一致。核心类
  1、xxljob配置类ConfigurationpublicclassXxlJobConfig{Value({xxl。job。admin。addresses})privateStringadminAValue({xxl。job。executor。appname})privateStringappNValue({xxl。job。executor。ip})privateSValue({xxl。job。executor。port})Value({xxl。job。accessToken})privateStringaccessTValue({xxl。job。executor。logpath})privateStringlogPValue({xxl。job。executor。logretentiondays})privateintlogRetentionDBeanpublicXxlJobSpringExecutorxxlJobExecutor(){创建XxlJobSpringExecutor执行器XxlJobSpringExecutorxxlJobSpringExecutornewXxlJobSpringExecutor();xxlJobSpringExecutor。setAdminAddresses(adminAddresses);xxlJobSpringExecutor。setAppname(appName);xxlJobSpringExecutor。setIp(ip);xxlJobSpringExecutor。setPort(port);xxlJobSpringExecutor。setAccessToken(accessToken);xxlJobSpringExecutor。setLogPath(logPath);xxlJobSpringExecutor。setLogRetentionDays(logRetentionDays);返回returnxxlJobSpringE}}复制代码
  2、xxljob工具类ComponentRequiredArgsConstructorpublicclassXxlUtil{Value({xxl。job。admin。addresses})privateStringxxlJobAdminAprivatefinalRestTemplaterestT请求UrlprivatestaticfinalStringADDINFOURLjobinfoaddJprivatestaticfinalStringREMOVEINFOURLjobinforemoveJprivatestaticfinalStringGETGROUPIDjobgrouploadByAppN添加任务paramxxlJobInfoparamappNamereturnpublicStringaddJob(XxlJobInfoxxlJobInfo,StringappName){MapString,ObjectparamsnewHashMap();params。put(appName,appName);StringjsonJSONUtil。toJsonStr(params);StringresultdoPost(xxlJobAdminAddressGETGROUPID,json);JSONObjectjsonObjectJSON。parseObject(result);MapString,Objectmap(MapString,Object)jsonObject。get(content);IntegergroupId(Integer)map。get(id);xxlJobInfo。setJobGroup(groupId);StringxxlJobInfoJsonJSONUtil。toJsonStr(xxlJobInfo);returndoPost(xxlJobAdminAddressADDINFOURL,xxlJobInfoJson);}删除jobpublicStringremoveJob(longjobId){MultiValueMapString,StringmapnewLinkedMultiValueMapString,String();map。add(id,String。valueOf(jobId));returndoPostWithFormData(xxlJobAdminAddressREMOVEINFOURL,map);}远程调用paramurlparamjsonprivateStringdoPost(Stringurl,Stringjson){HttpHeadersheadersnewHttpHeaders();headers。setContentType(MediaType。APPLICATIONJSON);HttpEntityStringentitynewHttpEntity(json,headers);ResponseEntityStringresponseEntityrestTemplate。postForEntity(url,entity,String。class);returnresponseEntity。getBody();}privateStringdoPostWithFormData(Stringurl,MultiValueMapString,Stringmap){HttpHeadersheadersnewHttpHeaders();headers。setContentType(MediaType。APPLICATIONFORMURLENCODED);HttpEntityMultiValueMapString,StringentitynewHttpEntity(map,headers);ResponseEntityStringresponseEntityrestTemplate。postForEntity(url,entity,String。class);returnresponseEntity。getBody();}}复制代码
  此处我们利用RestTemplate来远程调用xxljobadmin中的服务,从而实现动态创建定时任务,而不是局限于通过UI界面来创建任务。
  这里我们用到三个接口,都需要我们在xxljobadmin中手动添加,这样在调用接口时,就不需要登录验证了,这就要求在定义接口时加上一个PermissionLimit并设置limit为false,那么这样就不用去登录就可以调用接口。
  3、修改JobGroupController,新增loadByAppName方法RequestMapping(loadByAppName)ResponseBodyPermissionLimit(limitfalse)publicReturnTXxlJobGrouploadByAppName(RequestBodyMapString,Objectmap){XxlJobGroupjobGroupxxlJobGroupDao。loadByAppName(map);returnjobGroup!null?newReturnTXxlJobGroup(jobGroup):newReturnTXxlJobGroup(ReturnT。FAILCODE,null);}复制代码
  XxlJobGroupDao文件以及对应的xml文件XxlJobGrouploadByAppName(MapString,Objectmap);复制代码selectidloadByAppNameparameterTypejava。util。HashMapresultMapXxlJobGroupSELECTincluderefidBaseColumnListFROMxxljobgroupAStWHEREt。appname{appName}select复制代码
  4、修改JobInfoController,增加addJob方法和removeJob方法RequestMapping(addJob)ResponseBodyPermissionLimit(limitfalse)publicReturnTStringaddJob(RequestBodyXxlJobInfojobInfo){returnxxlJobService。add(jobInfo);}RequestMapping(removeJob)ResponseBodyPermissionLimit(limitfalse)publicReturnTStringremoveJob(Stringid){returnxxlJobService。remove(Integer。parseInt(id));}复制代码
  addJob方法与JobInfoController文件中的add方法具体逻辑是一样的,只是换个接口名。RequestMapping(add)ResponseBodypublicReturnTStringadd(XxlJobInfojobInfo){returnxxlJobService。add(jobInfo);}复制代码
  至此,关于调度中心的修改就结束了。
  5、XxlService创建任务ServiceSlf4jRequiredArgsConstructorpublicclassXxlService{privatefinalXxlUtilxxlUValue({xxl。job。executor。appname})privateStringappNpublicvoidaddJob(XxlJobInfoxxlJobInfo){xxlUtil。addJob(xxlJobInfo,appName);longtriggerNextTimexxlJobInfo。getTriggerNextTime();log。info(任务已添加,将在{}开始执行任务,DateUtils。formatDate(triggerNextTime));}}复制代码业务代码
  1、UserService,包括用户注册,给用户发送欢迎消息,以及发送天气温度通知。ServiceRequiredArgsConstructorSlf4jpublicclassUserService{privatefinalUserMapperuserMprivatefinalUserStructuserSprivatefinalWeatherServiceweatherSprivatefinalXxlServicexxlS假设有这样一个业务需求,每当有新用户注册,则1分钟后会给用户发送欢迎通知。paramuserRequest用户请求体Transactionalpublicvoidregister(UserRequestuserRequest){if(Objects。isNull(userRequest)isBlank(userRequest。getUsername())isBlank(userRequest。getPassword())){BusinessException。fail(账号或密码为空!);}UseruseruserStruct。toUser(userRequest);userMapper。insert(user);LocalDateTimescheduleTimeLocalDateTime。now()。plusMinutes(1L);XxlJobInfoxxlJobInfoXxlJobInfo。builder()。jobDesc(定时给用户发送通知)。author(hresh)。scheduleType(CRON)。scheduleConf(DateUtils。getCron(scheduleTime))。glueType(BEAN)。glueType(BEAN)。executorHandler(sayHelloHandler)。executorParam(user。getUsername())。misfireStrategy(DONOTHING)。executorRouteStrategy(FIRST)。triggerNextTime(DateUtils。toEpochMilli(scheduleTime))。executorBlockStrategy(SERIALEXECUTION)。triggerStatus(1)。build();xxlService。addJob(xxlJobInfo);}publicvoidsayHelloToUser(Stringusername){if(StrUtil。isBlank(username)){log。error(用户名为空);}UseruseruserMapper。selectByUserName(username);StringmessageWelcometoJava,Iamhresh。;log。info(user。getUsername(),hello,message);}publicvoidpushWeatherNotification(){ListUserusersuserMapper。queryAll();log。info(执行发送天气通知给用户的任务);WeatherInfoweatherInfoweatherService。getWeather(WeatherConstant。WUHAN);for(Useruser:users){log。info(user。getUsername()weatherInfo。toString());}}}复制代码
  2、WeatherService,获取天气温度等信息,这里就不贴代码了。
  3、UserController,只有一个用户注册方法RestControllerRequiredArgsConstructorpublicclassUserController{privatefinalUserServiceuserSPostMapping(register)publicResultObjectregister(RequestBodyUserRequestuserRequest){userService。register(userRequest);returnResult。ok();}}复制代码任务处理器
  这里演示两种任务处理器,一种是用于处理UI页面创建的任务,另一种是处理代码创建的任务。
  1、DemoHandler,仅用作演示,没什么实际含义。RequiredArgsConstructorSlf4jpublicclassDemoHandlerextendsIJobHandler{XxlJob(valuedemoHandler)Overridepublicvoidexecute()throwsException{log。info(自动任务this。getClass()。getSimpleName()执行);}}复制代码
  2、SayHelloHandler,用户注册后再xxljob上创建一个任务,到时间后就调用该处理器。ComponentRequiredArgsConstructorpublicclassSayHelloHandler{privatefinalUserServiceuserSXxlJob(valuesayHelloHandler)publicvoidexecute(){StringparamXxlJobHelper。getJobParam();userService。sayHelloToUser(param);}}复制代码
  在最新版本的xxljob中,任务核心类IJobHandler的execute方法取消出入参设计。改为通过XxlJobHelper。getJobParam获取任务参数并替代方法入参,通过XxlJobHelper。handleSuccesshandleFail设置任务结果并替代方法出参,示例代码如下XxlJob(demoJobHandler)publicvoidexecute(){StringparamXxlJobHelper。getJobParam();获取参数XxlJobHelper。handleSuccess();设置任务结果}复制代码
  3、WeatherNotificationHandler,每天定时发送天气通知ComponentRequiredArgsConstructorpublicclassWeatherNotificationHandlerextendsIJobHandler{privatefinalUserServiceuserSXxlJob(valueweatherNotificationHandler)Overridepublicvoidexecute()throwsException{userService。pushWeatherNotification();}}复制代码测试
  1、首先在执行器管理页面,点击新增按钮,弹出新增框。输入AppName(与application。yml中配置的appname保持一致),名称,注册方式默认自动注册,点击保存。
  2、新增任务
  控制台输出:com。msdn。time。handler。DemoHandler:自动任务DemoHandler执行复制代码
  2、利用postman来注册用户
  去UI任务管理页面,可以看到代码创建的任务。
  1分钟后,控制台输出如下:
  3、在UI任务管理页面手动新增任务,用来发送天气通知。
  点击执行一次,控制台输出如下:
  实际应用中,对于手动创建的任务,直接点击启动就可以了。
  这里还有一个问题,如果每次有新用户注册,都会创建一个定时任务,而且只执行一次,那么任务列表到时候就会有很多脏数据,所以我们在执行完发送欢迎通知后,就要删除。所以我们需要修改一下SayHelloHandlerXxlJob(valuesayHelloHandler)publicvoidexecute(){StringparamXxlJobHelper。getJobParam();userService。sayHelloToUser(param);longjobIdXxlJobHelper。getJobId();xxlUtil。removeJob(jobId);}复制代码
  重启项目后,比如说明再创建一个名为hresh2的用户,然后任务列表就会新增一个任务。
  等控制台输出sayHello后,可以发现任务列表中任务ID为20的记录被删除掉了。问题控制台输出邮件注册错误11:01:48。740logback〔RMITCPConnection(1)127。0。0。1〕WARNo。s。b。a。mail。MailHealthIndicatorMailhealthcheckfailedjavax。mail。AuthenticationFailedException:535LoginFail。Pleaseenteryourauthorizationcodetologin。Moreinformationinhttp:service。mail。qq。comcgibinhelp?subtype1id28no1001256复制代码
  原因:xxljobadmin项目的application。properties文件中关于spring。mail。password的配置不对,可能有人配置了自己邮箱的登录密码。
  解决方案:
  总结
  通过对比Quartz和XXLJOB的使用,可以发现后者更易上手,代码侵入不严重,且具备可视化界面。这就是推荐新手使用XXLJOB的原因。
  原文链接:https:juejin。cnpost7172325382320816165
投诉 评论 转载

前海人寿大股东不当干预姚振华被约谈单季巨亏23亿偿付能力持续长江商报消息长江商报记者蔡嘉姚振华野蛮人的特性,在前海人寿的治理中再次展现。7月15日,前海人寿收到银保监会人身险部监管意见书,指出前海人寿公司治理存在问题,应立即……安徽一大学生暑假打工,一举动令老板娘笑得合不拢嘴工资翻倍近日,在安徽亳州,一位大学生在打工的时候,因为做了一件事情,得到了老板娘的赏识。于是,到了月底的时候,老板娘还是特意给了这位大学生双份的工资。这到底是怎么回事呢?让我们接着往下……73家财险公司上半年互联网业务收入530亿平安国寿众安同比业南方财经全媒体记者郑嘉意北京报道近日,中国保险行业协会发布《2022年上半年互联网财产保险发展分析报告》(以下简称《报告》),通过调研部分保险机构的互联网财产保险业务发展……SpringBoot结合XXLJOB实现定时任务前言上篇文章我们介绍了Quartz的使用,当时实现了两个简单的需求,不过最后我们总结的时候也提到Quartz有不少缺点,代码侵入太严重,所以本篇将介绍xxljob这个定时……她们腿长,胸大,裙子够短,肯定有人看!1943年,美国青壮年大规模应征入伍,参加海外战争。其中,也包括棒球大联盟的运动员。俱乐部老板拍脑袋一想:没有男人,让女人上啊。于是,美国历史上第一届女子棒球……为什么感觉越来越多的全职妈妈不喜欢出门逛街了?第一,没有钱,不是舍不得花,全职妈妈没有收入,有些老公给的多点,还余下点钱,有些老公给的少,生活费都不够,哪还有钱去逛街。第二,没有社交,没有朋友,一天就围着小孩子转,最……欧米茄比劳力士差在哪里了?劳力士和欧米茄一直是经常被很多表迷拿来比较的两个品牌,虽然这两个品牌不论是机芯技术,还是外观,以及价格区间等都有很多的不同,似乎看起来没有什么可比性,但是通过比较来多了解一些关……穷秀才真的穷吗?这才是穷秀才的真面目在公众的印象中,布衣褴褛,举止清高是对古代秀才最好的写照。听到过的最多描写秀才的语句就是瞧你这副穷酸样。更多的人在通过鲁迅先生对孔乙己偷书不可谓偷的精辟描述后,对秀才的穷酸迂腐……京东总裁被算计?刘强东案反转,女方求巨额赔偿漏洞百出,真能编刘强东案想必大家都有所耳闻,他本人也因为此案跌下神坛,深陷泥沼,甚至被警方逮捕,名声可谓一落千丈。要知道刘强东的媳妇是集美貌与才华于一身的奶茶妹妹章泽天,事件一出大家纷纷……去西安旅游,必吃的早点是什么?去西安旅行,必吃的早点是什么?西安的美食全国闻名,以面食和清真风味为主。其中,凉皮、肉夹馍和冰峰汽水海贝冠以三秦套餐的美称。必吃的早点有:1、胡辣汤胡辣汤是非常能代表西安……狂飙徐忠劝降戏被大改,真不能全怪吴刚,看完原著就明白了虽然《狂飙》成为了今年目前最热门的电视剧,无论是收视率还是讨论热度都是接连创下不少佳绩,口碑也是被人称赞,但是即使如此,《狂飙》依旧存在不少显而易见的缺憾,其中最备受争议的便是……3年后回看铜陵教师自杀案,这场教育悲剧,比你想得更加沉重2019年7月3日清晨5点多,安徽省铜陵市陈瑶湖镇,一个中年男人睁开双眼,蹑手蹑脚地走下床。他走到窗前点燃一支烟,不舍地看着楼下喧闹的菜市场。烟雾缓缓上升,遮蔽了男……
世茂股份前9月销售签约金额约68亿元悄悄生子3年后,张碧晨怀孕分娩私照曝光这一切,都怪华晨宇?送别103岁的开国将军杨永松,开国将帅还有哪几位健在?包邮区多地连发高温红色预警!还要热多久?有摄影爱好者说一镜走天下的镜头画质不算太好?真的是这样吗?千方百计帮助高校毕业生就业少帅夫人于凤至18岁嫁张学良,苦等其50年,新婚之夜提了一要邮储银行通过数字人民币App开立个人钱包数排第一唐山被打女孩终于发声,保护伞被曝光果然,事情没那么简单电瓶没电了后电子手刹会不会失效而溜车?手刹一直在用电吗?有哪些贵州自驾游必去的地方?25岁称霸山西,作恶长达14年之久被称作太原黑老大海底两万里的读书笔记白癜风究竟多可怕!为什么被称为不死的癌症男朋友出轨可以要分手费吗男朋友出轨可以索要赔偿吗幼儿园工作计划衣服袖子短了怎么加长怎么避免袖子太短在沈阳生活的外地人谈谈,沈阳是一个让你有归属感的城市吗?世界上最大的馅饼,直径12米(足够4500人吃)明朝那些事儿有句子曾让我感动落泪,原来历史也有温度数学教学三年级工作计划中国科学家发现浩瀚宇宙中定位太阳新方法象棋比赛致敬梅西孤勇者歌词改起来

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找