做者 | 汪小哥java
Arthas 对于不少 Java 开发者来讲,已经不可分割了,在咱们平常开发、线上问题排查中扮演了很是重要的角色。做为小开发的我,平常须要排查线上运营同窗提的各类 bug、各类线上问题诊断、平常运维、线上问题优化等等。git
在刚来公司时,我是比较恐惧运维任务的,代码不熟悉、各类问题比较多...几乎崩溃的状态,运维的一周基本上没有干活,彻底是全身心投入到运维的任务中,排查问题效率低下。github
因为深入体验到了这种奔溃,我一直想改变这种状态,直到 Arthas 的开源,让我在这种崩溃的状态中减轻了很多负担,同时也让我成为了同事们咨询 Arthas 排查问题的小帮手~~ 虽然使用 Arthas 特别方便,但在此过程当中也遇到一些问题,做为问题咨询小帮手也感到有点不方便,所以才造就了 Arthas idea 插件的诞生。web
目前 Arthas 官方的工具还不够简单,须要记住一些命令,特别是一些扩展性特别强的高级语法,好比 ognl 获取 spring context 随心所欲,watch、trace 不够简单,须要构造一些命令工具的信息,所以只须要一个可以简单处理字符串信息的插件便可使用。spring
当在处理线上问题的时候须要最快速、最便捷的命令,所以 Idea Arthas plugin 插件仍是有存在的意义和价值的。---这个是最初编写这个插件的最核心的理由。缓存
Arthas 的功能点很是的多(详见下方大图),这里就不一一的讲解了,能够参考使用文档 ,不过最近一直在更新,使用文档中的命令名称可能有变化。mvc
下载 arthas idea 插件:https://plugins.jetbrains.com/plugin/13581-arthas-ideaapp
Preferences
-> Plugins
Settings
-> Plugins
Install Plugin form Disk... 导入插件less
安装以后重启 IDEA 就能够愉快的使用啦!运维
首先要获取 classloader 的 hash 值,而后获取命令,这个是一个交互流程须要连贯性,后续只要是 static 的经过 static spring context 的都须要有这个交互的流程,连贯的,都在同一个界面进行操做.粘贴执行,而后获取结果便可。
这里的 classloader 的 hash 值缓存起来的
最后合并的脚本以下。
ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_NAME' -c 316bc132
经过反射进行设置 static field ,参考:https://github.com/WangJi92/arthas-idea-plugin/issues/1
填写你想要修改的值、默认根据类型设置默认值 Str->"" Long -> 0L 等等。
ognl -x 3 '#field=@com.wangji92.arthas.plugin.demo.controller.StaticTest@class.getDeclaredField("INVOKE_STATIC_FINAL"),#modifiers=#field.getClass().getDeclaredField("modifiers"),#modifiers.setAccessible(true),#modifiers.setInt(#field,#field.getModifiers() & ~@java.lang.reflect.Modifier@FINAL),#field.setAccessible(true),#field.set(null,"设置的值")' -c 316bc132
经过 spring context 进行调用 bean 的方法、字段的内容。
首页要设置一下 static spring context 的路径。
因为都是经过 ognl 调用 static 的 spring context 都须要 classloader,这个就是配置的 spring conetxt 的地址信息:
@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context 参考 demo 就须要配置这个地址。
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()' -c 316bc132
watch 这个是支持在 spring mvc 场景,经过 watch 间接的获取 spring context,须要出发一次接口的调用,能够参考 :https://github.com/WangJi92/arthas-idea-plugin/issues/5
watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").getRandomInteger()'
这个是参考了横云断岭的 arthas 经过 tt 获取 spring context 随心所欲 ,能够参考这个文档:https://github.com/WangJi92/arthas-idea-plugin/issues/4 这里作了些什么?将整个连贯了起来,不须要记住参数信息,而后对于调用的参数进行简单的默认封装,复杂的参数场景不支持,须要手动拼接。
记录获取 spring context
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
而后根据这个 target 获取 spring context 调用方法
tt -w 'target.getApplicationContext().getBean("commonController").getRandomInteger()' -x 3 -i 1000
获取 spring 环境变量这里依托,static spring context ,固然这个 watch 、和 tt 获取 spring context 的场景也是支持的。在线上环境、测试环境程序多复杂,你怎么知道环境中的变量必定是你配置的?在 nacos 等等配置中心的场景,估计手速慢了一点点,可能就没有上去,这个时候就有这种需求获取当前的环境变量。选中变量,而后右键执行命令。因为使用静态的 static spring context 依然须要 classloader 的值。这里已经基本上是 arthas 的上层应用啦。
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")' -c 316bc132
比较优先级,最前面的必定优先级最高,你必定被 spring 的各类优先级顺序搞晕了,那么怎么办呢?arthas idea plugin 支持获取当前的所有的环境变量,依次打印出来,这样就能够了解优先级,特别是接入了 nacos、diamond 等远程的配置中心,实现不同确定更晕了。
参考文档:https://blog.csdn.net/xunjiushi9717/article/details/94050139
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#allProperties={},#standardServletEnvironment=#propertySourceIterator=#springContext.getEnvironment(),#propertySourceIterator=#standardServletEnvironment.getPropertySources().iterator(),#propertySourceIterator.{#key=#this.getName(),#allProperties.add(" "),#allProperties.add("------------------------- name:"+#key),#this.getSource() instanceof java.util.Map ?#this.getSource().entrySet().iterator.{#key=#this.key,#allProperties.add(#key+"="+#standardServletEnvironment.getProperty(#key))}:#{}},#allProperties' -c 316bc132
方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不一样的时间下调用进行观测(能够从新触发,周期触发,惟一缺点对于 ThreadLocal 信息丢失[隐含参数]、引用对象数据变动无效),这个方便二次触发,特别是本身调试不方便的状况下记录下来,二次触发、周期触发,不过自从段岭大神 tt 随心所欲以后都被带偏了。这里 arthas 插件作了一些什么?增长了二次触发的一些经常使用的命令,不让使用者愁于记忆,整个过程更加的具备连贯性。
获取方法从哪里执行的调用栈(用途:源码学习调用堆栈,了解调用流程) 这个是很是好用的功能,对于喜欢乐于排查问题的小伙伴真是福音,arthas idea 插件只是修改的命令的集成,以前也处理本身编码过程当中的问题,源码、问题排查技巧-Java Debug and Arthas:https://blog.csdn.net/u012881904/article/details/104591529
stack com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5
反编译方法、类的源码, 有时候须要查看提交的代码是否上线呢?这个功能就很是的友好。
参考文档:[https://github.com/WangJi92/a...
as-idea-plugin/issues/2](https://github.com/WangJi92/a...
jad --source-only com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger
增长了默认参数、默认展开的层级限制次数,使用者不用知道这些核心的参数,简单的使用就行了,要使用更加的高级的本身help 一下就知道了。
watch com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger '{params,returnObj,throwExp}' -n 5 -x 3 trace com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5
trace -E 本身构造起来很是的麻烦,经过界面操做简化了一下,须要观察多个类、多个方法的场景。选择你须要的场景继续添加便可。
trace -E com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService traceE|doTraceE -n 5
打印堆栈,有点相似 jmap -dump:format=b,file=/temp/dump.hprof pid 下载下来使用 MAT 分析便可。
heapdump /tmp/dump.hprof 打印堆栈信息
这个必需要说一下,这个特殊用法的连接在线上本身束手无措的时候能够查看一下,很是有用。
经过 spring context 调用复杂的方法实际上是不支持的,因为这个操做起来不方便,仍是必须手工处理一下。
好比这里的 Map names 的处理方式能够借鉴一会儿。
更多能够参考 demo:https://github.com/WangJi92/arthas-plugin-demo
/** * 复杂参数调用 场景 * static spring context * ognl -x 3 '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").complexParameterCall(#{"wangji":#user})' -c e374b99 * * watch get spring context 备注 须要调用一次方法 * watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").complexParameterCall(#{"wangji":#user})' * * tt get spring context ,only first get time index ok * tt -w '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),target.getApplicationContext().getBean("commonController").complexParameterCall(#{"wangji":#user})' -x 3 -i 1000 * @return */ @RequestMapping("complexParameterCall") @ResponseBody public String complexParameterCall(@RequestBody Map<String, User> names) { if (names == null) { return "EMPTY"; } return names.toString(); }
本文简单介绍了 Arthas IDEA 插件的安装与使用技巧,该插件解放了你们对于 Arthas 使用的一些记忆、机械性的重复工做,欢迎你们试用!
Arthas 官方举行了征文活动,于 3 月 26 日—— 4 月 26 日举办,若是你有:
欢迎参加征文活动,还有奖品拿哦~点击了解详情。
“ 阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术圈。”