线上调试工具 jvm-sandbox使用
jvm-sandbox使用
1 快速安装
-
1.1 下载解压
# 下载最新版本的JVM-SANDBOX wget http://ompc.oss-cn-hangzhou.aliyuncs.com/jvm-sandbox/release/sandbox-stable-bin.zip # 解压 unzip sandbox-stable-bin.zip
-
1.2 挂载目标应用
# 进入沙箱执行脚本 cd sandbox/bin # 常用命令!!! # 目标JVM进程73366(假设,使用jps命令查看) ./sandbox.sh -p 73366 #卸载沙箱 ./sandbox.sh -p 73366 -S #查询沙箱 ./sandbox.sh -p 73366 -l #刷新沙箱 ./sandbox.sh -p 73366 -F #使用自定义module执行(my-sandbox-module:自定义的module名字,addLog自定义切入方法名字) ./sandbox.sh -p 73366 -d 'my-sandbox-module/addLog' #日志配置及查看 #配置文件在 /sandbox/cfg/sandbox-logback.xml #默认日志路径 ~/logs/sandbox/sandbox.log
2 快速使用demo
本例采用maven多工程模式:(注意自己的父子结构引用)
-
主pom.xml(参考)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!--springboot start--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <!-- 去除对默认日志的依赖 --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!--log start--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <!--springAop--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--log end--> <!--springboot end--> </dependencies>
-
springboot-sandbox工程pom.xml
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
-
module-sandbox工程pom.xml
<dependencies> <dependency> <groupId>com.alibaba.jvm.sandbox</groupId> <artifactId>sandbox-api</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.kohsuke.metainf-services</groupId> <artifactId>metainf-services</artifactId> <version>1.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <archive> <manifest> <!-- <mainClass>com.sandbox.test.MySandBoxModule</mainClass>--> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <!-- 此处指定继承合并 --> <phase>package</phase> <!-- 绑定到打包阶段 --> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
2.1 springboot-sandbox代码
-
启动类SandboxApp
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SandboxApp { public static void main(String[] args) { SpringApplication.run(SandboxApp.class, args); } }
-
需要被挂载切入方法的类TestSandbox
import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import java.util.concurrent.atomic.LongAdder; @Slf4j @Component public class TestSandbox implements ApplicationRunner { private final LongAdder longAdder = new LongAdder(); @Override public void run(ApplicationArguments args) throws Exception { while (true) { longAdder.add(1); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } test(longAdder); } } private void test(LongAdder longAdder) { log.info("TestSandBox------->" + longAdder); } }
-
打包上传服务器使用java -jar 启动
2.2 module-sandbox代码
-
切入方法类MySandBoxModule
import com.alibaba.jvm.sandbox.api.Information; import com.alibaba.jvm.sandbox.api.Module; import com.alibaba.jvm.sandbox.api.annotation.Command; import com.alibaba.jvm.sandbox.api.listener.ext.Advice; import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; import lombok.extern.slf4j.Slf4j; import org.kohsuke.MetaInfServices; import javax.annotation.Resource; @MetaInfServices(Module.class) @Information(id = "my-sandbox-module")// 模块名,在指定挂载进程后通过-d指定模块,配合@Command注解来唯一确定方法 @Slf4j public class MySandBoxModule implements Module { @Resource private ModuleEventWatcher moduleEventWatcher; @Command("addLog")// 模块命令名 public void addLog() { new EventWatchBuilder(moduleEventWatcher) .onClass("com.sandbox.test.TestSandbox")// 想要对 TestSandbox 这个类进行切面 .onBehavior("test")// 想要对上面类的 bathSave 方法进行切面 .onWatch(new AdviceListener() { //对方法执行之前执行 @Override protected void before(Advice advice) throws Throwable { log.info("sandbox切入成功!!!!!!"); //获取方法的所有参数 Object[] parameterArray = advice.getParameterArray(); if (parameterArray != null) { for (Object po : parameterArray) { log.info("形参类型为:" + po.getClass().getName() + "!!!!!!!"); log.info("形参值为:" + po + "!!!!!!!"); } } } }); } }
-
使用 mvn clean compile assembly:single打包,上传至sandbox/sandbox-module目录下
2.3 使用命令挂载使用
参考: https://github.com/alibaba/jvm-sandbox
参考项目: https://github.com/70416450/jvm-sandbox