1. 介绍
1.1 简介
JVM-SANDBOX(沙箱)实现了一种在不重启、不侵入目标JVM应用的AOP解决方案。Sandbox仅仅是提供一个无侵入的入口,至于将Sandbox作用于何处,是需要额外去定义的,例如Sandbox-Repeater就是集成Sandbox使用的流量回放框架(坑)。
1.2 特性
无侵入
:目标应用无需重启也无需感知沙箱的存在类隔离
:沙箱以及沙箱的模块不会和目标应用的类相互干扰可插拔
:沙箱以及沙箱的模块可以随时加载和卸载,不会在目标应用留下痕迹多租户
:目标应用可以同时挂载不同租户下的沙箱并独立控制高兼容
:支持JDK[6,11]
1.3 原理
1.3.1 Java agent介绍
(1)什么是Java agent
java agent本质上可以理解为一个插件,该插件就是一个精心提供的jar包,这个jar包通过JVMTI(JVM Tool Interface)完成加载,最终借助JPLISAgent(Java Programming Language Instrumentation Services Agent)完成对目标代码的修改。
(2)功能
-
可以在加载java文件之前做拦截把字节码做修改
-
可以在运行期将已经加载的类的字节码做变更
-
还有其他的一些小众的功能
-
获取所有已经被加载过的类
-
获取所有已经被初始化过了的类
-
获取某个对象的大小
-
将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载
-
将某个jar加入到classpath里供AppClassloard去加载
-
设置某些native方法的前缀,主要在查找native方法的时候做规则匹配
-
(3) 实现agent启动方法
Java Agent支持目标JVM启动时加载,也支持在目标JVM运行时加载,这两种不同的加载模式会使用不同的入口函数,如果需要在目标JVM启动的同时加载Agent,那么可以选择实现下面的方法:
[1] public static void premain(String agentArgs, Instrumentation inst);
[2] public static void premain(String agentArgs);
JVM将首先寻找[1],如果没有发现[1],再寻找[2]。如果希望在目标JVM运行时加载Agent,则需要实现下面的方法:
[1] public static void agentmain(String agentArgs, Instrumentation inst);
[2] public static void agentmain(String agentArgs);
(4)指定Main-Class
<build>
<finalName>xxx-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>attached</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestEntries>
<Premain-Class>com.alibaba.jvm.sandbox.agent.AgentLauncher</Premain-Class>
<Agent-Class>com.alibaba.jvm.sandbox.agent.AgentLauncher</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
(5)agent加载
-
启动时加载
-
启动参数增加-javaagent:[path],其中path为对应的agent的jar包路径
-
-
运行中加载
-
使用com.sun.tools.attach.VirtualMachine加载
-
try {
String jvmPid = 目标进行的pid;
logger.info("Attaching to target JVM with PID: " + jvmPid);
VirtualMachine jvm = VirtualMachine.attach(jvmPid);
jvm.loadAgent(agentFilePath);//agentFilePath为agent的路径
jvm.detach();
logger.info("Attached to target JVM and loaded Java agent successfully");
} catch (Exception e) {
throw new RuntimeException(e);
}
1.4 Sandbox和Arthas
TBD
2. 源码
3. FAQ
3.1 jar-with-dependencies