Bytecode Programming | Dynamically Generate Hello World with Javassist

Hello everyone, I'm Glacier~~

Bytecode programming is not commonly used in actual business development (CRUD), but with the continuous development and heavy use of network programming, RPC, dynamic bytecode enhancement techniques and automated testing, and zero-intrusive APM monitoring, more and more technology requires the use of bytecode programming.

Well, we will use Javassist to dynamically generate a HelloWorld case today. The relevant program case code can be obtained from the public account: Glacier Technology , or directly from Github and Gitee.

Github:https://github.com/binghe001/bytecode

Gitee:https://gitee.com/binghe001/bytecode

development environment

  • JDK 1.8
  • IDEA 2018.03
  • Maven 3.6.0

Maven dependencies

Add the following environment dependencies to the project's pom.xml file.

<properties>
    <javassist.version>3.20.0-GA</javassist.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>${javassist.version}</version>
    </dependency>
</dependencies>

Case effect

The overall case effect is actually very simple. When learning the Java language, we will print the first Hello World program on the command line. Today, when we learn Javassist bytecode programming, we also implement a HelloWorld program.

The effect of the case is to generate the following program code.

package io.binghe.bytecode.javassist.test;

public class HelloWorld {
    
    
    public static void main(String[] var0) {
    
    
        System.out.println("Javassist Hello World by 冰河(公众号:冰河技术)");
    }

    public HelloWorld() {
    
    
    }
}

Look at this effect, does it look like the Java code we wrote in IDEA? Let's use Javassist to achieve it.

Case realization

This case is actually quite simple, and the source code is given directly here.

/**
 * @author binghe (公众号:冰河技术)
 * @version 1.0.0
 * @description 测试使用Javassist生成第一个类HelloWorld
 */
public class GenerateHelloWorldClass {
    
    

    /**
     * 创建HelloWorld的类,并返回HelloWorld的Class实例
     */
    public static Class createHelloWorld()throws Exception{
    
    
        //使用默认的ClassPool
        ClassPool pool = ClassPool.getDefault();
        //创建一个空类
        CtClass ctClass = pool.makeClass("io.binghe.bytecode.javassist.test.HelloWorld");
        //添加一个main方法
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "main", new CtClass[]{
    
    pool.get(String[].class.getName())}, ctClass);
        //将main方法声明为public static类型
        ctMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
        //设置方法体
        ctMethod.setBody("{" +
                "System.out.println(\"Javassist Hello World by 冰河(公众号:冰河技术)\");" +
                "}");
        ctClass.addMethod(ctMethod);

        //将生成的类的class文件输出的磁盘
        ctClass.writeFile();

        //返回HelloWorld的Class实例
        return ctClass.toClass();

    }

    public static void main(String[] args) throws Exception {
    
    
        Class clazz = createHelloWorld();
        Object obj = clazz.newInstance();
        Method mainMethod = clazz.getMethod("main", new Class[]{
    
    String[].class});
        mainMethod.invoke(obj, new String[1]);
    }
}

Next, let's see how Javassist generates complete bytecode based on the above code.

(1) Create a ClassPool in the createHelloWorld() method, which is essentially a CtClass object container.

(2) Call the makeClass() method of ClassPool, pass in the complete package name + class name to generate an empty class information. The full package name + class name passed in here is io.binghe.bytecode.javassist.test.HelloWorld.

(3) Add a method to the class, and set the method's return type, method name, parameter name (input and output parameters), access modifiers, and method body. The full method body set here is as follows:

public static void main(String[] var0) {
    
    
    System.out.println("Javassist Hello World by 冰河(公众号:冰河技术)");
}

(4) Although we did not show the creation of a parameterless constructor in the above code, at compile time, Javassist will automatically create a parameterless constructor of the HelloWorld class.

(5) The class information in the memory is output to the disk through the writeFile() method of CtClass, so that we can clearly see the HelloWorld class generated by Javassist through IDEA.

(6) Finally, the toClass() method of CtClass is called in the createHelloWorld() method to return the Class object.

(7) Call the createHelloWorld() method in the main() method to obtain the Class object.

(8) Instantiate the object through reflection, and call the main() method of the generated HelloWorld class through reflection.

Effect demonstration

Running the main() method of the GenerateHelloWorldClass class will io/binghe/bytecode/javassist/testgenerate the HelloWorld.class file in the directory under the top-level project directory, as shown below.

picture

When viewing the output information of IDEA, it is found that the following content will be output.

Javassist Hello World by 冰河(公众号:冰河技术)

Process finished with exit code 0

Summary

We used Javassist to implement the function of creating a HelloWorld class. Bytecode programming sounds difficult, but under the powerful API of Javassist, it is quite simple to implement.

In the next period of time, Glacier will continue to output articles about bytecode programming, let us master bytecode programming together.

Okay, let's stop here today, I'm Glacier, see you next time~~

write at the end

If you want to enter a big factory, want to get a promotion and a salary increase, or are confused about your current job, you can privately message me to communicate, I hope some of my experiences can help you~~

Recommended reading:

Okay, let's stop here today, friends, like, favorite, comment, and start walking with one click, I'm Glacier, see you in the next issue~~

Guess you like

Origin blog.csdn.net/l1028386804/article/details/123865457