xxl-job的原理(2)—调度中心管理注册信息

一、调度中心管理注册信息

1.JobApiController

执行器调用调度中心的url来实现注册、下线、回调等操作;其主要的实现类是JobApiController,调用/api/registry接口注册执行器信息,调用/api/registryRemove接口下线执行器信息,调用/api/callback接口执行回调操作。

@Controller
@RequestMapping("/api")
public class JobApiController {@Resourceprivate AdminBiz adminBiz;/*** api** @param uri* @param data* @return*/@RequestMapping("/{uri}")@ResponseBody@PermissionLimit(limit=false)public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {// validif (!"POST".equalsIgnoreCase(request.getMethod())) {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");}if (uri==null || uri.trim().length()==0) {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");}if (XxlJobAdminConfig.getAdminConfig().getAccessToken()!=null&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length()>0&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");}// services mappingif ("callback".equals(uri)) {List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);return adminBiz.callback(callbackParamList);} else if ("registry".equals(uri)) {RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);return adminBiz.registry(registryParam);} else if ("registryRemove".equals(uri)) {RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);return adminBiz.registryRemove(registryParam);} else {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping("+ uri +") not found.");}}}

2.AdminBizImpl

执行adminBiz.registry(registryParam)是调用实现类AdminBizImpl,在实现类中调用registry(registryParam)来实现。

@Service
public class AdminBizImpl implements AdminBiz {@Overridepublic ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {return JobCompleteHelper.getInstance().callback(callbackParamList);}@Overridepublic ReturnT<String> registry(RegistryParam registryParam) {return JobRegistryHelper.getInstance().registry(registryParam);}@Overridepublic ReturnT<String> registryRemove(RegistryParam registryParam) {return JobRegistryHelper.getInstance().registryRemove(registryParam);}}

3.JobRegistryHelper

在AdminBizImpl中的实现也不难理解,通过在初始化start()方法中创建的registryOrRemoveThreadPool线程池中执行异步注册任务,注册信息写入到数据表xxl_job_registry中。

//AdminBizImpl.javapublic void start(){// for registry or removeregistryOrRemoveThreadPool = new ThreadPoolExecutor(2,10,30L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(2000),new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode());}},new RejectedExecutionHandler() {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {r.run();logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now).");}});//...省略public ReturnT<String> registry(RegistryParam registryParam) {// validif (!StringUtils.hasText(registryParam.getRegistryGroup())|| !StringUtils.hasText(registryParam.getRegistryKey())|| !StringUtils.hasText(registryParam.getRegistryValue())) {return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");}// async execute//my-异步执行,将注册信息持久化到数据库registryOrRemoveThreadPool.execute(new Runnable() {@Overridepublic void run() {//my-写入数据库int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());if (ret < 1) {XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());// freshfreshGroupRegistryInfo(registryParam);}}});return ReturnT.SUCCESS;
}

4.总结

  1. 执行器通过restful api形式注册到调度中心来,调度中心JobApiController对应有3个注册、下线和回调的方法实现;
  2. 通过AdminBizImpl的adminBiz.registry(registryParam)来实际执行注册方法,实际使用JobRegistryHelper类;
  3. 在JobRegistryHelper类中在初始化的时候会创建一个线程池,每次注册执行器的时候会创建一个异步线程来将注册信息持久化的数据库;

JobApiController_api

二、调度中心的配置和启动

1.添加权限控制

制定权限注解@PermissionLimit,其实现的逻辑在PermissionInterceptor中,首先判断是否需要鉴权,如果需要则根据cookie中拿到的用户信息查库判断是否有权限登录,如果没有权限则重定向到登录页面或提示没有权限。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionLimit {/*** 登录拦截 (默认拦截)*/boolean limit() default true;/*** 要求管理员权限** @return*/boolean adminuser() default false;}
@Component
public class PermissionInterceptor implements AsyncHandlerInterceptor {@Resourceprivate LoginService loginService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//my-处理登录权限的逻辑if (!(handler instanceof HandlerMethod)) {return true;   // proceed with the next interceptor}// if need loginboolean needLogin = true;boolean needAdminuser = false;HandlerMethod method = (HandlerMethod)handler;PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);if (permission!=null) {needLogin = permission.limit();needAdminuser = permission.adminuser();}if (needLogin) {XxlJobUser loginUser = loginService.ifLogin(request, response);if (loginUser == null) {response.setStatus(302);response.setHeader("location", request.getContextPath()+"/toLogin");return false;}if (needAdminuser && loginUser.getRole()!=1) {throw new RuntimeException(I18nUtil.getString("system_permission_limit"));}request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);}return true;   // proceed with the next interceptor}}

将PermissionInterceptor添加到web配置文件中。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Resourceprivate PermissionInterceptor permissionInterceptor;@Resourceprivate CookieInterceptor cookieInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");}}

2.配置中心初始化

xxljob的初始化和销毁动作在XxlJobAdminConfig中配置完成。

@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {private static XxlJobAdminConfig adminConfig = null;public static XxlJobAdminConfig getAdminConfig() {return adminConfig;}// ---------------------- XxlJobScheduler ----------------------private XxlJobScheduler xxlJobScheduler;@Overridepublic void afterPropertiesSet() throws Exception {adminConfig = this;xxlJobScheduler = new XxlJobScheduler();xxlJobScheduler.init();}@Overridepublic void destroy() throws Exception {xxlJobScheduler.destroy();}
}

具体初始化的操作。

public class XxlJobScheduler  {private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);public void init() throws Exception {// init i18ninitI18n();// admin trigger pool startJobTriggerPoolHelper.toStart();// admin registry monitor runJobRegistryHelper.getInstance().start();// admin fail-monitor runJobFailMonitorHelper.getInstance().start();// admin lose-monitor run ( depend on JobTriggerPoolHelper )JobCompleteHelper.getInstance().start();// admin log report startJobLogReportHelper.getInstance().start();// start-schedule  ( depend on JobTriggerPoolHelper )JobScheduleHelper.getInstance().start();logger.info(">>>>>>>>> init xxl-job admin success.");}public void destroy() throws Exception {// stop-scheduleJobScheduleHelper.getInstance().toStop();// admin log report stopJobLogReportHelper.getInstance().toStop();// admin lose-monitor stopJobCompleteHelper.getInstance().toStop();// admin fail-monitor stopJobFailMonitorHelper.getInstance().toStop();// admin registry stopJobRegistryHelper.getInstance().toStop();// admin trigger pool stopJobTriggerPoolHelper.toStop();}// ---------------------- I18n ----------------------private void initI18n(){for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

操作系统和进程相关的认识

目录 冯诺依曼体系结构 冯诺依曼体系结构五大组成部分 为什么数据只能通过存储器进行输入和输出 操作系统 概念一&#xff1a;访问操作系统的请求都是通过系统调用完成的 操作系统如何管理用户信息 概念二&#xff1a;先描述&#xff0c;再组织。 进程的概念 在认识进行相关的知…

二叉树的经典OJ题

判断平衡二叉树 1.题目2.分析3.时间复杂度为O(N^2)的代码4.优化时间复杂度的代码 1.题目 2.分析 3.时间复杂度为O(N^2)的代码 4.优化时间复杂度的代码

总结三:计算机网络面经

文章目录 1、简述静态路由和动态路由&#xff1f;2、说说有哪些路由协议&#xff0c;都是如何更新的&#xff1f;3、简述域名解析过程&#xff0c;本机如何干预域名解析&#xff1f;4、简述 DNS 查询服务器的基本流程是什么&#xff1f;DNS 劫持是什么&#xff1f;5、简述网关的…

re学习(38)HGAME2020-re-Level-Week1-maze

题目描述 You won’t figure out anything if you give in to fear. 学习资料: https://ctf-wiki.github.io/ctf-wiki/reverse/maze/maze-zh/ 附加说明&#xff1a;请走最短路线 题解 分析题目 一看题目&#xff1a;maze 可以确定是一个迷宫题 void __fastcall __noreturn…

【java爬虫】使用vue+element-plus编写一个简单的管理页面

前言 前面我们已经将某宝联盟的数据获取下来了&#xff0c;并且编写了一个接口将数据返回&#xff0c;现在我们需要使用vueelement-plus编写一个简单的管理页面进行数据展示&#xff0c;由于第一次使用vue编写前端项目&#xff0c;所以只是编写了一个非常简单的页面。 项目结…

关于PointHeadBox类的理解

forward函数 def forward(self, batch_dict):"""Args:batch_dict:batch_size:point_features: (N1 N2 N3 ..., C) or (B, N, C)point_features_before_fusion: (N1 N2 N3 ..., C)point_coords: (N1 N2 N3 ..., 4) [bs_idx, x, y, z]point_labels (opti…

【计算机组成 课程笔记】7.1 存储层次结构概况

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 7 - 1 - 701-存储层次结构概况&#xff08;15-14--&#xff09;_哔哩哔哩_bilibili 这是我们已经非常熟悉的冯诺依曼计算机结构&#xff0c; 其中和存储功能相关的部件有&#xff1a;存储器和外部记录介质肯定具有…

80%测试员被骗,关于jmeter 的一个弥天大谎!

jmeter是目前大家都喜欢用的一款性能测试工具&#xff0c;因为它小巧、简单易上手&#xff0c;所以很多人都愿意用它来做接口测试或者性能测试&#xff0c;因此&#xff0c;在目前企业中&#xff0c;使用各个jmeter的版本都有&#xff0c;其中以jmeter3.x、4.x的应该居多。 但是…

Waves 14混音特效插件合集mac/win

Waves14是一款音频处理软件&#xff0c;主要用于音频编辑、混音和母带处理。该软件提供了各种插件&#xff0c;包括EQ、压缩、混响、延迟、失真等&#xff0c;以及一些专业的音频处理工具&#xff0c;如L2限幅器、Linear Phase EQ和多频道扬声器管理。 Mac软件下载&#xff1a;…

凉鞋的 Unity 笔记 106. 第二轮循环场景视图Sprite Renderer

106. 第二轮循环&场景视图&Sprite Renderer 从这一篇开始&#xff0c;我们开始进行第二轮循环。 这次我们至少能够在游戏运行窗口看到一些东西。 首先还是在场景层次窗口进行编辑&#xff0c;先创建一个 Sprite&#xff0c;操作如下: 创建后&#xff0c;会在 Scene …

Nginx与Spring Boot的错误模拟实践:探索502和504错误的原因

文章目录 前言502和504区别---都是Nginx返回的access.log和error.log介绍SpringBoot结合Nginx实战502 and 504准备工作Nginx配置host配置SpringBoot 502模拟access.logerror.log 504模拟access.logerror.log 500模拟access.logerror.log 总结 前言 刚工作那会&#xff0c;最常…

JMeter接口自动化测试(数据驱动)

之前我们的用例数据都是配置在HTTP请求中&#xff0c;每次需要增加&#xff0c;修改用例都需要打开JMeter重新编辑&#xff0c;当用例越来越多的时候&#xff0c;用例维护起来就越来越麻烦&#xff0c;有没有好的方法来解决这种情况呢&#xff1f;我们可以将用例的数据存放在cs…

MyBatis过时了吗?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

3263页学习资料,一本在手,python不愁!

Python3.11已经发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 爬虫。简单的爬虫库&am…

手机图片合成gif怎么操作?用这个网站试试

制作gif动图的工具越来越多&#xff0c;但是很多时候使用电脑并不方便&#xff0c;想要在手机上制作gif动图的时候应该怎么办呢&#xff1f;很简单&#xff0c;给大家分享一款无需下载手机浏览器就能操作的gif制作&#xff08;https://www.gif.cn/&#xff09;工具-GIF中文网&a…

朋友圈怎么定点发朋友圈?

微信朋友圈是我们日常生活中常用的社交媒体之一。但有时我们忙碌而可能会忘记发布朋友圈&#xff0c;或是因时间不合适而无法发布。那么&#xff0c;有没有一种方法可以在规定的时间内自动发布朋友圈呢&#xff1f; 当然有啦&#xff01; 定时发朋友圈可以帮助我们在特定时间点…

使用ebpf 监控linux内核中的nat转换

1.简介 Linux NAT&#xff08;Network Address Translation&#xff09;转换是一种网络技术&#xff0c;用于将一个或多个私有网络内的IP地址转换为一个公共的IP地址&#xff0c;以便与互联网通信。 在k8s业务场景中&#xff0c;业务组件之间的关系十分复杂. 由于 Kubernete…

tortoiseSVN树冲突解决方案

方案一&#xff1a; 手动导出 trunk 上的文件(夹)&#xff0c;把本地目录文件(夹)删了并替换成 trunk上的&#xff0c;再点击测试合并方案二&#xff1a; 如果执行了方案一还是冲突&#xff0c;确认本地和trunk文件一致后&#xff0c;可以跳过冲突的revision

【数据结构】初探时间与空间复杂度:算法评估与优化的基础

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;数据结构 &#x1f525;该文章主要了解算法的时间复杂度与空间复杂度等相关知识。 目录&#xff1a; &#x1f30f; 时间复杂度&#x1f52d…

目标检测算法改进系列之Backbone替换为FocalNet

FocalNet 近些年&#xff0c;Transformers在自然语言处理、图像分类、目标检测和图像分割上均取得了较大的成功&#xff0c;归根结底是自注意力&#xff08;SA &#xff1a;self-attention&#xff09;起到了关键性的作用&#xff0c;因此能够支持输入信息的全局交互。但是由于…