当前位置: 首页 > news >正文

PowerJob的server启动都经历了哪些?代码不多也很简单,咱们来逐一理解。

这是一篇让你受益匪浅的文章,点个关注交流一下吧~

PowerJob如何使用,官方文档已经说的很详细了,即使没学过计算机的人,按照那上面的步骤来也是可以搭建出一个可以使用的例子来,所以今天就不在这里重复前人的工作,直接开始就开始将这个源代码中的原理吧。

 

powerjob框架主要分成两个分部,server和worker,这两部分需要分别去启动,而且需要先启动server,后启动worker,否则,worker会因为找不到可用的server,而启动失败。作为一个server启动的时候工作自然是非常繁重的,主要有以下几个步骤:

  1. 读取配置文件

  2. 启动Akka服务

  3. 启动Vertx服务

  4. 启动Spring

详细的启动代码如下所示:

private static final String TIPS = "\n\n" +"******************* PowerJob Tips *******************\n" +"如果应用无法启动,我们建议您仔细阅读以下文档来解决:\n" +"if server can't startup, we recommend that you read the documentation to find a solution:\n" +"https://www.yuque.com/powerjob/guidence/problem\n" +"******************* PowerJob Tips *******************\n\n";public static void main(String[] args) {pre();//下方的私有静态方法AkkaStarter.init();//启动AkkaVertXStarter.init();//启动Vertx//启动Springtry {SpringApplication.run(PowerJobServerApplication.class, args);} catch (Throwable t) {log.error(TIPS);throw t;}
}private static void pre() {log.info(TIPS);//将上方的常量字符串打印出来PropertyUtils.init();//读取配置文件
}

读取配置文件

PropertyUtils.init();//读取配置文件

这一步特别简单,仅仅涉及到server.common.utils包中的PropertyUtils。主要代码段如下:

public static void init() {URL propertiesURL =PropertyUtils.class.getClassLoader().getResource("application.properties");Objects.requireNonNull(propertiesURL);try (InputStream is = propertiesURL.openStream()) {PROPERTIES.load(is);}catch (Exception e) {ExceptionUtils.rethrow(e);}
}

因为代码也不是很多,就直接把该方法的所有代码全部展示出来。

代码中第二行,方法里第一行有这么一段代码

PropertyUtils.class.getClassLoader().getResource("application.properties");

这个代码就是读取配置文件中的内容,下面是powerjob的文件目录层次,看图就知道该段代码到底读的是哪一部分。

说句实话,最开始的时候,我认为读取的是上面红色箭头指的地方,因为他代码里getResource,这个地方我认为就是读取resource文件夹下面的文件,但是.getClassLoader无法解释,后来自己跑一下这个代码就明白了,读取的是编译完的文件路径,而不是编译之前的路径。

读取的和配置文件里面的一模一样,一条不多一条不少~,springboot正常也会读取配置文件,这里为什么要单独执行一下读取,作用是什么?在这里先不说,看到后面遇到了,再来解答,留作问题1。

启动Akka服务

 

AkkaStarter.init();

powerjob里面主要使用的akka-remote,就是用来通信的,说白了就是手机,用来给彼此打电话汇报信息的。

Akka框架的介绍,请移步akka的官网自己去欣赏,这里只将代码的作用做一个讲解。

这个AkkaStarter是在server.remote.transport.starter包里,init方法代码如下:

public static void init() {//一个计时的方法,就不用在开始与结束的时候使用System获取时间,然后再进行相减了。Stopwatch stopwatch = Stopwatch.createStarted();log.info("[PowerJob] PowerJob's akka system start to bootstrap...");// 解析配置文件Config akkaFinalConfig = parseConfig();//创建一个Akka的actor系统,相当于建立了一个公司,之后所有的actor行动都在这个公司内进行actorSystem = ActorSystem.create(RemoteConstant.SERVER_ACTOR_SYSTEM_NAME, akkaFinalConfig);//创建了一个actor。actorSystem.actorOf(FriendRequestHandler.defaultProps(), RemoteConstant.SERVER_FRIEND_ACTOR_NAME);log.info("[PowerJob] PowerJob's akka system started successfully, using time {}.", stopwatch);}

解析配置文件

解析配置文件的代码如下所示:

private static Config parseConfig() {//这一步是获取了启动第一步的读取配置文件后获取的配置内容,这也就回答了问题1。Properties properties = PropertyUtils.getProperties();//获取配置文件中oms.akka.port字段的内容,如果没有该配置,则默认为10086端口int port = Integer.parseInt(properties.getProperty(PowerJobServerConfigKey.AKKA_PORT, String.valueOf(OmsConstant.SERVER_DEFAULT_AKKA_PORT)));//这个是通过jvm启动时配置oms.akka.port的参数,例如:启动时候的java -Doms.akka.port=30086...String portFromJvm = System.getProperty(PowerJobServerConfigKey.AKKA_PORT);//如果配置了jvm启动的配置,则将其覆盖配置文件的akka端口,也就是说jvm配置优先级高于配置文件的配置if (StringUtils.isNotEmpty(portFromJvm)) {log.info("[PowerJob] use port from jvm params: {}", portFromJvm);port = Integer.parseInt(portFromJvm);}// 启动 ActorSystemMap<String, Object> overrideConfig = Maps.newHashMap();//获取本地的ip地址,下面会详细进入到代码中说一下,这里面还挺深的String localIp = NetUtils.getLocalHost();//将关键字放到一个map映射中overrideConfig.put("akka.remote.artery.canonical.hostname", localIp);overrideConfig.put("akka.remote.artery.canonical.port", port);//ip和端口组成了akka的通信地址actorSystemAddress = localIp + ":" + port;log.info("[PowerJob] akka-remote server address: {}", actorSystemAddress);//获取oms-server.akka.conf配置文件里面的配置,ConfigFactory为akka自带方法Config akkaBasicConfig = ConfigFactory.load(RemoteConstant.SERVER_AKKA_CONFIG_NAME);//overrideConfig里面有的配置内容,按照overrideConfig走,没有的,按照配置文件akkaBasicConfig走return ConfigFactory.parseMap(overrideConfig).withFallback(akkaBasicConfig);
}

获取本地地址

String localIp = NetUtils.getLocalHost();

在解析配置文件中,其实真正有点内容的就是这个获取本地地址这个方法,之前我没有去细研究之前,可把我给坑毁了,因为我想用局域网的ip进行来回通信,但是因为这个获取地址里面的默认策略,导致每一次使用的都不是我想用的IP地址,当我研究完了这个代码之后,终于是柳暗花明又一村了,直接就可以指定地址了。

先看源码如下所示:

public static String getLocalHost() {
//这个代码就是在获取了地址之后,就直接将地址存起来,下一次再用就可以直接返回了if (HOST_ADDRESS != null) {return HOST_ADDRESS;}//获取jvm启动时,设置的powerjob.network.local.address关键字的地址,通过这个就可以直接绑定ip了String addressFromJVM = System.getProperty(PowerJobDKey.BIND_LOCAL_ADDRESS);if (StringUtils.isNotEmpty(addressFromJVM)) {log.info("[Net] use address from[{}]: {}", PowerJobDKey.BIND_LOCAL_ADDRESS, addressFromJVM);return HOST_ADDRESS = addressFromJVM;}//如果上一步没有绑定地址,那就在通过getLocalAddress来获取地址。InetAddress address = getLocalAddress();if (address != null) {return HOST_ADDRESS = address.getHostAddress();}return LOCALHOST_VALUE;
}

大概知道了获取host的思路,下一篇文章我们再详细介绍里面的具体流程,因为里面的流程相对来说有那么一点点的不简单,在这里讲的话会稍显冗长,所以我准备另开一篇,详细说一下。

启动Actor

actorSystem = ActorSystem.create(RemoteConstant.SERVER_ACTOR_SYSTEM_NAME, akkaFinalConfig); actorSystem.actorOf(FriendRequestHandler.defaultProps(), RemoteConstant.SERVER_FRIEND_ACTOR_NAME);

第一个就是建立actor系统,参数一个是系统的名字,类似于电话号码后四位那么一个东西,另一个是akka的配置,这个在解析配置文件步骤中获取。

第二个是创建actor,这里创建的是FriendRequestHandler的Actor,调用其defaultProps()方法,源代码如下:

public static Props defaultProps() {return Props.create(FriendRequestHandler.class)//这一步是设置派发器的配置。//读取配置文件oms-server.akka.conf中akka.friend-request-actor-dispatcher的关键字.withDispatcher("akka.friend-request-actor-dispatcher")//路由配置.withRouter(new RoundRobinPool(Runtime.getRuntime().availableProcessors() * 4).withResizer(new DefaultResizer(Runtime.getRuntime().availableProcessors() * 4,Runtime.getRuntime().availableProcessors() * 10,1,0.2d,0.3d,0.1d,10)));
}    

到这里,这个Akka服务就算是启动完成了

总结

 

最后的vertx的启动基本没什么东西,就是vertx的默认启动,一行代码就OK了,其余的内容和akka启动时基本相同。

vertx = Vertx.vertx();

Server的启动相对来说没有那么的复杂,代码读起来也是非常的通俗易懂,这里面只出现了一个问题

springboot自带读配置文件的功能,为什么启动的时候要先读取配置文件?

因为启动akka和vertx的时候,需要配置文件的内容,而这个时候spring还没有读取该配置文件。

相关文章

https://blog.csdn.net/i_mycode/article/details/108382597 【getClassLoader().getResource() 】

http://doc.yonyoucloud.com/doc/akka-doc-cn/2.3.6/scala/book/chapter1/01_what_is_akka.html 【AKKA 2.3.6 Scala 文档】

相关文章:

PowerJob的server启动都经历了哪些?代码不多也很简单,咱们来逐一理解。

这是一篇让你受益匪浅的文章&#xff0c;点个关注交流一下吧~ PowerJob如何使用&#xff0c;官方文档已经说的很详细了&#xff0c;即使没学过计算机的人&#xff0c;按照那上面的步骤来也是可以搭建出一个可以使用的例子来&#xff0c;所以今天就不在这里重复前人的工作&#…...

分享好玩的h5小游戏制作步骤_怎么做h5微信小游戏

近年来&#xff0c;市面上一直流行各种h5游戏&#xff0c;例如投票、答题、刮刮乐、大转盘等等等等&#xff0c;而且我在各种营销场景下经常看到它们的身影&#xff0c;是做促销&#xff0c;引流和宣传的神器之一&#xff01;那么&#xff0c;怎么做好玩的h5游戏&#xff1f;还…...

代理模式--设计模式

为什么要学习代理模式&#xff1f; 因为这是SpringAOP的底层&#xff01; 1、定义&#xff1a; 在不改变源码的情况下&#xff0c;实现对目标对象的功能扩展 根据代理类的生成时间不同可以将代理分为静态代理和动态代理两种 静态代理 角色分析 抽象角色&#xff1a;一般会…...

【RSTP的原理和配置】

一、RSTP 概述 RSTP使用了IEEE 802.1W协议&#xff0c;视为STP的改进版本&#xff0c;收敛速度快&#xff0c;兼容STP。 RSTP可以兼容STP&#xff0c;但是会丧失快速收敛等优势&#xff1b; 1、RSTP对STP的改进&#xff1b; 1.1、端口角色的增补、简化了生成树协议的理解及部…...

Doom流量回放工具导致的测试环境服务接口无响应的排查过程

Doom流量回放工具导致的测试环境服务接口无响应的排查过程 现象描述&#xff1a; a)部分接口&#xff08;A组接口&#xff09;无响应 b)部分接口&#xff08;B组接口&#xff09;正常响应 c)还有一部分接口&#xff08;C组接口&#xff09;,场景1无响应&#xff0c;场景2正常响…...

2023年留学基金委(CSC)西部/地方合作项目选派办法及解读

2023年2月13日国家留学基金委&#xff08;CSC&#xff09;官方网站发布了2023年西部地区人才培养特别项目、地方合作项目通知。知识人网小编现将其选派工作流程及选派办法原文转载并加以解读、提出建议。知识人网建议1. 邀请函是公派申请的必备条件。对于外语语言证明未达标者&…...

ILSSI国际研讨会将为您呈现六西格玛技术的未来与前景

ILSSI 欢迎世界各地的精益六西格玛专业人士参加即将举行的2023年国际精益六西格玛研讨会&#xff0c;这次研讨会将邀请到世界各地的专家学者&#xff0c;分享他们的专业知识和经验&#xff0c;并就精益六西格玛等相关议题进行探讨和交流。 这是一个绝佳的机会&#xff0c;让您…...

KDJ日周月金叉共振指标

昨天介绍了MACD多周期共振指标公式&#xff0c;KDJ通过类似的写法&#xff0c;也可以共振。本文介绍的KDJ日周月金叉共振指标包含日周金叉共振、日月金叉共振、周月金叉共振、日周月金叉共振四种类型。 需要注意的问题依然是周、月金叉的信号漂移&#xff0c;接近周末月末的信…...

线程私有变量ThreadLocal详解

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 烈火试真金&#xff0c;逆境试强者。——塞内加 文章目录什么是ThreadLocalThreadLocal 原理set()方法get()方法remove()方法ThreadLocal 的Hash算法ThreadLocal 1.7和1.8的区别ThreadLocal 的问题ThreadLoca…...

如何保证数据库和缓存双写一致性

前言 数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。 我很负责的告诉大家,该问题无论在面试,还是工作中遇到的概率非常大,所以非常有必要跟大家一起探讨一下。 今天这篇文章我会从浅入深,…...

一文搞懂:JS严格模式“use strict”

什么是JS的严格模式 JS严格模式概念是在ES5中引入的&#xff0c;在此模式下&#xff0c;JS对语法的要求会变的严格&#xff0c;某些不太严谨的代码在严格模式下将不能运行。 如何启用严格模式 只需要JS代码的起始添加 "use strict"即可。如&#xff1a; "use…...

Linux的ACL(扩展权限)规划:setfacl、getfacl

目录 什么是ACL与如何支持启动ACL ACL设置技巧&#xff1a;getfacl、setfacl getfacl命令用法 setfacl命令用法 最简单的【u&#xff1a;账号&#xff1a;权限】设置 使用默认权限设置目录未来文件的ACL权限继承 什么是ACL与如何支持启动ACL ACL是Access Control List的…...

HTML预格式化文本pre标签

文章目录参考white-spaceword-breakfont-family参考 https://blog.csdn.net/weixin_44368963/article/details/120054949 https://www.zhangxinxu.com/wordpress/2017/03/css-font-family-chinese-english/ pre 元素可定义预格式化的文本。被包围在 pre 元素中的文本通常会保留…...

基于机器学习的心脏病预测方法(11)——梯度提升机(GBM)

一、梯度提升机介绍 GBM(Gradient Boosting Machine)算法是Boosting(提升)算法的一种。主要思想是,串行地生成多个弱学习器,每个弱学习器的目标是拟合先前累加模型的损失函数的负梯度, 使加上该弱学习器后的累积模型损失往负梯度的方向减少。 且它用不同的权重将基学习器…...

Linux多版本python切换以及多版本pip对应 (cloud studio Ubuntu16.04)

linux && cloud studio && Ubuntu16.04 简单解决多版本python切换以及多版本pip对应问题 1.python2切换成python 多版本python: 更改前先查看版本号 $ python -V Python 2.7.12 $ python2 -V Python 2.7.12 $ python3 -V Python 3.5.2 通过下面的命令看到py…...

【并发编程】LockSupport源码详解

目录 一、前言 1.1 简介 1.2 为什么说LockSupport是Java并发的基石&#xff1f; 二、LockSupport的用途 2.1 LockSupport的主要方法 2.2 使用案例 2.3 总结 三、LockSupport 源码分析 3.1 学习原理前的前置知识 3.1.1 Unsafe.park()和Unsafe.unpark() 3.1.2wait和notify/notify…...

元宇宙之声:新鸿基公司

在本期节目中&#xff0c;新鸿基团队讲述了他们在农历新年季中展示的元宇宙最新创作&#xff01; 为什么将体验命名为「乘风启航」&#xff1f;什么是 「Scallywag」&#xff1f; 香港专业离岸帆船队新鸿基 Scallywag 队由新鸿基公司赞助&#xff0c;其团队精神与公司的精神相呼…...

Linux中定时监控Tomcat服务器进程并在进程结束时重启Tomcat服务器

目录一、问题二、解决方法1、创建定时任务文件2、修改Tomcat的部分文件3、添加系统的定时调度4、执行monitor.sh文件5、查看脚本执行的日志文件一、问题 当我们的Tomcat配置完成后投入使用后&#xff0c;在用户使用一定时间后&#xff0c;Tomcat可能会出现一些问题导致进程结束…...

快速部署私有云笔记,免费享受多端同步

一、老Q笔记之一路坎坷 市面上的笔记软件非常多&#xff0c;有些是本地编辑功能特别强大但是不支持云同步&#xff0c;有些是支持上云但是编辑功能不够完善。选择一款合适的云笔记软件&#xff0c;无疑能让我们工、学习的时候更加顺心、顺手。 这么多年来老Q使用过很多云笔记…...

python生成 2048位随机质数 Miller-Rabin质数测试算法

Miller-Rabin质数测试算法是一种基于随机化的算法&#xff0c;用于判断一个数是否为质数。该算法具有高效性和强健性&#xff0c;通常被用于加密算法中生成大素数。 该算法基于以下两个事实&#xff1a;对于质数ppp和任意整数aaa&#xff0c;有ap−1≡1(modp)a^{p-1} \equiv 1…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...