ASM Learning Series (2)

Series Article Directory

ASM Learning Series (1)



foreword

The previous article introduced some basic operations in ASM. The theme of this article is to introduce the design patterns used in ASM. After understanding the content of this article, I believe you will have some new understanding of ASM. and understand.


1. Visitor mode

The design pattern used in the ASM library is the visitor pattern . The main purpose of this pattern is to separate the data from the operation on the data. In simple terms, there is a separate data operation object for different data. Using this design pattern, multiple if-else uses can be avoided for data type judgment. His UML class diagram can be described as:

![Insert picture description here](https://img-blog.csdnimg.cn/31b847cdfcdf41c88c6fddce5ca5f5b6.png
As can be seen from the above figure, we can rewrite different visit methods in the real visitor (AVisitor) for different data types, and call different methods according to different parameter types, which saves the need to pass if -else is the process of type judgment. The data can be read by accept in the data class and the visitor can use the visitor to operate the data in the class. The above process can be represented by the following code: first create an interface Data
:

public interface Data {
    
    
    void accept(Visitor visitor);
}

There are two Data implementation classes, AData and BData:

public class AData implements Data{
    
    
    int a1 = 100;
    int a2 = 200;
    int a3 = 300;

    @Override
    public void accept(Visitor visitor) {
    
    
        visitor.visit(this);
    }
}
public class BData implements Data {
    
    
    int b1 = 100;
    int b2 = 200;
    int b3 = 300;

    public void accept(Visitor visitor) {
    
    
        visitor.visit(this);
    }
}

A collection of data, also contains a method to read data:

public class DataStruct {
    
    
    AData aData = new AData();
    BData bData = new BData();

    void readData(Visitor visitor) {
    
    
        aData.accept(visitor);
        bData.accept(visitor);
    }
}

The above are the classes related to data, and the following are classes related to data manipulation:

public interface Visitor {
    
    
    void visit(AData data);
    void visit(BData data);
}

The implementation class AVisitor of the data visitor:

public class AVisitor implements Visitor {
    
    
    @Override
    public void visit(AData data) {
    
    
        System.out.println("a1: " + data.a1 + " a2: " + data.a2 + " a3: " + data.a3);
    }

    @Override
    public void visit(BData data) {
    
    
        System.out.println("b1: " + data.b1 + " b2: " + data.b2 + " b3: " + data.b3);
    }
}

Then we create a client, as follows:

public class Client {
    
    
    public static void main(String[] args) {
    
    
        DataStruct data = new DataStruct();
        data.readData(new AVisitor());
    }
}

Finally, you can get the printout:

a1: 100 a2: 200 a3: 300
b1: 100 b2: 200 b3: 300

It can be seen that by operating data in this way, the decoupling of data and data operation objects can be realized.

Two, ASM instance analysis

In ASM, we will see the following code:

ClassPrinter cp = new ClassPrinter();	//ClassVisitor的实现类
ClassReader cr = new ClassReader("java.lang.Boolean");
cr.accept(cp, 0);

Among them, ClassPrinter is an implementation class of ClassVisitor, as follows:

class ClassPrinter extends ClassVisitor {
    
    
    public ClassPrinter() {
    
    
        super(ASM4);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    
    
        super.visit(version, access, name, signature, superName, interfaces);
        System.out.println(name + " extends " + superName + "{");
    }

    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
    
    
        System.out.println(" " + descriptor + " " + name);
        return super.visitField(access, name, descriptor, signature, value);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
    
    
        System.out.println(" " + name + descriptor);
        return super.visitMethod(access, name, descriptor, signature, exceptions);
    }

    @Override
    public void visitEnd() {
    
    
        super.visitEnd();
        System.out.println("}");
    }
}

This corresponds to the Visitor and AVisitor in the first section. ClassReader is a data class, corresponding to Data, you can call its accept method to use Visitor to access data.
In addition, a very interesting place in ASM is that multiple ClassVisitors can be combined for use. Here he also puts a ClassVisitor object in the member variable of each ClassVisitor. That is to say, when constructing data, you can use the access logic of ClassVisitor in the member variable. Of course, on this basis, you can also add your own logic. For example, in the ASM learning series (1), remove or When adding variables, the function of accessing data of the class TraceClassVisitor is also used.

Summarize

The above is the content of this article. This article mainly introduces the design pattern used by ASM. After understanding the pattern, it can be of great help to understand the architecture of ASM and use ASM.

Guess you like

Origin blog.csdn.net/qq_42788340/article/details/125892974
ASM