热部署instrumentation工具类

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 利用jvm的instrumentation类实现实时修改class文件,用来更新线上代码。

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.agent.ByteBuddyAgent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
public class ReloadClassUtil {

/**
 * 手动上传class文件实时更新jvm内存中的字节码文件
 * @param classFile newClassFile
 * @param classPath com.xxx.xxx.xxx
 * @return success/fail
 */
@PostMapping("/reloadClass")
public Result<String> reloadClass(List<MultipartFile> classFiles, String classPath) {
    log.info("reloadClass start, classPath:{}", classPath);
    if (!permission) return new Result<>(ResultCodeEnum.UNAUTHORIZED);
    return reTransformClass(classFiles, classPath);
}

private Result<String> reTransformClass(List<MultipartFile> files, String path){
    try {
        Map<String, String> fileByteMap = new HashMap<>();
        for (MultipartFile file : files) {
            String className = path + "." + file.getOriginalFilename().replace(".class", "");
            reTransform(file.getBytes(), className);
            fileByteMap.put(className, Base64Utils.encodeBase64String(file.getBytes()));
        }
        syncOthersClient(fileByteMap);
        return new Result<>(ResultCodeEnum.SUCCESS);
    } catch (Exception e) {
        log.error("reloadClass exception", e);
        return new Result<>(ResultCodeEnum.INTERNAL_SERVER_ERROR, e.getMessage());
    }
}

/**
 * 重载class
 * @param fileBytes 字节码文件
 * @param classPath 目标包+类名
 */
public static boolean reTransform(byte[] fileBytes, String classPath) throws Exception{
    inst = inst != null ? inst : ByteBuddyAgent.install();
    String targetClass = classPath.replace(".", "/");
    inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) ->
            className.equals(targetClass) ? fileBytes : classfileBuffer, true);
    inst.retransformClasses(Class.forName(classPath));
    return true;
}

/**
 * 同步class文件给集群内其他服务器
 */
private void syncOthersClient(Map<String, String> fileByteMap){
    StringBuilder sb = new StringBuilder();
    fileByteMap.forEach((k,v) -> {
        sb.append(k).append(",");
        redisTemplate.opsForValue().set(k, v, cacheSecond, TimeUnit.SECONDS);
    });
    ReloadClassDto body = ReloadClassDto.builder().classPath(sb.substring(0, sb.length()-1)).build();
    mq.sendMsg(body);
}

@Value("${reload.cacheSecond:60}")
private long cacheSecond;

@Value("${reload.permission:false}")
private boolean permission;

private static Instrumentation inst;

@Resource
private RedisTemplate<String, String> redisTemplate;

}

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6月前
|
监控 Java Maven
使用AspectJ实现Java代码的运行时织入
使用AspectJ实现Java代码的运行时织入
|
7月前
|
Java 编译器 Maven
Java一分钟之-AspectJ:AOP库
【6月更文挑战第13天】AspectJ是Java的AOP框架,扩展了语言并提供编译时和加载时织入,便于模块化横切关注点。关键概念包括编织、切面、切点和通知。常见问题涉及编译时织入配置、切点表达式误用、异常处理和版本兼容性。通过正确配置构建工具、精准设计切点、妥善处理异常和确保版本兼容,可避免这些问题。文中还提供了一个记录服务层方法执行时间的代码示例,帮助读者快速上手AspectJ。
244 2
|
Java uml Kotlin
Spring框架源码分析之Spring源码编译
Spring框架源码分析之Spring源码编译
232 1
|
XML 开发框架 Java
spring框架,以及和spring框架相关的Java面试题和spring ioc的注入方式
spring框架,以及和spring框架相关的Java面试题和spring ioc的注入方式
107 0
|
XML Java 数据库连接
【Spring学习笔记 五】Spring注解及Java类配置开发
【Spring学习笔记 五】Spring注解及Java类配置开发
106 0
|
Java Spring
java202304java学习笔记第六十天-ssm-spring配置文件-spring加载properties文件1
java202304java学习笔记第六十天-ssm-spring配置文件-spring加载properties文件1
63 0
|
Java
java热部署
热部署【devtools】 改完代码不需要重启,等待系统反应一两秒就可以
168 0
java热部署
|
Java 网络架构
Java-SpringBoot-05-使用@Value注解注入单个应用程序参数
SpringBoot中可以使用使用@Value注解注入单个应用程序参数,很方便的在业务类中使用。
222 0
Java-SpringBoot-05-使用@Value注解注入单个应用程序参数
Java:Springboot 实现热部署的两种方式
Java:Springboot 实现热部署的两种方式
126 0
Java:Springboot 实现热部署的两种方式
|
XML 设计模式 前端开发
Java笔记:SpringBoot热部署与热加载
Java笔记:SpringBoot热部署与热加载
765 0