各位坐稳扶好,我们要开车了。不过在开车之前,我们还是例行回顾一下上期分享的要点。

上期我们抛了一个砖:“如何实现 Java 应用进程的状态监控,如果被监控的进程 down 掉,是否有机制能启动起来?”并结合 Resin 应用服务器背后启动的进程,更详细的阐述了一下问题。

我们依然不考虑自己怎么去实现,而是先看看 Resin 这款技术轮子,是不是按照我们的猜想设计的呢?是不是可以模仿一二?

好了,熟读唐诗三百首,不会作诗也会吟,抱着疑问,我们再深入一次 Resin 的源码,如果不感兴趣,或者脑仁疼,那建议跳到下篇直接撸码实战。

1.

我们从 ResinBoot 的 main 函数开始,一步一步来看看怎么实现,目标是提取里面的关键核心思想,细枝末节莫纠结。

ResinBoot 的 main 函数是 Resin 应用服务器入口,大概流程如下:

创建 ResinBoot 实例 boot;

然后根据传入的 args 参数获取对应的 XxCommand 对象;

接着调用 ResinBoot 的 start 函数,完成服务的启动;

最后退出 ResinBoot 的进程。

  

那接下来不妨再深入看看创建 ResinBoot 对象时,构造方法中都干了啥?

发现 ResinBoot 创建对象时,构造方法中创建了 WatchdogArgs 对象,WatchdogArgs 里面到底又做了什么呢?

发现 WatchdogArgs 静态代码块中提前预制了一堆命令执行的对象实例,其中就包括 StartCommand,再回头看看它的构造方法,会发现会进行解析咱们 main 函数传入的 args 入参,然后根据入参获取对应的命令执行对象。

其中格式化命令行入参的方法 parseCommandLine 会匹配一堆预制的参数,实在匹配不到就从静态的 _commandMap 中去匹配对应的命令执行对象,当然咱们传入的参数是 start,所以会匹配成功  StartCommand。

那么我们再回头看看 ResinBoot 的 main 函数,发现又调用了 ResinBoot 的 start 方法。

那我们也一起看看 ResinBoot 的 start 方法做了些什么操作?发现方法中获取对应的 command,然后调用 command.doCommand() 方法。

我们知道此时的 command 为 StartCommand,那 StartCommand 中的 doCommand() 到底做了什么事情呢?会发现 doCommand 方法中调用了 WatchdogClient 的 startWatchdog 的方法。

那我们看看 startWatchdog 方法中又做了哪些事情?重点要来了,重点要来了,重点要来了。发现调用了 launchManager 方法,那 launchManager 又是干什么的呢?

仔细深入会发现,launchManager 方法主要用 ProcessBuilder 来实现启动 WatchdogManager 的进程。

并且第 539 行有一句日志输出,和咱们在控制台输入 ./resin.sh start 命令启动 Resin 服务时的日志不谋而合。

至此,ResinBoot 通过 ProcessBuilder.start() 成功触发启动 WatchdogManager 进程,也就是咱们猜测的大总管进程,哪丫鬟进程是否也存在呢?丫鬟进程又是怎么启动的呢?

2.

此时我们跟随源码设计的脚步,继续向下刨一刨 WatchdogManager,发现 WatchdogManager 程序入口 main 函数中,根据传入参数构建了 WatchdogManager 对象,并通过参数获取对应的 XxCommand(似曾相识的感觉),然后通过 XxCommand 调用 doWatchdogStart 函数完成服务的启动。

再深入去跟踪,发现 doWatchdogStart 方法中会调用 WatchdogManager 的 startServer 方法。

那 startServer 方法中又干了什么事情呢?很显然是通过配置找到要启动的子服务,然后调用重载的 startServer 方法。

接着就开始调用 WatchdogChild 的 start 方法,方法干了什么事情呢?

WatchdogChild 的 start 方法中创建了 WatchdogChildTask 任务对象,并调用 start 方法完成任务启动。

其中 WatchdogChildTask 的 start 方法很简单,就是起了一个线程开始跑任务。

重点再一次来临,会发现线程体中创建了一个 WatchdogChildProcess 对象实例,接着调用对象的 run 方法。此处就是保证了 Resin 应用为什么一直杀不死的原因,有个循环调度,一旦子进程有问题,立即再次进行创建子进程。

我们看看 run 方法的实现,会发现创建了一个 socket 用于通讯;然后把端口传入 createProcess 方法构建 Resin 进程对象。

接着会发现 WatchdogProcess 的创建进程的方法 createProcess 中定义要启动的类为 com.caucho.server.resin.Resin;然后封装一系列的参数;紧接着用 ProcessBuilder 完成 Resin 进程的启动。

然后 connectToChild 方法主要用于等待子进程的连接。这不就是大总管开辟的实时通讯的端口么!

至此,我们知道 WatchdogManager 会创建 WatchdogTask 任务,用于创建WatchdogChildProcess 对象,此对象会触发启动 Resin 进程,并提供 socket 通讯服务。

3.

那 Resin 进程又干了啥?我们依然从 main 函数开始看起。一目了然根据传入参数创建 Resin 实例,然后重点关注一下 waitForExit,这个是不是和咱们猜测的丫鬟进程与大总管进程通讯不上就退出,是不是这么回事呢?

然后深入 Resin 的 waitForExit 方法发现通过 pingSocket 参数构建 ResinWaitForExitService,用于启动 ResinActor(这个 Actor 模型前期的分享咱们提过一嘴),然后调用 waitForExit 方法。

到这大概也就到了最后,根据蓝色框中的日志输出约莫也就是那么回事儿。

...... 此处省略一万图(不刨了,点到为止)......

至此,丫鬟进程 Resin 也启动完毕了,并且与父进程建立了实时通讯。源码看了七七八八,细枝末节没细谈,主要是能明白梗概,梳理个大致脉略,能大致清晰 Resin 服务启动时启动了 ResinBoot 进程、WatchdogManager 进程、Resin 进程,当进程启动完成后 ResinBoot 进程就正常退出了,所以当我们用 jps 命令看时,就发现只有 WatchdogManager、Resin 两个进程啦,其中用到的核心技术为 ProcessBuilder、Socket 通讯。

好了,能坚持看到这儿的,那绝对都是铁粉,希望我不是一人在饮酒醉,独醉不如众醉,独乐乐不如众乐乐,希望这期的分享能帮你打通任督二脉,以后如果真用到时,不妨以本文作为参考,说不定会有点价值。

下期我们将站在 Resin 的肩膀上进行实战,请各位期待。

如何让Java应用成为杀不死的小强?(中篇)的更多相关文章

  1. 如何让Java应用成为杀不死的小强?(上篇)

    各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 项庄舞剑意在沛公,而咱们上期主要借助应用服务器 Resin 的源码,体验了一次 JMX 的真实应用.鉴于 9012 年 ...

  2. 如何让Java应用成为杀不死的小强?(下篇)

    各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 经过前两期的铺垫及烧脑的分享,我们大概对「如何实现 Java 应用进程的状态监控,如果被监控的进程 down 掉,是否 ...

  3. 一个杀不死的小强,kill进程无效的原因 记录故障排查过程中kill进程无效的分析过程

    今天在处理一个机器异常负载(1000+)的问题,碰到了一个从未碰到过的情况,遇到了一个异常顽固的分子.我使用了所能想到的所有杀进程的方法,却始终无法干掉这个顽固分子,最后终于在谷歌大神的指引下,干掉了 ...

  4. Linux中杀不死的进程

    前段时间,一哥们,去杀Linux服务器的进程,发现kill命令失灵了,怎么杀都杀不死. 然后上网查了下资料,原来是要被杀的进程,成为了僵尸进程. 僵尸进程的查看方法: 利用命令ps,可以看到有标记为Z ...

  5. paip.杀不死进程的原因--僵尸进程的解决.txt

    paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...

  6. 手把手教你写LKM rookit! 之 杀不死的pid&root后门

    ......上一节,我们编写了一个基本的lkm模块,从功能上来说它还没有rootkit的特征,这次我们给它添加一点有意思的功能.我们让一个指定的进程杀不死, 曾经,想写一个谁也杀不死的进程,进程能捕捉 ...

  7. Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程

    Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程 原因: 一般造成这种原因是因为项目中有非守护线程的存在: 解决方案: 一.从Tomcat上解决 方案1:(推荐的方案:因为一台 ...

  8. 不死的小强 .net core 微服务 快速开发框架 Viper 限流

    1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...

  9. Android设备直接运行java项目?还杀不死?

    思路:拿到dex可执行文件,使用android执行 使用idea创建java类库,写相关逻辑代码 使用idea导出该类库jar包 使用android dx工具 将jar文件转换为dex可执行文件 dx ...

随机推荐

  1. 复习笔记——1. C语言基础知识回顾

    1. 数据类型 1.1 基本数据类型 整型:int, long,unsigned int,unsigned long,long long-- 字符型:char 浮点型:float, double-- ...

  2. 02 VMware下载与安装

    一.虚拟机的下载 1.进入官方网站 vmware Workstation 官方网站: https://www.vmware.com/cn.html 2.根据操作系统选择合适的产品,在这里以Window ...

  3. 简说Python之图形初体验

    针对孩子,最容易引起小孩的感官认知的就是图形.因此,系统运用图形编程,可以更好地让孩子喜欢上编程. turtle叫做,Turtle graphics.是python第三方的画图模块工具.可以通过imp ...

  4. Java自学路线图之Java系统自学

    Java自学不是一朝一夕的事情.可以采用"懒开始"的方法,但是必须要坚持下去,才能真正自学Java掌握编程技术.那些企图学几天去包装一下找工作的,请绕道.如果你下定决心自学Java ...

  5. eslint常用三种校验语句

    1.关闭对整段代码的校验 /* eslint-disable */ code /* eslint-enable */ 2.关闭当前行代码的校验 line code // eslint-disable- ...

  6. 详解分页组件中查count总记录优化

    1 背景 研究mybatis-plus(以下简称MBP),使用其分页功能时.发现了一个JsqlParserCountOptimize的分页优化处理类,官方对其未做详细介绍,网上也未找到分析该类逻辑的只 ...

  7. Python基础篇_实例练习1

    1.逢7跳过小游戏:从1-100之间,遇到带7的数字或者7的倍数跳过. for i in range(1,101): if i == 7 or i % 10 == 7 or i // 10 == 7: ...

  8. Java多线程并发04——合理使用线程池

    在此之前,我们已经了解了关于线程的基本知识,今天将为各位带来,线程池这一技术.关注我的公众号「Java面典」了解更多 Java 相关知识点. 为什么使用线程池?线程池做的工作主要是控制运行的线程的数量 ...

  9. SSM整合搭建(二)

    本页来衔接上一页继续来搭建SSM,再提一下大家如果不详细可以再去看视频哦,B站就有 之后我们来配置SpringMVC的配置文件,主要是配置跳转的逻辑 先扫描所有的业务逻辑组件 我们要用SpringMV ...

  10. Sqli-labs 搭建SQL注入平台

    sqli-labs是一款学习sql注入的开源平台,共有75种不同类型的注入. 搭建步骤: 1.在Windows系统中安装WAMP 下载地址:https://pan.baidu.com/s/1HY0hF ...