有一天,开发的代码在CI阶段遇到这样一个看似“诡异”的问题:代码在CI阶段,有一个步骤会去单元测试。因为依赖远程配置中心,所以有两种配置,一种在配置中心,一种在本地yml文件。这两个配置中使用了两个不同的数据库。一般情况下,本地开发可以方便的在yml中设置需要的属性进行测试,然后将不同环境下的配置添加到配置中心,相当于不同的配置文件。而这个诡异的问题是,在单测阶段,在两个不同的数据库上跳来跳去,某个测试数据写在A,其他测试可能写在B,直觉上是配置加载错误,但是不确定何时使用哪个配置。CI机器是公共容器,没有权限登录。我的第一个想法是JMXMBean上可能有这个信息。只要连接了JConsole,就可以查看。我在本地试了一下,没有问题。通过org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager的ObjectName,可以得到Env对象,然后就可以进行setProperty和getProperty操作了,像这样。操作中可以选择getProperty,然后写入属性名,点击按钮。但无奈,远程机器并没有开启JMX连接,于是开始想其他的办法。折腾了一番,发现机器所在的平台上有网页版的命令,支持部分Arthas命令。可以在页面选择命令,在输入框中定义参数值,发送到远程服务器执行。之前研究过一些Arthas的使用和实现原理(阿里监控诊断工具Arthas源码原理分析),感觉这个可能会派上用场。毕竟Agent附加到JVM之后,通过JVMTI可以做的事情太多了。网上的文章基本介绍都是通过tt命令获取ApplicationContext,然后进行其他想要的操作。查看Arthas的文档。在提供的命令中,watch和tt这两个命令可以获取输入参数、返回值、目标等,还支持Ognl表达式。不过上面说的页面平台不支持tt。可以通过迂回的方式使用手表来检查。折腾了一番,在页面发送的命令中加入了转义,通过watch中的target对象进行了额外的操作,终于实现了需要的功能。它可以通过watch命令执行。如果需要在本地执行,需要去掉这两个转义字符。org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapterinvokeHandlerMethod'{target.getApplicationContext().getEnvironment().getProperty(\"app.name\"),returnObj}'-x2除了取env除了属性值的作用外,还可以在方法执行的不同阶段观察到besf的选项。此外,还可以添加过滤表达式,为输入值添加条件,像这样:可以灵活组合,应用于场景中的分析问题。折腾了下,可以查看加载的配置文件,但是跑单个测试为什么要来回改配置呢?有同学Debug发现,原来是有的测试类加了@TestProperty注解,有的没写。该注解改写了一个配置中心命名空间的属性,导致远程配置中心的配置拉取失败。直接使用本地的yml配置,与yml配置和远程配置中心不一致,所以出现了一个看似诡异的问题。如果你也有需要排查的问题,可以尝试相关阅读中的Arthas或者其他几个工具。
