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

上期我们抛了一个砖:“如何实现 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. safari坑之 回弹

    博客地址: https://www.seyana.life/post/20 今天在使用safari浏览博客的时候, 发现在拉至顶部并产生回弹之后,头部导航隐藏了, 除非在上拉的时候,刚好达到顶部而不超 ...

  2. 负margin在页面布局中的应用

    关于负margin的原理建议大家看看这篇文章:http://www.cnblogs.com/2050/archive/2012/08/13/2636467.html#2457812 一. 左右列固定, ...

  3. Protocol buffers编写风格指南

    原文链接:https://developers.google.com/protocol-buffers/docs/style Style Guide 本文说明了.proto文件的编写风格指南.遵循这些 ...

  4. adb模拟按键与输入

    在 adb shell 里有个很实用的命令叫 input,通过它可以做一些有趣的事情. input 命令的完整 help 信息如下: Usage: input [<source>] < ...

  5. ajax 瀑布流 demo

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. Geotools在shapefile路网数据中建立缓冲区,并获取缓冲区内的要素

    记录一下如何创建创建缓冲区并获取缓冲区内的要素,便于以后查找使用 static SimpleFeatureSource featureSource = null; static CoordinateR ...

  7. StormDRPC流程解读

    Storm 的编程模型是一个有向无环图,模型角度决定了 Storm 的 Spout 接收到外部系统的请求,将请求数据分发给下游的 bolt 进行处理后,spout 并不能得到 bolt 的处理结果并将 ...

  8. 一文带你熟悉SpringIOC

    Spring的IOC: IOC是Spring的一个核心组件,理解IOC是迈向Spring大门的重要一步 现实生活中,我们写字用的笔会有多种颜色,为了做不同的标记,需要用不同颜色的笔.如果只是使用一两种 ...

  9. 6. concat_ws用法

    select  CONCAT_WS('-', e.audit_one_name, e.audit_second_name) from t_audit_item_name e  where e.id= ...

  10. 说两个我在工作中有价值的bug

    看了虫师在公众号上写的一边文章,叫做<面试官问,说一个你在工作非常有价值的bug>.看完虫师举的列子后,我也开始想之前测试的bug,想到之后,觉得有必要记录一下. First,在测试新闻动 ...