Preface

Bytecode We all know java file compiled after the class file, each byte code file consists of 10 sections have a fixed order; in fact, enhance the transformation of bytecode files to generate a new file has been To achieve our purpose, such as dynamic proxy, AOP etc.; of course, it needs to be used after the enhancement, so it involves the problem of loading; before the introduction, let's take a look at what bytecode enhancement technologies are available.

Common technology

Common bytecode enhancement techniques are roughly divided into two categories: static enhancement and dynamic enhancement; the most common static enhancement is AspectJ , which can be directly compiled and has its own syntax; dynamic enhancement includes: ASM , Javassist , Cglib , Java Proxy ; A brief introduction is given below.

AspectJ

AspectJ from Eclipse foundations are woven into a static, compile-time is mainly used in weaving, used during this AspectJ the acj compiler (similar javac ) the aspect class compiled into class bytecode; following look AspectJ how in use;

  • Download and install
    AspectJ official website address: https://www.eclipse.org/aspectj/
    Directly download the latest version: AspectJ 1.9.6 ; directly run the following command to install:

    java -jar aspectj-1.9.6.jar

Specify the installation directory, and then configure classPath and path :

ASPECTJ_HOME=E:\aspectj1.9
CLASSPATH=...%ASPECTJ_HOME%\lib\aspectjrt.jar
PATH=...%ASPECTJ_HOME%\bin
  • Compile and use
    You can directly use AspectJ provided by Demo to test under the examples\tjp
    There are two java files, which are Demo.java and GetInfo.java . Demo is our normal java file, and GetInfo is an enhanced file. There are some AspectJ grammars that need to be ajc command.

    E:\aspectj1.9\doc\examples\tjp>ajc -argfile files.lst
    E:\aspectj1.9\doc\examples\tjp>cd ..
    E:\aspectj1.9\doc\examples>java tjp.Demo
    Intercepted message: foo
    in class: tjp.Demo
    Arguments:
      0. i : int = 1
      1. o : java.lang.Object = tjp.Demo@6e3c1e69
    Running original method:
    
    Demo.foo(1, tjp.Demo@6e3c1e69)
    
      result: null
    Intercepted message: bar
    in class: tjp.Demo
    Arguments:
      0. j : java.lang.Integer = 3
    Running original method:
    
    Demo.bar(3)
    
      result: Demo.bar(3)
    Demo.bar(3)

It can be found that the new class file compiled by ajc, the two methods of go and bar have been enhanced, log output has been added before and after the method call, and the method parameters; it can be found that AspectJ has already done the class file before running Enhanced processing; Spring AOP borrows AspectJ , but does not use AspectJ in its implementation but uses dynamic enhancement technology;

ASM

ASM is a general Java bytecode manipulation and analysis framework, which can be used to modify existing classes or directly generate classes in binary form; ASM provides some common bytecode conversion and analysis algorithms from which you can build customizations Complex conversion and code analysis tools; several core classes:

  • ClassVisitor: for generating and converting compiled classes ASM API based ClassVisitor abstract class, each class corresponding to the methods of the same name as the file structure;
  • ClassReader: The main function of this type is to read bytecode files, and then notify ClassVisitor the read data;
  • ClassWriter: It inherits from ClassVisitor and is mainly used to generate classes;

ASM partial low-level bytecode operation, all need to be familiar with bytecode commands, but high performance; for example, FastJson, Cglib, Lombok, etc. all rely on ASM; the general operation steps are to first load the original Class file, and then pass the visitor mode Access all elements, transform each element in the process of access, and finally regenerate a bytecode binary file, and load a new Class or reload according to requirements;

More references: ASM Introduction

Javassist

Just because ASM needs to be familiar with bytecode commands, and the bytecode itself is more obscure, so there is an easier to understand enhancement tool Javassist , which can be directly coded in Java without knowing the relevant bytecode commands. It is more friendly to developers, of course, the performance is definitely not as good as ASM . Let's take a look at a few common classes:

  • ClassPool: It can be simply understood as the pool for storing classes, all CtClass must be obtained from the pool;
  • CtClass pair can be obtained by the fully qualified name of a class;
  • CtMethod: The method in the corresponding class, the specified method CtClass
  • CtField: Corresponding to the attribute in the class, you can get the specified attribute CtClass

Combine the above core classes to see a simple log enhancement example:

public class JavassistTest {
    public static void main(String[] args) throws Exception {
        //增强后的类信息存放路径
        CtClass.debugDump = "./dump";
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("com.zh.asm.TestService");
        CtMethod m = cc.getDeclaredMethod("query");
        m.insertBefore("{ System.out.println(\"start\"); }");
        m.insertAfter("{ System.out.println(\"end\"); }");
        TestService h = (TestService) c.newInstance();
        h.query();
    }
}

Dubbo uses Javassist to do dynamic compilation processing, JBoss uses Javassist to do AOP processing, etc.;

More: http://www.javassist.org/tutorial/tutorial.html

Cglib

Cglib is a powerful and high-performance code generation package. The bottom layer depends on ASM ; it provides a good supplement JDK Java does not support the situation without interfaces. In addition, Cglib is more powerful; several cores The classes are as follows:

  • Enhancer: Cglib of the most commonly used classes in Proxy , which is similar to the 060d3e732820cf class introduced in the dynamic proxy. The difference is that Enhancer can not only proxy the ordinary class , but also proxy interfaces;
  • MethodInterceptor: interceptors, when you call the target method, CGLib calls back MethodInterceptor interface methods to intercept, to realize your own proxy logic, similar to JDK in InvocationHandler interfaces;
public class CgLibProxy {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:/asm/cglib");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TestService.class);
        enhancer.setCallback(new MyMethodInterceptor());
        TestService testService = (TestService)enhancer.create();
        testService.query();
    }
}

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("增强处理");
        Object object = proxy.invokeSuper(obj, args);
        return object;
    }
}

Cglib will dynamically generate a proxy class. When it is actually executed, it is actually the proxy class. The original class is called in the proxy class to achieve functional enhancements;

Java Proxy

The reflection mechanism is used to create proxy classes at runtime; the interface and the proxy class remain unchanged, and a handler class is constructed to implement the InvocationHandler interface; the core classes are as follows:

  • Proxy: Specify a ClassLoader object and a group of interface to create a dynamic proxy class;
  • InvocationHandler: Create your own invocation handler, that is, enhance processing;
public class MyHandler implements InvocationHandler{
    private Object object;
    public MyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke...");
        method.invoke(object, args);
        System.out.println("After invoke...");
        return null;
    }
}

Obtained by reflection dynamic proxy class constructor, the dynamic proxy class instance created by the constructor; and Cglib inside bottom dependence ASM , stronger than using reflective properties; FastJson in use is ASM instead of using reflection, Spring AOP implementations are Use Cglib to achieve.

Loading problem

The above is a brief introduction to various bytecode enhancement technologies. Regardless of the enhancement technology, the class information after the enhancement needs to be loaded. According to the different enhancement technologies used, and the role of the enhancement, the class loading used The method is also different, and the following situations are roughly summarized;

Static compilation

This situation is described above AspectJ technology, before running on to class do enhancement processing, so there is no difference between loading and loading a normal class, during the run may not know class file has been enhanced; this This way of class loading is the simplest;

Dynamic proxy

This method uses dynamic enhancement technology to create a proxy class. The proxy class has its own unique name. The proxy class implements the interface class or inherits from the original class. In fact, a new class is generated, which is also mentioned ASM Two functions: generation class and conversion class; FastJson is also ASM in the generation class function of 060d3e73287547; so in this case, only one class loading is required; ASM does not provide class loading, but several other dynamic enhancement technologies are provided Class loading function;

Hot update

This situation is the most complicated. If the class that needs to be enhanced has been loaded into the memory, how to reload the class after the bytecode is enhanced; instrument is a class library provided by the JVM that can modify the loaded classes, specifically for Java Instrumentation services written in the language provide support; before JDK 1.6, instrument can only take effect when the JVM just starts to load classes, but after JDK 1.6, instrument supports the modification of class definitions at runtime; specific use needs to provide one ClassFileTransformer implementation class implements the transform method. This method returns a byte array, which can be generated using the bytecode enhancement tool introduced above;

Using Instrumentation , developers can build an application-independent agent program ( Agent ) to monitor and assist JVM , and can even replace and modify certain class definitions. With this function, developers can implement more flexible runtime virtual machine monitoring and Java class operations. This feature actually provides a virtual machine-level support for AOP implementation, so that developers do not need to control JDK Do any upgrades and changes, you can realize some of the functions of AOP

instrument introduced above relies on JPDA : Java platform debugging framework ( Java Platform Debugger Architecture ), which is a set of interfaces specially provided by the Java virtual machine for debugging and monitoring virtual machines; JPDA composed of three specifications: JVMTI(JVM Tool Interface) , JDWP(Java Debug Wire Protocol) , JDI(Java Debug Interface) ;

More: https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/

to sum up

This article briefly introduces some commonly used bytecode enhancement technologies. It is the support of these underlying technologies that help us greatly improve the efficiency of development during the development process. For example, lombok、aop etc.; improve performance, such as FastJson、ReflectASM etc.; cooperate with Java Agent for hot update and many more.

Thanks for attention

You can follow the WeChat public "160d3e7328779d roll back code ", read it as soon as possible, the article is continuously updated; focus on Java source code, architecture, algorithm and interview.

ksfzhaohui
398 声望70 粉丝