Arthas对于很多Java开发者来说都离不开它,在我们的日常开发和在线排错中扮演着非常重要的角色。作为一个小开发者,每天都需要查看线上运维同学提出的各种bug,各种线上问题诊断,日常运维,线上问题优化等等。刚来公司的时候,比较害怕运维任务。对代码不熟悉,问题多多……我都快崩溃了。运维一周我基本没干活,全身心的投入到运维中。在排查任务中,排查效率低下。因为对这次崩溃的深切体会,一直想改变这种状态,直到Arthas的开源,让我在这种崩溃状态下减轻了很多负担,也让我成为了同事咨询Arthas排错的第一人问题。小帮手~~虽然使用Arthas很方便,但是过程中也遇到了一些问题。作为问题请教小帮手有点不方便,于是诞生了Arthasidea插件。目前Arthas官方的工具不够简单,有些命令需要背,尤其是一些扩展性强的高级语法,比如ognl获取spring上下文为所欲为,watch和trace不够简单,并且需要构建一些命令工具信息,所以只需要一个可以简单处理字符串信息的插件就可以使用了。在处理线上问题的时候,需要最快最方便的命令,所以IdeaArthas插件还是有存在意义和价值的。---这就是当初写这个插件的核心原因。ArthasIDEA插件在练习Arthas中有很多功能(详见下图),这里就不一一说明了。可以参考文档,不过最近更新了,文档中的命令名可能会发生变化。插件安装和下载arthasidea插件:https://plugins.jetbrains.com/...-ideaMac:Preferences->PluginsWindows:Settings->PluginsInstallPluginformDisk...导入插件并安装后,你可以愉快的重启IDEA使用啦!要获取静态变量,首先要获取classloader的hash值,然后获取command。这是一个需要连续性的交互过程。只要是静态的,通过静态的springcontext,就需要这个交互过程。连贯的都在同一个界面。操作。粘贴执行,即可得到结果。缓存类加载器哈希值的最终合并脚本如下。yamlognl-x3'@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_NAME'-c316bc132reflectionsettingstaticfield通过反射设置静态字段,参考:https://github.com/WangJi92/ar...ues/1填写你要修改的值,根据类型设置默认值Str->""Long->0L等。yamlognl-x3'#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,"设置值")'-c316bc132SpringContextInvoke通过springcontext调用bean的方法和字段内容。StaticSpringContextInvokeMethodField首页要设置静态springcontext的路径。由于静态springcontext是通过ognl调用的,所以需要classloader。这是配置的springconetxt的地址信息:@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context参考demo配置该地址。yamlognl-x3'#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()'-c316bc132WatchSpringContextInvokeMethodFieldwatchspring支持这个mvc场景下,通过watch间接获取spring上下文,需要发起接口调用。可以参考:https://github.com/WangJi92/ar...ues/5yamlwatch-x3-n1org.springframework.web.servlet.DispatcherServletdoDispatch'@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").getRandomInteger()'TimeTunnelSpringContextInvokeMethodField这个是参考横云断岭的arthas通过tt获取springcontext可以为所欲为,你可以参考这个文档:https://github.com/WangJi92/ar...ues/4你在这里做了什么?为了让整个事情连贯起来,不需要记住参数信息,然后对调用的参数进行简单的默认封装。不支持复杂参数场景,需要手动拼接。记录获取spring上下文yamltt-torg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapterinvokeHandlerMethod然后获取spring上下文调用方法yamltt-w'target.getApplicationContext().getBean("commonController").getRandomInteger()'根据这个target-x3-i1000获取spring环境变量获取spring环境变量依赖于静态spring上下文。当然这个watch和tt获取spring上下文也是支持的。线上环境和测试环境那么复杂,你怎么知道环境里的变量一定是你配置的?在nacos等配置中心的场景下,估计手速有点慢,可能上不去。这时候就需要获取当前的环境变量。选择变量,然后右键单击以执行命令。由于使用了static静态spring上下文,classloader的值还是需要的。这基本上就是arthas的上层应用。yamlognl-x3'#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")'-c316bc132优先获取所有spring环境变量level,前面肯定是最高优先级的,你肯定被spring的各种优先级顺序弄糊涂了,怎么办?arthaidea插件支持获取当前所有的环境变量,并一一打印出来,方便了解优先级,尤其是连接nacos、diamond等远程配置中心的话,肯定会更晕实现是不同的。参考文档:https://blog.csdn.net/xunjiush...50139yamlognl-x3'#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()instanceofjava.util.Map?#this.getSource().entrySet().iterator.{#key=#this.key,#allProperties.add(#key+"="+#standardServletEnvironment.getProperty(#key))}:#{}},#allProperties'-c316bc132TimeTunnelTt方法执行数据的时空隧道,记录指定方法每次调用的入参和返回信息,可以在不同的时间观察这些调用(可重触发,周期性触发,唯一不足的是ThreadLocal信息是lost[隐藏参数],引用对象数据更改无效),这个方便二次触发,尤其是不方便自己调试的时候记录一下,二次触发,周期性触发,不过既然断灵大神tt为所欲为,它已误入歧途。arthas插件在这里做什么?增加了一些常用的二次触发命令,免去用户内存的烦恼,整个过程更加连贯。stack获取方法执行的调用栈(目的:源码学习调用栈,了解调用流程)这是一个非常实用的功能,对于喜欢排查问题的朋友来说真是福音。arthasideaplugin只是修改命令的集成,我也处理了我之前编码过程中的问题,源码,排错技巧-JavaDebug和Arthas:https://blog.csdn.net/u0128819...91529yamlstackcom.wangji92.arthas.plugin.demo.controller.CommonControllergetRandomInteger-n5DecompileClassJad反编译方法和类的源代码。有时候需要检查提交的代码是否在线?这个功能非常友好。参考文档:https://github.com/WangJi92/arth!as-idea-plugin/issues/2yamljad--source-onlycom.wangji92.arthas.plugin.demo.controller.CommonControllergetRandomIntegerwatch,trace添加默认参数,默认扩展的级别数量有限。用户无需知道这些核心参数,简单使用即可。如果你想使用更高级的自助,你会知道的。yamlwatchcom.wangji92.arthas.plugin.demo.controller.CommonControllergetRandomInteger-n5trace-E(levelprinttrace)trace-E自己构造起来很麻烦。通过接口操作来简化,需要多类多方法的场景观察。只需选择您需要的场景并继续添加。yamltrace-Ecom.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestServicetraceE|doTraceE-n5HeapDump打印栈,有点类似jmap-dump:format=b,file=/下载temp/dump.hprofpid并使用MAT分析。yamlheapdump/tmp/dump.hprof打印堆栈信息特殊用法链接这个不得不说,这个特殊用法链接可以在网上一头雾水的时候查一查,很有用。对于通过springcontext调用方法,其实是不支持通过springcontext调用复杂方法的。由于此操作不方便,必须手动处理。比如这里的Mapnames的处理方法可以借鉴。更多可以参考demo:https://github.com/WangJi92/arthas-plugin-demoyaml/***复杂参数调使用场景*staticspringcontext*ognl-x3'#user=newcom.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})'-ce374b99**watchgetspringcontext备注需要调用一次方法*watch-x3-n1org.springframework.web.servlet.DispatcherServletdoDispatch'#user=newcom.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})'**ttgetspringcontext,onlyfirstgettimeindexok*tt-w'#user=newcom.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),target.getApplicationContext().getBean("commonController").complexParameterCall(#{"wangji":#user})'-x3-i1000*@return*/@RequestMapping("complexParameterCall")@ResponseBodypublicStringcomplexParameterCall(@RequestBodyMap
