曹工说Spring Boot源码(25)-- Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解 (5)

但是,这是有问题的。因为,这段代码,最终aop切面会被插入到target:

public class HelloXunChe { private String methodName = "abc"; public static void main(String[] args) throws InterruptedException { HelloXunChe helloXunChe = new HelloXunChe(); helloXunChe.sayHi(); } public void sayHi() throws InterruptedException { System.out.println("hi, xunche"); sleep(); } public void sleep() throws InterruptedException { Thread.sleep((long) (Math.random() * 200)); } }

我实话跟你说,这个target类里,压根访问不到org/xunche/agent/TimeAgentByJava$TimeAdviceAdapter类的methodName字段。

我是怎么发现这个问题的,之前一直报错,直到我在target后来加了这么一行:

public class HelloXunChe { private String methodName = "abc"; ... }

哎,没个大佬带我,真的难。

当然,我是通过这个确认了上述问题,最终解决的思路呢,就是:把你生成的class,反编译出来看看,看看是不是你想要的。

所以,我专门写了个main测试类,来测试改后的class是否符合预期。

public class SaveGeneratedClassWithOriginAgentTest { public static void main(String[] args) throws IOException { //1 ClassReader reader = new ClassReader("org.xunche.app.HelloXunChe"); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); reader.accept(new TimeAgentByJava.TimeClassVisitor(writer), ClassReader.EXPAND_FRAMES); byte[] bytes = writer.toByteArray(); // 2 File file = new File( "F:\\ownprojects\\all-simple-demo-in-work\\java-agent-premain-demo\\test-agent\\src\\main\\java\\org\\xunche\\app\\HelloXunCheCopy2.class"); FileOutputStream fos = new FileOutputStream(file); fos.write(bytes); fos.close(); } }

1处这段代码,就是模拟在classTransformer中的那段。

2处,将最终要返回给jvm的那段class字节码,写到一个文件里,然后我们就可以反编译,看看有问题没。

所以,上面那段asm,大家如果看:

初探 Java agent

会发现,访问methodname那句代码,是这么写的:

mv.visitLdcInsn(methodName);

这就是,相当于直接把methodName写死到最终的class里去了;最终的class就会是想要的样子:

public void sayHi() throws InterruptedException { //1 TimeHolder.start(this.getClass().getName() + "." + "sayHi"); System.out.println("hi, xunche"); this.sleep(); // 2 String var1 = this.getClass().getName() + "." + "sayHi"; System.out.println(var1 + ": " + TimeHolder.cost(var1)); }

1/2处,直接把sayHi写死到target了,而不是此时再去访问field。

maven插件配置premain-class

插件中,配置Premain-Class

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.3.1</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Premain-Class> org.xunche.agent.TimeAgent </Premain-Class> </manifestEntries> </archive> </configuration> </plugin> 测试模块开发

测试模块,没啥开发的,就只有那个target那个类。

运行

最终我是这么运行的:

java -javaagent:agent.jar -classpath lib/*;java-agent-premain-demo.jar org/xunche/app/He lloXunChe

这里指定了lib目录,主要是agent模块需要的jar包:

曹工说Spring Boot源码(25)-- Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解

简单的运行效果如下:

loaded class: org/xunche/app/HelloXunChe methodName = 0 <init> methodName = 0 main methodName = 0 sayHi methodName = 0 sleep hi, xunche org.xunche.app.HelloXunChe.abc: 129 org.xunche.app.HelloXunChe.abc: 129 总结

ASM这个东西,想要不熟悉字节码就去像我上面这样傻瓜操作,坑还是比较多的,比较难趟。回头有空再介绍字节码吧。我也是半桶水,大家一起学习吧。
本节源码:
https://gitee.com/ckl111/all-simple-demo-in-work/tree/master/java-agent-premain-demo

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzfzd.html