详解Java中的字节码增强技术

作者:深色風信子 时间:2022-08-20 06:25:12 

1.字节码增强技术

字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。

参考地址

2.常见技术

技术分类类型
静态增强AspectJ
动态增强ASM、Javassist、Cglib、Java Proxy

详解Java中的字节码增强技术

3.ASM

<dependency>
   <groupId>org.ow2.asm</groupId>
   <artifactId>asm</artifactId>
   <version>9.4</version>
</dependency>

ASM Core API可以类比解析XML文件中的SAX方式,不需要把这个类的整个结构读取进来,就可以用流式的方法来处理字节码文件。好处是非常节约内存,但是编程难度较大。然而出于性能考虑,一般情况下编程都使用Core API。在Core API中有以下几个关键类:

技术分类类型
ClassReader用于读取已经编译好的.class文件。
ClassWriter用于重新构建编译后的类,如修改类名、属性以及方法,也可以生成新的类的字节码文件。
Visitor类如上所述,CoreAPI根据字节码从上到下依次处理,对于字节码文件中不同的区域有不同的Visitor,比如用于访问方法的MethodVisitor、用于访问类变量的FieldVisitor、用于访问注解的AnnotationVisitor等。为了实现AOP,重点要使用的是MethodVisitor。

3.1 测试 Main

package com.xu.test;

/**
* @author Administrator
*/
public class Main {

public void print() {
       System.out.println("ASM");
   }

}

3.2 测试 CustomerClassVisitor

package com.xu.test;

import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
* ASM 字节码增强技术
*
* @author Administrator
*/
public class CustomerClassVisitor extends ClassVisitor implements Opcodes {

public CustomerClassVisitor(ClassVisitor api) {
       super(ASM9, api);
   }

@Override
   public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
       cv.visit(version, access, name, signature, superName, interfaces);
   }

@Override
   public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
       MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
       if (StringUtils.equals("print", name) && mv != null) {
           mv = new CustomerMethodVisitor(mv);
       }
       return mv;
   }

class CustomerMethodVisitor extends MethodVisitor implements Opcodes {
       public CustomerMethodVisitor(MethodVisitor api) {
           super(ASM9, api);
       }

@Override
       public void visitCode() {
           super.visitCode();
           mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
           mv.visitLdcInsn("start");
           mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
       }

@Override
       public void visitInsn(int opcode) {
           if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
               mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
               mv.visitLdcInsn("end");
               mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
           }
           mv.visitInsn(opcode);
       }
   }

}

3.3 测试 Test

package com.xu.test;

import java.io.File;
import java.io.FileOutputStream;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;

/**
* @author Administrator
*/
public class Test {

public static void main(String[] args) throws Exception {
       ClassReader reader = new ClassReader("com/xu/test/Main");
       ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
       // 处理
       ClassVisitor visitor = new CustomerClassVisitor(writer);
       reader.accept(visitor, ClassReader.SKIP_DEBUG);
       // 输出
       File file = new File("target\\classes\\com\\xu\\test\\Main.class");
       FileOutputStream stream = new FileOutputStream(file);
       stream.write(writer.toByteArray());
       stream.close();
       // 测试
       Class<?> cls = Class.forName("com.xu.test.Main");
       Main main = (Main) cls.getDeclaredConstructor().newInstance();
       main.print();
   }

}

来源:https://blog.csdn.net/qq_34814092/article/details/127243802

标签:Java,字节码,增强
0
投稿

猜你喜欢

  • Java调用.dll文件的方法

    2023-11-23 21:16:22
  • Maven install 报错"程序包不存在"问题的解决方法

    2021-05-27 06:08:06
  • 详解SpringMVC中的异常处理

    2022-10-22 07:05:14
  • c#简单工厂、工厂方法与抽象工厂的区别分析

    2021-11-30 04:39:47
  • IDEA使用SequenceDiagram插件绘制时序图的方法

    2023-07-03 11:20:07
  • Jmeter如何添加循环控制器

    2021-06-26 20:09:52
  • c#多线程程序设计实例方法

    2023-07-24 16:39:28
  • Springboot文件上传功能的实现

    2021-09-20 12:48:47
  • 详解App保活技术实现

    2023-05-24 18:06:26
  • 深入探讨Java多线程中的volatile变量

    2023-08-31 02:32:18
  • C#基础入门之值类型和引用类型的区别详析

    2022-02-22 00:14:04
  • 聊聊MultipartFile与File的一些事儿

    2023-06-27 03:07:00
  • SuperSocket入门--Telnet服务器和客户端请求处理

    2021-07-24 19:35:14
  • C#中ManualResetEvent用法总结

    2023-01-21 23:41:41
  • C#中的位操作小结

    2023-08-07 07:01:29
  • Java判断两个日期相差天数的方法

    2021-11-29 05:55:07
  • c#中多线程间的同步示例详解

    2022-07-05 00:24:56
  • java定义数组的三种类型总结

    2022-06-27 01:44:44
  • JAVA 根据设置的概率生成随机数的方法

    2023-07-15 00:13:37
  • Spring容器-BeanFactory和ApplicationContext使用详解

    2022-03-20 07:02:45
  • asp之家 软件编程 m.aspxhome.com