SandBox中的JavaAgent技术

2024-03-03 11:52
文章标签 java 技术 agent sandbox

本文主要是介绍SandBox中的JavaAgent技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

8.1 JavaAgent

Java Agent 是一种强大的技术,在运行时动态修改已加载类的字节码,为应用程序注入额外的功能和行为。

JDK 1.5 支持静态 Instrumentation,基本的思路是在 JVM 启动的时候添加一个代理(javaagent),每个代理是一个 jar 包,其 MANIFEST.MF 文件里指定了代理类,这个代理类包含一个 premain 方法。JVM 在类加载时候会先执行代理类的 premain 方法,再执行 Java 程序本身的 main 方法,这就是 premain 名字的来源。在 premain 方法中可以对加载前的 class 文件进行修改。

8.1.1 应用场景:

代码注入:通过 Java Agent 技术,我们可以在运行时将自定义的字节码注入到已加载的类中。这样可以实现 AOP 编程思想,将通用的逻辑代码动态地注入到目标类中,简化代码的编写和维护。

性能监控:Java Agent 可以用于实时监控应用程序的性能指标,如方法的执行时间、方法的调用次数等。通过在方法的前后插入字节码,我们可以收集这些信息,并进行实时监控、统计和分析,帮助优化和调优应用程序的性能。

调试工具:Java Agent 可以用作调试工具的基础。我们可以通过动态修改字节码,将额外的调试信息插入到目标类中,例如打印方法的参数、返回值等。这样,在调试过程中可以更加方便地获取和分析这些信息,帮助快速定位问题。

安全检查:Java Agent 还可以用于实现安全检查机制。通过对正在加载的类进行拦截和检查,我们可以在运行时进行代码审计、防止恶意代码注入等,提高应用程序的安全性。

8.1.2 启动方式

启动挂载(Agent):

所有的类在加载时都会执行transform,我们在此方法中通过 Instrumentation 增强目标类。

随着JVM启动一起启动(java -javaagent:(jar包名) (方法类名))

premain(): 实现premain方法,并且添加一个自定义transformer,把操作放在自定义的transformer内,该transformer要实现ClassFileTransformer.transform() 主程序运行时:加载每个类前都会进入transform(),可以获取到它的加载器、类名、字节码buffer等

动态挂载(Attach):

动态挂载之后,类加载时都会执行transform,我们在此方法中通过 Instrumentation 增强目标类。

动态挂载前 已经加载的类,都未经历增强的处理。 可通过调用retransformClasses方法,让已加载的类重新加载, 重新加载时也会执行transform,我们在此方法中增强目标类。

在已经运行的JVM进程中,动态的插入。通过attach API调用,在sandbox中执行./sandbox -p pid(目标 jvm 进程 id)是使用的 attach api 方式进行 agent 的挂载

agentmain():对于agentmain也是一样的流程,但多一步inst.retransformClasses()的操作让JVM重新加载修改过的类的字节码,否则修改不会生效 使用com.sun.tools.attach.VirtualMachine进行动态挂载Agent:

 
private void attachAgentToTargetJVM() throws Exception {List<VirtualMachineDescriptor> virtualMachineDescriptors = VirtualMachine.list();VirtualMachineDescriptor targetVM = null;for (VirtualMachineDescriptor descriptor : virtualMachineDescriptors) {if (descriptor.id().equals(configure.getPid())) {targetVM = descriptor;break;}}if (targetVM == null) {throw new IllegalArgumentException("could not find the target jvm by process id:" + configure.getPid());}VirtualMachine virtualMachine = null;try {virtualMachine = VirtualMachine.attach(targetVM);virtualMachine.loadAgent("{agent}", "{params}");} catch (Exception e) {if (virtualMachine != null) {virtualMachine.detach();}}}

它的 addTransformer 给 Instrumentation 注册一个 transformer,transformer 是 ClassFileTransformer 接口的实例,这个接口就只有一个 transform 方法,调用 addTransformer 设置 transformer 以后,后续JVM 加载所有类之前都会被这个 transform 方法拦截,这个方法接收原类文件的字节数组,返回转换过的字节数组,在这个方法中可以做任意的类文件改写。

8.1.3 JavaAgent使用demo

使用premain的方式进行javaAgent的启动(不详细展示对java类的增强demo)

首先在一个maven项目中创建我们的核心demo-AgentDemo

 
package com.xhz.demo;import java.lang.instrument.Instrumentation;/*** @version V1.0* @Author : xiehuizhi* @create 2023/12/20 14:33*/public class AgentDemo {public static void premain(String agentArgs, Instrumentation instrumentation){System.out.println(agentArgs+"============尊贵的xxxx===============");}public static void premain(String agentArgs){System.out.println(agentArgs+"============尊贵的xxxx================");}}

创建完成之后可以手动在resources中创建MANIFEST.MF文件(也可以在pom中配置)

 

Manifest-Version: 1.0

Premain-Class: com.xhz.demo.AgentDemo

Can-Redefine-Classes: true

Can-Retransform-Classes: true

 

pom配置:

 
<plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.1.2</version><configuration><archive><manifestEntries><Premain-Class>club.throwable.permain.PermainAgent</Premain-Class><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes></manifestEntries></archive></configuration></plugin></plugins>

然后要实现agent的功能,需要将你的项目打成jar包

打包命令:mvn clean package

然后新建一个可以启动的Main类

 
package Utils;/*** @version V1.0* @Author : xiehuizhi* @create 2023/12/20 14:29*/public class Main {public static void main(String[] args) {System.out.println("流量回放");}}

 

在springboot启动项增加启动参数

8.2 Sandbox启动与Agent挂载的流程

sandbox-spy:这个包里的代码是一系列的模板代码,后期Sandbox会通过ASM框架将这些代码转化成字节码增加到业务代码的字节码当中,实现对业务代码的增强功能

但spy类为什么要被BootstrapClassLoader加载呢?我们不仅要增强业务代码,也要增强JDK里面的代码,将spy添加到BootstrapClassLoader的类路径,只要不破坏双亲委托机制,都能够被spy类增强,这是一种比较保险的做法。

8.3 JVM-SandBox实现字节码增强

一般的Spring AOP:实现业务切面,针对于JAVA后端应用也需要AOP

JVM-Sandbox的设计目的是实现一种在不重启、不侵入目标JVM应用情况下的AOP解决方案。

Jvm-SandBox字节码增强流程梳理:

8.3.1 增强过程

8.3.2 实现字节码增强逻辑

通过AsmMethods接口获取Sandbox自定义Spy类完成字节码增强

spy增强的静态方法

JavaAgent的本质就是字节码增强,这章主要介绍了Sandbox字节码增强功能的核心逻辑,包括增强逻辑、SandboxClassFileTransformer类形变器、Spy增强的静态方法。

这篇关于SandBox中的JavaAgent技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/769532

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏