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

news2025/2/21 1:28:43

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

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();//启动Akka
    VertXStarter.init();//启动Vertx

    //启动Spring
    try {
        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);
    }

    // 启动 ActorSystem
    Map<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 文档】

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

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

相关文章

DataWhale 大数据处理技术组队学习task1

DataWhale 大数据处理技术组队学习task1 一、大数据概述 1. 大数据时代&#xff08;详细内容参考参考文章&#xff09; 2. 大数据的概念&#xff08;又或者是特点&#xff09; 4V 数据量大&#xff08;Volume&#xff09; 数据来源&#xff1a;可以是计算机、手机&#xff…

Linux 常用命令——【 2.查看程序端口占用及网络连接 netstat 命令】

文章目录1. netstat 简介2.命令格式&#xff1a;3. 命令参数&#xff1a;4. 常用命令1. netstat 简介 netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据&#xff0c;一般用于检验本机各端口的网络连接情况。netstat是在内核中访问网络及相关信息的程序&#xff0c;…

ACWING寒假每日一题python

ACWING寒假每日一题 一、孤独的照片 一个点一个点的来看&#xff0c;比如对于GHGHG中间的G&#xff0c;找到他的左边的G&#xff0c;以及右边的G的位置&#xff0c;l,r分别等于1&#xff0c;答案就要多加上11 但是如果对于 GHHGHHG 中间的G&#xff0c;我们可以看到l,r等于2&a…

【计算机网络期末复习】第六章 应用层

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为想复习学校计算机网络课程的同学提供重点大纲&#xff0c;帮助大家渡过期末考~ &#x1f4da;专栏地址&#xff1a; ❤️如果有收获的话&#xff0c;欢迎点…

Echarts 修改雷达图背景分割面,分割线颜色,设置数据线颜色

第016个点击查看专栏目录Echarts的雷达图背景可以是圆形的&#xff0c;也可以是多边形的&#xff0c;背景颜色&#xff0c;线条颜色都可以做个性化设置&#xff0c;这里是改变背景灰色&#xff0c;设置为浅红色。分割线也变成浅蓝色。同时数据线的颜色也变成了亮色。参考源代码…

【LeetCode】最大正方形 [M](动态规划)

221. 最大正方形 - 力扣&#xff08;LeetCode&#xff09; 一、题目 在一个由 0 和 1 组成的二维矩阵内&#xff0c;找到只包含 1 的最大正方形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [["1","0","1","0…

从零实现WebRTC(二):WebRTC的通信过程

文章目录一、WebRTC需要解决的问题二、ICE(Interactive Connectivity Establishment)三、ICE的详细步骤四、知识点四一、WebRTC需要解决的问题 WebRTC是由google提出的的一个用于端到端实现p2p音视频通信的框架。比起其他的hls, http-flv等直播方案&#xff0c;webrtc在公网的…

ChatGPT的来源-InstructGPT论文简要介绍

文章目录前言一、ChatGPT是什么&#xff1f;二、ChatGPT的前身InstructGPT论文解读论文下载地址&#xff1a;主要内容&#xff1a;模型训练数据类型结果效果示例总结前言 现在大火的ChatGPT功能十分强大&#xff0c;不仅可以回答用户问题&#xff0c;编写故事&#xff0c;甚至…

Spring Cloud Alibaba Sentinel 熔断降级与OpenFeign整合

熔断降级 概述 对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块&#xff0c;可能是另外的一个远程服务、数据库&#xff0c;或者第三方 API 等。例如&#xff0c;支付的时候&#xff0c;可能需要远程调用银联提供的 API&…

关于基线长度对双天线GNSS测姿精度的影响

文章目录一、GNSS测姿原理1. 载波相位双差求解基线向量2. GNSS姿态角表示二、基线长度对GNSS测姿精度的影响三、GNSS定向产品精度描述实例四、参考文献在GNSS定向模块或者板卡的指标参数中&#xff0c;我们一般会看到航向的测量精度和基线的长度相关。在实际使用&#xff0c;用…

Python if else条件语句详解

在刚学习 Python 的时候&#xff0c;我们看到的代码都是顺序执行的&#xff0c;也就是先执行第1条语句&#xff0c;然后是第2条、第3条……一直到最后一条语句&#xff0c;这称为顺序结构。 但是对于很多情况&#xff0c;顺序结构的代码是远远不够的&#xff0c;比如一个程序限…

BERT在CNN上也能用?看看这篇ICLR Spotlight论文丨已开源

如何在卷积神经网络上运行 BERT&#xff1f;你可以直接用 SparK —— 字节跳动技术团队提出的提出的稀疏层次化掩码建模 ( Designing BERT for Convolutional Networks: Sparse and Hierarchical Masked Modeling )&#xff0c;近期已被人工智能顶会 ICLR 2023 收录为 Spotligh…

论文投稿指南——中文核心期刊推荐(植物保护)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

JavaScript原型、原型链、原型方法

文章目录原型和原型链prototype、 __ proto __ 、constructor原型链原型方法instanceOfhasOwnPropertyObject.create()、new Object()总结原型和原型链 prototype、 __ proto __ 、constructor 首先我们看下面一段代码 // 构造函数Personfunction Person(name, age) {this.na…

无法访问org.springframework.boot.SpringApplication

问题 更新idea版本后使用过程中发生下面的错误 Error:(3, 32) java: 无法访问org.springframework.boot.SpringApplication 错误的类文件: D:\maven-repository\org\springframework\boot\spring-boot\3.0.0\spring-boot-3.0.0.jar(org/springframework/boot/SpringApplicati…

【ChatGPT】如何使用python调用ChatGPT API?

是什么ChatGPT&#xff1f; ChatGPT 是由 OpenAI 开发的一个语言模型。OpenAI 是一家领先的人工智能研究机构。ChatGPT 基于变换器架构&#xff0c;使用深度学习生成会话风格的文本。该模型在大量文本数据上进行训练&#xff0c;并可以针对特定任务进行微调。例如&#xff0c;它…

2023年,产业互联网八大趋势

从全世界的TO B发展线来看&#xff0c;中国的TO B企业不是脚步最快的&#xff0c;但它们却也正在通过汲取中国数字经济高速发展的养料不断成长&#xff0c;同时主动下沉&#xff0c;成为新的产业数字化的底盘&#xff0c;做撑举起未来数字中国的无名力量。 作者|皮爷 出品|…

UDS 诊断

UDS全称为Unified Diagnostic Services&#xff0c;统一的诊断服务。由ISO-14229系列标准定义。 诊断通信的过程从用户角度来看非常容易理解&#xff0c;诊断仪发送诊断请求(request)&#xff0c;ECU给出诊断响应&#xff08;response&#xff09;&#xff0c;而UDS就是为不同…

1.9实验9:配置虚链路

1.4.4实验9:配置虚链路 实验目的(1) 实现OSPF 虚链路的配置 (2) 描述虚链路的作用 实验拓扑配置虚链路实验拓扑如图1-19所示。[1] 图1-19 配置虚链路 实验步骤

第2集丨Java中的数据类型汇总

目录一、数据类型分类二、基本数据类型取值范围数据类型的转换byte和char的关系三、包装类一、数据类型分类 二、基本数据类型 取值范围 比特(bit位) : 数据运算得最小存储单位字节(byte) : 数据最小存储单位bit和byte可以互相转换得&#xff0c;1 byte 8 bit位默认情况下&am…