阅读 1569

JRebel + Arthas 大幅提高开发幸福感

前言

选择编程语言,不仅看语言本身提供的特性,更关键的是生态。生态决定了真正的开发效率,以及能够站在多高的巨人肩膀上。而 Java 在这一点,可以说拥有其他所有语言都难以企及的生态,不仅体现在编程时,运行时的 Java 同样是世界上最具可观测性可调试性的语言。这篇文章会从一个侧面体现这点。

本文向大家介绍一种的开发方式,让你写代码像 JS 一样即时生效,还能做到 JS 也做不到的超距调用

适用人群

所有 Java 开发,尤其是基于 Spring Boot 的开发人员。以下的内容均默认在 Spring Boot 开发的场景。

适用场景

  • 开发 xxl-job 或其他定时任务,需要等待任务中心调度的场景
  • 开发 Dubbo 等 RPC 接口,难以构造请求协议测试接口的场景
  • 开发消费 MQ 消息队列时,需要在远程构造消息内容的场景

使用 Arthas + JRebel 的组合,以上场景均可以绕过一切外部系统的依赖直接调用,随意构造参数。

效果演示

快速调用方法

调用 XXL-JOB 任务: Kapture 2021-08-16 at 18.07.02.gif

调用其他 Spring Bean

可随时修改随时生效 Kapture 2021-08-16 at 18.14.18.gif

新建测试方法,构建测试参数

Kapture 2021-08-16 at 18.17.37.gif

如何实现?

JRebel Plugin For IDEA

JRebel 是一个神奇的工具,它做到了真正的代码热加载,可以避免了绝大多数需要重启的场景。

我们知道代码的热加载热更新,通常是用 classLoader 的 retransformClass 和 redefineClass,比如 Skywalking 是在类加载之前使用 retransformClass 来更改类的内容实现代理,而 tomcat、spring boot 的热加载则是后者。但是 redefineClass 有个致命的缺陷,所有的修改只能针对已有的方法和属性。

而 JRebel 则选择了另外一条路,实现原理可以看这里:How does JRebel work? 有兴趣可以看看,不过文章中实现细节不多。大意是 JRebel 绕开了 Java 本身的限制,自己实现了一套。不仅如此,在 Spring 这样的容器中,不仅是新增类的问题,还需要注册成 bean。所以 JRebel 还要负责去管理 Spring 框架载入 bean 的流程。这其中不得不说做了大量的工作。可以说在这个领域,找不到任何替代品。

JRebel IDEA 插件的安装激活方式可以在网上找找,其实 JRebel 是收费的,但目前没有针对个人用户的付费渠道。

Tips1: 记得项目启动配置中勾选 spring boot 下的 「On 'Update' action」 为 「Update classes and resources」: 截屏2021-08-16 18.45.29.png

Tips2: 如果项目中用了 MyBatis Plus,还需要一个 JRebel MybatisPlus Extension 插件:

截屏2021-08-16 18.46.17.png

现在我们得以在新增/修改 类、方法、变量、HTTP 接口、MyBatis XML 等省去了反复重启项目。

能不能动态调用方法?

JRebel 几乎做到了动态加载一切,Java 类加载这点东西让它整得明明白白,什么都可以是动态的,那它能不能动态调用方法?为什么方法必须要一层一层调用过来?

在我们开发的时候,经常遇到很多调试的麻烦,除了 HTTP 接口,类似 Dubbo 接口、XXL-JOB 定时任务、程序中层级比较深的函数,都非常不方便触发。有时候为了验证某个 SQL 条件都能浪费个十分钟过去,因为层级太深了。

于是我开始寻找这种方法,JRebel 没有,万能的 IDEA 没有,会不会有个 IDEA 插件来做这事呢?也没有。

在寻找的过程中,我逐渐意识到这个问题的本质。调用某个方法听起来简单,最麻烦的是在一个正确的上下文里执行,比如 Spring 的上下文,否则调用代码本身只能得到一堆 NPE。也就是说,我们得找到具体的实例去执行对应的方法。

Arthas

Arthas 是一个神级的 Java 诊断工具,它一举将 Java 的可观测性提升到了不可思议的地步。Arthas 功能很多,在这暂且按下不表,日后开新篇专门介绍。

而 Arthas 自己可能也没想到的,它还可以被用来在开发时提高效率。刚才我们希望动态调用方法,Arthas 提供了两种方式实现:

  1. vmtool

我们可以利用 vmtool 从 JVM 里查询对象,用这个对象执行方法。通常情况下,这个对象就是我们想要的。但是实测在开发时与 IDEA 相冲突,会报错。正常部署的项目可以使用这种方法。

  1. ognl

ognl 是一种操作对象的表达式,在 arthas 获取 spring 被代理的目标对象 一文中,提到了可以用它来调用 Spring 中的方法,只要我们提供一个获取 SpringContext 的变量即可。

组合起来

接下里搞上下面几个东西,就可以让开发过程变得无比顺滑:

Arthas IDEA 插件

Arthas 的命令太多,我们可以在 IDEA 中安装这个(Github 地址)插件自动生成命令。安装插件之后可以参考 设置获取 spring context 的上下文 ,提供出 Spring Context 的地址并配置到插件中。

Arthas Spring Boot Starter

让 Arthas 随项目启动时一起启动,免去了每次启动 Arthas 选择进程的麻烦。如果线上不希望启动 arthas,在启动参数中加 -Dspring.arthas.enabled=false。

文档见:arthas.aliyun.com/doc/spring-…

Embedded Web Browser

IDEA 的一个小插件,内置在 IDE 里的简易浏览器。我们会用这个来打开 arthas 控制台,不用在浏览器与 IDE 之间反复横跳了。

设置两个快捷键,可以更快一步

  • idea arthas 复制调用 spring 方法的命令:

截屏2021-08-16 18.36.20.png

  • idea reload 项目的动作:

截屏2021-08-16 18.36.49.png

最终效果

现在我们拥有了完整体的效率工具包,写代码时通过 JRebel 免去了重启,调用方法通过 Arthas idea plugin 复制命令,打开内置浏览器小窗口,在 Arthas 控制台中粘贴即可。方法没写对?改了后点击更新,再回到小窗口中调用一次,随时验证。代码不再需要 HTTP 接口,函数即入口。

回头我会录一个完整的开发流程 Demo,更直观地显示这种开发方式带来的效率提升,以及其自由与乐趣。

文章分类
开发工具
文章标签