资讯专栏INFORMATION COLUMN

【效率专精系列】几种常见的JVM热部署技术及实现难点浅谈

dongfangyiyu / 591人阅读

摘要:而热部署技术能够帮助开发人员减少重新部署的等待时间。本文的目的为调研热部署的技术现状及其对开发效率的帮助,并简单梳理其技术实现的难点。热部署技术总结热部署目前有多种技术实现官方开源商业。

开发、自测、联调期间代码可能会被频繁地修改,通常即使只增加了一行代码,都需要重启容器以检查执行效果。而热部署技术能够帮助开发人员减少重新部署的等待时间。本文的目的为调研热部署的技术现状及其对开发效率的帮助,并简单梳理其技术实现的难点。

热部署技术 总结

JVM热部署目前有多种技术实现:官方、开源、商业。其中商业的JRebel功能强大,涵盖了日常开发中大部分热更新场景。以团队中一个基于Tomcat + Spring的业务后台为例,修改代码后,本地冷启动耗时4.5min,本地热部署的时间则小于1s,极大改善了开发效率。

官方实现

当前JVM和JVMTI(JVM Tool Interface)规范中通过相应的agent机制支持的retransformClass/redefineClass操作可以在加载前和加载后动态修改类的内容,从Java 5开始,这一功能还通过Instrumentation API直接提供给Java应用使用,但是其适用范围是受限的:只能修改已有方法的方法体。

以下摘自 JVM(TM) Tool Interface 1.2.3
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance. These restrictions may be lifted in future versions. See the error return description below for information on error codes returned if an unsupported redefinition is attempted.

IDE的edit-and-continue功能(Intellij IdeaUpdate Application)就用到了这种被称为HotSwap的热部署技术,但是它的限制太大,完全无法满足实际开发中的需求。

Dynamic Code Evolution VM(DCEVM)

这是一个由JKU主导的、基于HotSpot VM的研究项目,诞生于2010年。该项目希望能动态修改类的任意元素,包括成员、方法、注解、继承等而无需重启JVM。目前的light版已经支持到Java 8 update 144, build 2

HotSwapAgent

基于DCEVM构建的开源项目,其完成度要高于DCEVM,目前已发布1.0版。对于常见的IDE、IoC/ORM/Log框架、J2EE应用容器的支持比较完善。根据官方文档,HA支持下列特性。

Add/remove/modify class fields.

Add/remove/modify methods. Add/remove/modify method annotations

Add/remove/modify classes including anonymous classes. HotswapAgent handless correct anonymous class redefinitions.

Add/remove static member of classes. HotswapAgent handles static member initialization.

Add/remove enum values

Refresh framework and application server settings

JRebel

Java世界中大名鼎鼎的热部署解决方案,热部署特性与上面提到的HotSwapAgent类似。当然作为一款商业软件,它支持的框架、IDE、J2EE应用容器的种类都更多,总计100+;同时支持Hotspot VM和Oracle VM;文档和社区支持非常完善,很容易上手。

最重要的是,没钱的码农可以通过赞助官方的Social Plan免费激活JRebel!

JRebel实测

测试环境为团队使用的Tomcat + Spring + SpringMvc
以下是实际开发中常见的改动类型的测试结果。【Pass】为支持,【Fail】为不支持。

【Pass】在Spring和SpringMvc的配置Xml中增加Bean定义

【Pass】新增Controller类,新增、修改Controller注解

【Pass】新增、修改RequestHandler方法、方法体、方法签名、注解

【Fail】在Spring和SpringMvc的配置Xml中增加、修改容器配置项。如 / / /

浅谈热部署的实现难点

热部署的本质,简单的理解,是在运行中实时增加、替换JVM中的类文件而无需重启JVM。

众所周知,JVM使用ClassLoader加载类文件,内含的双亲委派模型通过指定类文件加载的顺序避免由于类冲突而导致核心类库加载失败。单个ClassLoader不能加载全限定名相同的类;不能修改已加载的类的声明;不能卸载已加载的类,除非移除整个ClassLoader,或者被GC回收。

那么,修改原有的类(如Test.class)的任意元素后,热部署就会面临很多问题。比方说:

两个全限定名相同的类如何加载?

类的实例化如何获取到新的类?

更新类的声明后,如增加类方法、实例方法;修改类方法、实例方法签名、方法体、方法注解;新增、修改类变量、实例变量;修改接口、类的继承关系,调用点怎么指向新的类?

如果JVM使用了内联优化技术呢?

如何保证反射正确,比如调用ClassgetName()getMethods()getField()等方法时如何获取到新的类?

如果用了容器或者框架,修改JavaConfig或者XML后,怎么反映到容器里?

热部署问题在底层绕不开ClassLoader,当一个类被更新后,需要被重新载入到ClassLoader中,原先对类变量、实例变量、类方法、实例方法的调用都需要重定向到新类。可以通过引入一个包含所有符号链接的中间层,当JVM加载用户的类时进行动态增强,并记录下涉及的符号链接。

举几个实现思路的小例子:

在类加载时为新的类起一个新的限定名(如原来的类名是Test,而新的类名是Test_v1),绕开ClassLoader的限制。

所有指向老的类的符号链接都实时替换为相应的新符号链接

在ClassLoader中查找老的类时返回新的类

监控容器配置文件,发生变化后调用容器refresh API

Reference

Java SE 6 新特性 Instrumentation 新功能

HotSwapAgent

深入探索 Java 热部署

DCEVM

Get True Hot Swap in Java with DCEVM and IntelliJ IDEA

Features - JRebel

HotSwap和JRebel原理

实现增强的java class hotswap (三) 解决方案 续

实现增强的java class hotswap (三) 解决方案

Java是否可以做到修改类而不用重启JVM?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70435.html

相关文章

  • 效率专精系列】我有一个梦想:提高开发效率,晚上回家吃鸡

    摘要:效率专精系列善用统一描述语言提升开发效率分钟搞定环境配置与使用考虑到篇幅较长的文档反复修改的情况,要快速找到修改点比较困难。 之前零零散散写了几篇文章,主要是实际开发过程中一些效率痛点和相应的改善方法。今天抽空温故知新,把之前的内容串起来,做了个小总结,即《效率专精系列》小系列的总集篇。 回顾项目开发流程 开发一个新项目时,开发流程大概分成以下几步: 设计方案,并落地成设计文档 设计...

    zhaot 评论0 收藏0
  • 效率专精系列】Beta环境不需要,本地联调拯救开发效率

    摘要:目前团队中前后端联调是较之个人单独开发相对耗时的一个环节,主要体现在环境下的部署时间较长。本文的目的是通过将联调本地化,减少部分枯燥劳动以及无效的等待时间,提高团队的开发效率。不需要更改的为外部,保持即可。 目前团队中前后端联调是较之个人单独开发相对耗时的一个环节,主要体现在: beta环境下的部署时间较长。首先部署beta需要经过push分支、合并冲突、build、部署四个步骤。...

    cc17 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,附链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    spacewander 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,附链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    xfee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<