A Brief Introduction to Bytecode Enhancement Technology Series 1

0 18
Author: Dong ZilongPrefaceIn the recent period, I have been thinking of writing...

Author: Dong Zilong

Preface

In the recent period, I have been thinking of writing a patent for a plugin that can generate business document modification records based on the implementation principle of lombok. During the process of reviewing materials, I accidentally learned about the bytecode enhancement tool - byteBuddy. However, due to the tight schedule at that time, I did not delve into the understanding of this component. In fact, the身影 of bytecode enhancement components is everywhere in our daily development, such as spring-aop and mybatis. Adhering to the spirit of knowing not only the what but also the why, I decided to sink my heart into a thorough study and summary of bytecode enhancement technology. This article serves as the opening of this series, mainly for a simple introduction to bytecode, laying a good foundation for our subsequent in-depth study.

1. Brief introduction to bytecode

A Brief Introduction to Bytecode Enhancement Technology Series 1

Bytecode is a binary file in an intermediate state, which is compiled from source code and has lower readability than source code. The CPU cannot directly read bytecode, and in Java, bytecode needs to be translated into machine code by JVM before the CPU can read and run it.

The benefits of using bytecode: compile once, run anywhere. Java is a typical example of using bytecode as an intermediate language, where the source code is compiled once, and the .class file can be run on various computers.

2. Use scenarios of bytecode enhancement

If we do not want to modify the source code but want to add new features and make the program run as expected, we can do the corresponding operations during the compilation process and loading process. Simply put, it is: modify or replace the generated .class file with the target .class file we need.

Since bytecode enhancement can implant code logic without侵入 business code at all, it can be used to do some cool things, such as the following common scenarios:

1. Dynamic proxy

2. Hot deployment

3. Call chain tracking埋点

4. Dynamic insertion of log (performance monitoring)

5. Test code coverage tracking

...

3. Implementation methods of bytecode enhancement

Bytecode tools Class creationImplement interfaceMethod callClass extensionParent class method callAdvantagesDisadvantagesCommon usageLearning cost
java-proxySupportsSupportsSupportsDoes not supportDoes not support Preferred for simple dynamic proxyLimited in function, does not support expansionspring-aop, MyBatis 1 star
asmSupportsSupportsSupportsSupportsSupportsCan insert arbitrary bytecode, almost unrestrictedHigh learning difficulty, more code writingcglib5 stars
javaassitSupportsSupportsSupportsSupportsSupportsJava original syntax, string insertion in string form, writing is intuitiveDoes not support syntax above JDK1.5, such as generics, enhanced for Fastjson, MyBatis2 stars
cglibSupportsSupportsSupportsSupportsSupportsLooks similar to bytebuddyIs being phased out by bytebuddy EasyMock, jackson-databind3 stars
bytebuddySupportsSupportsSupportsSupportsSupportsSupports interception of any dimension, can obtain the original class, method, as well as proxy class and all parametersNot very intuitive, with some cost in learning and understanding, with a very large number of APIsSkyWalking, Mockito, Hibernate, powermock3 stars

4. Simple Example

AOP is an architectural design idea commonly used in our daily development, AOP'sThe main implementations include cglib, Aspectj, Javassist, java proxy, and others. Next, we will take the logging before and after method execution, which we often encounter in our daily development, as a starting point to manually implement AOP using bytecode.

Define the target interface and implementation

public class SayService{
   public void say(String str) {
      System.out.println("hello" + str); 
   }
 }

Define the class SayService, before executing the say method, we will printWhen the method starts to execute start, after the method is executed, we will print the end of method execution

ASM implements AOP

4.1.1, Introduction of jar package
<dependency>    
    <groupId>org.ow2.asm</groupId>    
    <artifactId>asm</artifactId>   
    <version>9.1</version>
</dependency>
4.1.2, Specific implementation of AOP
public class ResourceClassVisitor extends ClassVisitor implements Opcodes {

    public ResourceClassVisitor(ClassVisitor cv) {
        super(Opcodes.ASM4, cv);
    }

    public ResourceClassVisitor(int i, ClassVisitor classVisitor) {
        super(i, classVisitor);
    }

    /**Access class basic information*/
    @Override
    public void visit(int version, int access, String name,
                      String signature, String superName, String[] interfaces) {
        this.cv.visit(version, access, name, signature, superName, interfaces);
    }

    /**Access method basic information*/
    @Override
    public MethodVisitor visitMethod(int access, String name,
                                     String desc, String signature, String[] exceptions) {
        MethodVisitor mv = this.cv.visitMethod(access, name, desc,
                signature, exceptions);
        //假如不是构造方法,我们构建方法的访问对象(MethodVisitor)
        if (!name.equals("<init>") && mv != null) {
            mv = new ResourceClassVisitor.MyMethodVisitor((MethodVisitor)mv);
        }

        return (MethodVisitor)mv;
    }

    /**自定义方法访问对象*/
    class MyMethodVisitor extends MethodVisitor implements Opcodes {

        public MyMethodVisitor(MethodVisitor mv) {
            super(Opcodes.ASM4, mv);
        }
        /**此方法会在方法执行之前执行*/
        @Override
        public void visitCode() {
            super.visitCode();
            this.mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out",
                    "Ljava/io/PrintStream;");
            this.mv.visitLdcInsn("方法开始执行start");
            this.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream",
                    "println", "(Ljava/lang/String;)V", false);
        }
        /**对应方法体本身*/
        @Override
        public void visitInsn(int opcode) {
            //在方法return或异常之前,添加一个end输出
            if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
                this.mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out",
                        "Ljava/io/PrintStream;");
                this.mv.visitLdcInsn("方法执行结束end");
                this.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream",
                        "println", "(Ljava/lang/String;)V", false);
            }
            this.mv.visitInsn(opcode);
        }
    }
}
public class AopTest {

    public static void main(String[] args) throws IOException {
        //First step: Build the ClassReader object to read the specified class file (default is classpath)
        ClassReader classReader = new ClassReader("com/aop/SayService");
        //Second step: Build the ClassWriter object, based on which a new class file is created
        //ClassWriter.COMPUTE_FRAMES indicates that ASM will automatically calculate max stacks, max locals, and the specific content of stack map frames.
        //ClassWriter.COMPUTE_MAXS indicates that ASM will automatically calculate max stacks and max locals, but will not automatically calculate stack map frames.
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); //Recommended to use COMPUTE_FRAMES
        //Third step: Build the ClassVisitor object, which is used to receive data from the ClassReader objectand pass the processed data to the ClassWriter object
        ClassVisitor classVisitor = new ResourceClassVisitor(classWriter);
        //Fourth step: Read class information based on ClassReader and pass the data to the ClassVisitor object
        //The parameter ClassReader.SKIP_DEBUG here indicates skipping some debugging information, etc., making the ASM code look simpler
        //The parameter ClassReader.SKIP_FRAMES here indicates skipping some part of stack frame information in certain methods, as manual calculation of stack frames is very complex, so let the system handle it
        //Recommended parameters
        classReader.accept(classVisitor, ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
        //Fifth step: Obtain data from ClassWriter and write it to a class file
        byte[] data = classWriter.toByteArray();
        //Write bytecode into the disk's class file
        File f = new File("target/classes/com/aop/SayService.class");
        FileOutputStream fout = new FileOutputStream(f);
        fout.write(data);
        fout.close();
        SayService rs = new SayService();
        rs.say("asm");//start,handle(),end
    }
}
4.1.3 Test class output results


Javassist implements AOP

4.2.1 Introduction of jar package
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.28.0-GA</version>
</dependency>
4.2.2 Specific implementation of AOP
public class AopTest {

    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("com.aop.SayService");
        CtMethod personFly = cc.getDeclaredMethod("say");
        personFly.insertBefore("System.out.println("\"Method execution starts start\")");
        personFly.insertAfter("System.out.println("\"Method execution ends end\")");
        cc.toClass();
        SayService sayService = new SayService();
        sayService.say("assist");
    }
}
4.2.3 Test class output results


5. Summary

As the opening article of the series on bytecode enhancement, it simply introduces the definition and implementation methods of bytecode, and finally demonstrates how to enhance bytecode through specific examples. In subsequent articles, a detailed summary of the principles and specific applications of related frameworks will be provided, and I welcome all experts to criticize and correct me.

你可能想看:

d) Adopt identification technologies such as passwords, password technologies, biometric technologies, and combinations of two or more to identify users, and at least one identification technology sho

Announcement regarding the addition of 7 units as technical support units for the Ministry of Industry and Information Technology's mobile Internet APP product security vulnerability database

Distributed Storage Technology (Part 2): Analysis of the architecture, principles, characteristics, and advantages and disadvantages of wide-column storage and full-text search engines

Interpretation of Meicreate Technology's 'Security Protection Requirements for Key Information Infrastructure' (Part 1)

How to implement cloud workload protection in the production network? A practice sharing from ByteDance

Data security can be said to be a hot topic in recent years, especially with the rapid development of information security technologies such as big data and artificial intelligence, the situation of d

Deception defense for advanced threat detection: enhance security orchestration, automation, and response capabilities

a hidden injection shellcode technology and defense method under Linux

Article 2 of the Cryptography Law clearly defines the term 'cryptography', which does not include commonly known terms such as 'bank card password', 'login password', as well as facial recognition, fi

Google Android 11 Beta version officially released, Baidu Security fortification technology first fully compatible

最后修改时间:
admin
上一篇 2025年03月26日 13:22
下一篇 2025年03月26日 13:45

评论已关闭