使用Arthas 获取Spring ApplicationContext还原问题现场
背景
*近来了个实习僧小弟,安排他实现对目标网站 连通性检测的小功能,简单讲就是将下边的shell 脚本换成Java 代码来实现
-
1#!/bin/bash
-
2URL=“https://www.baidu”
-
3HTTP_CODE=`curl -o /dev/null -s -w “%{http_code}” “${URL}”`
-
4#echo $HTTP_CODE
-
5if [ $HTTP_CODE != ’200′ ];then
-
6curl ‘https://oapi.dingtalk.com/robot/send?access_token=xx’ \
-
7 –H ‘Content–Type: application/json’ \
-
8 -d ‘{“msgtype”: “text”,
-
9 “text”: {
-
10 “content”: “百度平台状态不正常,请注意!”
-
11 },
-
12 “isAtAll”: true
-
13 }’
-
14
-
15fi
功能实现
使用spring task
-
1@Scheduled(cron = “0 0 0/1 * * ? “)
-
2public void startSchedule() {
-
3 log.info(“开始执行定时任务 ,检测百度网站连通性”);
-
4 try {
-
5 HttpResponse response = HttpRequest.get(“”).execute();
-
6 if (HttpStatus.HTTP_OK != response.getStatus()) {
-
7 this.send2DingTalk(response.getStatus());
-
8 }
-
9 log.info(“请求百度成功,返回报文:{}”,response.body());
-
10 } catch (HttpException e) {
-
11 log.error(“请求异常百度:{}”, e);
-
12 this.send2DingTalk(e.getMessage());
-
13 }
-
14 log.info(“执行检测百度网站连通任务完毕”);
-
15}
问题描述
部署在服务器上,我的老jio本 都已经呼叫任务状态不正常了,可是小弟的Java 代码还是没有执行通知
- 去翻生产日志,只输入了开始并没有输出定时任务结束,感觉是哪里卡死,想当然以为如果超时总会到catch 逻辑,排查无果
- 由于任务是一小时一次,如何快速触发一下这个异常,还原事故现场
- 由于使用简单的Spring Task 没有图形化界面和API接口
Arthas 还原事故现场,重新触发任务
核心拿到 spring context 然后执行它的 startSchedule
方法
确定监控点
- SpringMVC 的请求会通过
RequestMappingHandlerAdapter
执行invokeHandlerMethod
到达目标接口上进行处理 - 而在
RequestMappingHandlerAdapter
类中有 getApplicationContext()
-
1
-
2public final ApplicationContext getApplicationContext() throws IllegalStateException {
-
3 if (this.applicationContext == null && this.isContextRequired()) {
-
4 throw new IllegalStateException(“ApplicationObjectSupport instance [“ + this + “] does not run in an ApplicationContext”);
-
5 } else {
-
6 return this.applicationContext;
-
7 }
-
8}
- 任意执行一次请求获取到
RequestMappingHandlerAdapter
target 目标,然后执行getApplicationContext
tt命令 获取到ApplicationContext
- arthas 执行 tt
1tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
- 任意执行一次web 请求,tt 即可捕获
- 根据目标的索引,执行自定义 OGNL 表达式即可
1tt -i 1019 -w 'target.getApplicationContext()'
使用ApplicationContext获取 定时任务bean 执行 startSchedule
1tt -i 1000 -w 'target.getApplicationContext().getBean("baiduSchedule").startSchedule()'
ok 任务重新触发了
事故原因调查清楚,由于使用hutool 的工具类 没有设置timeout 导致无限等待,所以没有执行catch 逻辑
总结
以上吓哭实习僧的操作禁止
生产操作,只是提供个思路 ,当然可以衍生其他业务场景的操作
核心是通过Arthas 来抓取Spring ApplicationContext 对象,然后获取bean 进行执行方法
关于Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱