Java view code generated by dynamic proxy

https://www.cnblogs.com/ctgulong/p/5011614.html

1. Create an agent that exports the generated class

Agent is used to deal with a jvm. It needs to implement a static public static void premain(String agentArgs, Instrumentation inst) method I use the following code to create an agent

package ctgu.jagent;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class CustomAgent implements ClassFileTransformer {
 
	public static void premain(String agentArgs, Instrumentation inst) {
		inst.addTransformer(new CustomAgent());
	}

	@Override
	public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
			ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
		if (!className.startsWith("java") && !className.startsWith("sun")) {
			// It doesn't start with java or sun
			// Export code
			int lastIndexOf = className.lastIndexOf("/") + 1;
			String fileName = className.substring(lastIndexOf) + ".class";
			exportClazzToFile("E:/javaeeworkspace/bytecode/exported/", fileName, classfileBuffer);
			System.out.println(className + " --> EXPORTED Succeess!");
		}    
		return classfileBuffer;
	}

	/**
	 * 
	 * @param dirPath
	 *Directory ends with / and must exist
	 * @param fileName
	 * @param data
	 */
	private void exportClazzToFile(String dirPath, String fileName, byte[] data) {
		try {
			File file = new File(dirPath + fileName);
			if (!file.exists()) {
				file.createNewFile();    
			}    
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(data);
			fos.close();    
		} catch (Exception e) {
			System.out.println("exception occured while doing some file operation");
			e.printStackTrace();
		}
	}
}

Then use the export function of eclipse to export the jar (note that the agent must exist in the form of jar), and use the specified manifest. XML in the wizard MF file, manifest The contents of MF file are as follows

Manifest-Version: 1.0
Premain-Class: ctgu.jagent.CustomAgent

Note that this premain class is a class with premain static methods.
If you use maven, you can also use the following plugin

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-jar-plugin</artifactId>
	<configuration>
		<archive>
			<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
		</archive>
	</configuration>
</plugin>

Replace the manifestFile with the user-defined manifestFile MF path, and then mvn package.

The exported jar package is assumed to be jagent jar

2. Use jagent jar

Put jagent Put jar under the project and add jvm parameters when running

-javaagent:jagent.jar

Note: there is no space on the left and right. If the jvm prompt cannot be found, you can use eclispe to put jagent Add jar to buildpath.

3. Use dynamic proxy

3.0 interface and implementation of original target

The interface is defined as follows:

package ctgu.bytecode.proxy.service;

public interface HelloService {
 public String sayHello(String name) ;
}

The implementation is as follows:

package ctgu.bytecode.proxy.service.impl;    
import ctgu.bytecode.proxy.service.HelloService;    
public class HelloServiceImpl implements HelloService{    
	@Override
	public String sayHello(String name) {
		return "Hello "+name;
	}    	
}

3.1 agents using jdk

private static void javaDynamicProxy() {
	HelloService helloService=new HelloServiceImpl();
	MyInvocationHandler handler=new MyInvocationHandler(helloService);
	
	HelloService proxy = (HelloService)Proxy.newProxyInstance(HelloService.class.getClassLoader(), 
			new Class<?>[]{HelloService.class}, handler);
	
	
	String sayHello = proxy.sayHello("woober");
	
	System.out.println(sayHello);
}

The code of MyInvocationHandler is as follows:

package ctgu.bytecode.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

	Object trueTarget;
	
	public MyInvocationHandler(Object target) {
		this.trueTarget=target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("before invoke method:"+method.getName());
		Object result = method.invoke(trueTarget, args);
		System.out.println("invoke finish return:"+result);
		return result;
	}

}

Output after operation:

ctgu/bytecode/TestMain --> EXPORTED Succeess!    
ctgu/bytecode/proxy/service/impl/HelloServiceImpl --> EXPORTED Succeess!
ctgu/bytecode/proxy/service/HelloService --> EXPORTED Succeess!
ctgu/bytecode/proxy/MyInvocationHandler --> EXPORTED Succeess!
com/sun/proxy/$Proxy0 --> EXPORTED Succeess!
before invoke method:sayHello
invoke finish return:Hello woober
Hello woober

In part 4, we will analyze the decompiled code that generates com/sun/proxy/$Proxy0.

3.2 using cglib proxy

private static void cgLibProxy(){		
	HelloService helloService=new HelloServiceImpl();
	MyMethodIntercepter intercepter=new MyMethodIntercepter(helloService);		 
	HelloService proxy = (HelloService)Enhancer.create(HelloService.class,intercepter);
	System.err.println("Proxy class name is "+proxy.getClass().getName());
	System.out.println(proxy.sayHello("Woober"));
}

The code of mymethodinterceptor is as follows:

package ctgu.bytecode.proxy;

import java.lang.reflect.Method;    
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyMethodIntercepter  implements MethodInterceptor{

	Object trueTarget;
	
	public MyMethodIntercepter(Object target) {
		 trueTarget=target;
	}
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("In cglib before invoke");
		//This methodProxy is a proxy of the target method, which can be seen below    		 
		 Object result = proxy.invoke(trueTarget, args);
		System.out.println("In cglib after invoke");
		return result;
	}
}

Run output:

ctgu/bytecode/TestMain --> EXPORTED Succeess!
net/sf/cglib/proxy/Callback --> EXPORTED Succeess!
ctgu/bytecode/proxy/service/impl/HelloServiceImpl --> EXPORTED Succeess!
ctgu/bytecode/proxy/service/HelloService --> EXPORTED Succeess!
ctgu/bytecode/proxy/MyMethodIntercepter --> EXPORTED Succeess!
net/sf/cglib/proxy/MethodInterceptor --> EXPORTED Succeess!
net/sf/cglib/proxy/Enhancer --> EXPORTED Succeess!
Omit a lot in the middle cglib Other classes asm Class of.....  

ctgu/bytecode/proxy/service/HelloService$$EnhancerByCGLIB$$1af19a1d --> EXPORTED Succeess!

net/sf/cglib/proxy/MethodProxy --> EXPORTED Succeess!
net/sf/cglib/proxy/MethodProxy$CreateInfo --> EXPORTED Succeess!

In cglib before invoke

Proxy class name is ctgu.bytecode.proxy.service.HelloService$$EnhancerByCGLIB$$1af19a1d

Omit a lot cglib Class of...

ctgu/bytecode/proxy/service/HelloService$$FastClassByCGLIB$$c2826506 --> EXPORTED Succeess!

ctgu/bytecode/proxy/service/HelloService$$EnhancerByCGLIB$$1af19a1d$$FastClassByCGLIB$$a45a31f6 --> EXPORTED Succeess!

In cglib after invoke

Hello Woober

Pay attention to the order of these two sentences

In cglib before invoke
Proxy class name is ctgu.bytecode.proxy.service.HelloService$$EnhancerByCGLIB$$1af19a1d

It is reasonable to say that the back should be in the back, and this sentence should be in the front, because I use system The sentence Proxy class name is typed by err is not the same stream as out, so it is in the wrong order (because err will be marked red in eclipse, which is more beautiful...)

Focus on the following bytecode. proxy. service. HelloService E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB1af19a1d this class

4. View the source code of the generated class

Find a handy decompiler. I use Bytecode Viewer and GitHub address https://github.com/Konloch/bytecode-viewer

4.1 JDK dynamic agent Decompilation

/*
 * Decompiled with CFR 0_110.
 * 
 * Could not load the following classes:
 *  com.sun.proxy.$Proxy0
 *  ctgu.bytecode.proxy.service.HelloService
 */
package com.sun.proxy;

import ctgu.bytecode.proxy.service.HelloService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements HelloService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke((Object)this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException v0) {
            throw v0;
        }
        catch (Throwable var2_2) {
            throw new UndeclaredThrowableException(var2_2);
        }
    }

    public final String sayHello(String string) {
        try {
            return (String)this.h.invoke((Object)this, m3, new Object[]{string});
        }
        catch (Error | RuntimeException v0) {
            throw v0;
        }
        catch (Throwable var2_2) {
            throw new UndeclaredThrowableException(var2_2);
        }
    }

    public final String toString() {
        try {
            return (String)this.h.invoke((Object)this, m2, null);
        }
        catch (Error | RuntimeException v0) {
            throw v0;
        }
        catch (Throwable var1_1) {
            throw new UndeclaredThrowableException(var1_1);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke((Object)this, m0, null);
        }
        catch (Error | RuntimeException v0) {
            throw v0;
        }
        catch (Throwable var1_1) {
            throw new UndeclaredThrowableException(var1_1);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("ctgu.bytecode.proxy.service.HelloService").getMethod("sayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException var1) {
            throw new NoSuchMethodError(var1.getMessage());
        }
        catch (ClassNotFoundException var1_1) {
            throw new NoClassDefFoundError(var1_1.getMessage());
        }
    }
}

It can be seen that he implements the HelloService interface and the sayHello method. When actually calling, the invocationHandler is used and m3 is passed in. m3 is actually the sayHello method in the interface obtained by reflection.

m3 = Class.forName("ctgu.bytecode.proxy.service.HelloService").getMethod("sayHello", Class.forName("java.lang.String"));

4.2 CGLIB dynamic agent Decompilation

package ctgu.bytecode.proxy.service;

import java.lang.reflect.*;
import net.sf.cglib.proxy.*;
import net.sf.cglib.core.*;

public class HelloService$$EnhancerByCGLIB$$1af19a1d implements HelloService, Factory
{
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$finalize$0$Method;
    private static final MethodProxy CGLIB$finalize$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;
    private static final Method CGLIB$sayHello$5$Method;
    private static final MethodProxy CGLIB$sayHello$5$Proxy;
    
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        final Class<?> forName = Class.forName("ctgu.bytecode.proxy.service.HelloService$$EnhancerByCGLIB$$1af19a1d");
        final Class<?> forName2;
        final Method[] methods = ReflectUtils.findMethods(new String[] { "finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (forName2 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$finalize$0$Method = methods[0];
        CGLIB$finalize$0$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()V", "finalize", "CGLIB$finalize$0");
        CGLIB$equals$1$Method = methods[1];
        CGLIB$equals$1$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = methods[2];
        CGLIB$toString$2$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = methods[3];
        CGLIB$hashCode$3$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = methods[4];
        CGLIB$clone$4$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        final Class<?> forName3;
        CGLIB$sayHello$5$Method = ReflectUtils.findMethods(new String[] { "sayHello", "(Ljava/lang/String;)Ljava/lang/String;" }, (forName3 = Class.forName("ctgu.bytecode.proxy.service.HelloService")).getDeclaredMethods())[0];
        CGLIB$sayHello$5$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "(Ljava/lang/String;)Ljava/lang/String;", "sayHello", "CGLIB$sayHello$5");
    }
    
    final void CGLIB$finalize$0() throws Throwable {
        super.finalize();
    }
    
    protected final void finalize() throws Throwable {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$finalize$0$Method, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$emptyArgs, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$finalize$0$Proxy);
            return;
        }
        super.finalize();
    }
    
    final boolean CGLIB$equals$1(final Object o) {
        return super.equals(o);
    }
    
    public final boolean equals(final Object o) {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            final Object intercept = cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$equals$1$Method, new Object[] { o }, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$equals$1$Proxy);
            return intercept != null && (boolean)intercept;
        }
        return super.equals(o);
    }
    
    final String CGLIB$toString$2() {
        return super.toString();
    }
    
    public final String toString() {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            return (String)cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$toString$2$Method, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$emptyArgs, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$toString$2$Proxy);
        }
        return super.toString();
    }
    
    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }
    
    public final int hashCode() {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            final Object intercept = cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$hashCode$3$Method, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$emptyArgs, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$hashCode$3$Proxy);
            return (intercept == null) ? 0 : ((Number)intercept).intValue();
        }
        return super.hashCode();
    }
    
    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }
    
    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            return cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$clone$4$Method, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$emptyArgs, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$clone$4$Proxy);
        }
        return super.clone();
    }
    
    final String CGLIB$sayHello$5(final String s) {
        return super.sayHello(s);
    }
    
    public final String sayHello(final String s) {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            return (String)cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Method, new Object[] { s }, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Proxy);
        }
        return super.sayHello(s);
    }
    
    public static MethodProxy CGLIB$findMethodProxy(final Signature signature) {
        final String string = signature.toString();
        switch (string.hashCode()) {
            case -1816210712: {
                if (string.equals("sayHello(Ljava/lang/String;)Ljava/lang/String;")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Proxy;
                }
                break;
            }
            case -1574182249: {
                if (string.equals("finalize()V")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$finalize$0$Proxy;
                }
                break;
            }
            case -508378822: {
                if (string.equals("clone()Ljava/lang/Object;")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$clone$4$Proxy;
                }
                break;
            }
            case 1826985398: {
                if (string.equals("equals(Ljava/lang/Object;)Z")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$equals$1$Proxy;
                }
                break;
            }
            case 1913648695: {
                if (string.equals("toString()Ljava/lang/String;")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$toString$2$Proxy;
                }
                break;
            }
            case 1984935277: {
                if (string.equals("hashCode()I")) {
                    return HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$hashCode$3$Proxy;
                }
                break;
            }
        }
        return null;
    }
    
    public HelloService$$EnhancerByCGLIB$$1af19a1d() {
        CGLIB$BIND_CALLBACKS(this);
    }
    
    public static void CGLIB$SET_THREAD_CALLBACKS(final Callback[] array) {
        HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$THREAD_CALLBACKS.set(array);
    }
    
    public static void CGLIB$SET_STATIC_CALLBACKS(final Callback[] cglib$STATIC_CALLBACKS) {
        CGLIB$STATIC_CALLBACKS = cglib$STATIC_CALLBACKS;
    }
    
    private static final void CGLIB$BIND_CALLBACKS(final Object o) {
        final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = (HelloService$$EnhancerByCGLIB$$1af19a1d)o;
        if (!helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$BOUND) {
            helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$BOUND = true;
            Object o2;
            if ((o2 = HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$THREAD_CALLBACKS.get()) != null || (o2 = HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$STATIC_CALLBACKS) != null) {
                helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])o2)[0];
            }
        }
    }
    
    public Object newInstance(final Callback[] array) {
        CGLIB$SET_THREAD_CALLBACKS(array);
        final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = new HelloService$$EnhancerByCGLIB$$1af19a1d();
        CGLIB$SET_THREAD_CALLBACKS(null);
        return helloService$$EnhancerByCGLIB$$1af19a1d;
    }
    
    public Object newInstance(final Callback callback) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[] { callback });
        final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = new HelloService$$EnhancerByCGLIB$$1af19a1d();
        CGLIB$SET_THREAD_CALLBACKS(null);
        return helloService$$EnhancerByCGLIB$$1af19a1d;
    }
    
    public Object newInstance(final Class[] array, final Object[] array2, final Callback[] array3) {
        CGLIB$SET_THREAD_CALLBACKS(array3);
        switch (array.length) {
            case 0: {
                final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = new HelloService$$EnhancerByCGLIB$$1af19a1d();
                CGLIB$SET_THREAD_CALLBACKS(null);
                return helloService$$EnhancerByCGLIB$$1af19a1d;
            }
            default: {
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    }
    
    public Callback getCallback(final int n) {
        CGLIB$BIND_CALLBACKS(this);
        Object cglib$CALLBACK_0 = null;
        switch (n) {
            case 0: {
                cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0;
                break;
            }
            default: {
                cglib$CALLBACK_0 = null;
                break;
            }
        }
        return (Callback)cglib$CALLBACK_0;
    }
    
    public void setCallback(final int n, final Callback callback) {
        switch (n) {
            case 0: {
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
                break;
            }
        }
    }
    
    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[] { this.CGLIB$CALLBACK_0 };
    }
    
    public void setCallbacks(final Callback[] array) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)array[0];
    }
    
    static {
        CGLIB$STATICHOOK1();
    }
}
The generated class also implements HelloService Interface and implemented Factory Interface, Factory The interfaces are as follows:

public interface Factory {
    
    Object newInstance(Callback callback);	    
     
    Object newInstance(Callback[] callbacks);	
    
    Object newInstance(Class[] types, Object[] args, Callback[] callbacks);	
   
    Callback getCallback(int index);
 
    void setCallback(int index, Callback callback);	
    
    void setCallbacks(Callback[] callbacks);	
     
    Callback[] getCallbacks();
}

Look directly at the generated sayHello implementation

  public final String sayHello(final String s) {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            return (String)cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Method, new Object[] { s }, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Proxy);
        }
        return super.sayHello(s);
    }

You can see cglib C A L L B A C K 0 yes through too C G L I B CALLBACK_0 is through CGLIB CALLBACK0 , is through CGLIBBIND_CALLBACKS(this) completed, glib C A L L B A C K 2 Follow g l i b CALLBACK_2 with glib CALLBACK2 and glibCALLBACK_2 is a thing.

See cglib $bind again_ What did callbacks (this) do

private static final void CGLIB$BIND_CALLBACKS(final Object o) {
    final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = (HelloService$$EnhancerByCGLIB$$1af19a1d)o;
    if (!helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$BOUND) {
        helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$BOUND = true;
        Object o2;
        if ((o2 = HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$THREAD_CALLBACKS.get()) != null || (o2 = HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$STATIC_CALLBACKS) != null) {
            helloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])o2)[0];
        }
    }
}

CGLIB C A L L B A C K 0 yes C G L I B CALLBACK_0 is CGLIB CALLBACK0 # is CGLIBTHREAD_CALLBACKS.get() or CGLIB S T A T I C C A L L B A C K S , C G L I B STATIC_CALLBACKS, CGLIB STATICC​ALLBACKS,CGLIBTHREAD_CALLBACKS is a member variable of threadlocal.

CGLIB T H R E A D C A L L B A C K S yes from lower noodles of C G L I B THREAD_CALLBACKS are generated by the following CGLIB THREADC ALLBACKS is composed of the following CGLIBSET_THREAD_CALLBACKS method,

public static void CGLIB$SET_THREAD_CALLBACKS(final Callback[] array) {
    HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$THREAD_CALLBACKS.set(array);
}

This method is called by the newInstance of the Factory interface

public Object newInstance(final Callback[] array) {
    CGLIB$SET_THREAD_CALLBACKS(array);
    final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = new HelloService$$EnhancerByCGLIB$$1af19a1d();
    CGLIB$SET_THREAD_CALLBACKS(null);
    return helloService$$EnhancerByCGLIB$$1af19a1d;
}

public Object newInstance(final Callback callback) {
    CGLIB$SET_THREAD_CALLBACKS(new Callback[] { callback });
    final HelloService$$EnhancerByCGLIB$$1af19a1d helloService$$EnhancerByCGLIB$$1af19a1d = new HelloService$$EnhancerByCGLIB$$1af19a1d();
    CGLIB$SET_THREAD_CALLBACKS(null);
    return helloService$$EnhancerByCGLIB$$1af19a1d;
}

What I don't understand is why he CGLIB S E T T H R E A D C A L L B A C K S ( a r r a y ) ; of after also C G L I B SET_THREAD_CALLBACKS(array); Then CGLIB SETT​HREADC​ALLBACKS(array); Then CGLIBSET_THREAD_CALLBACKS(null); ??? Decompilation problem?

For CGLIB$STATIC_CALLBACKS are created by

public static void CGLIB$SET_STATIC_CALLBACKS(final Callback[] cglib$STATIC_CALLBACKS) {
    CGLIB$STATIC_CALLBACKS = cglib$STATIC_CALLBACKS;
}

This method is on assignment, but I can't find the place to call.

The last place to look at the method actually executed is the intercept method of the missing interceptor.

(String)cglib$CALLBACK_2.intercept((Object)this, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Method, new Object[] { s }, HelloService$$EnhancerByCGLIB$$1af19a1d.CGLIB$sayHello$5$Proxy);

The last parameter is a MethodProxy

 CGLIB$sayHello$5$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "(Ljava/lang/String;)Ljava/lang/String;", "sayHello", "CGLIB$sayHello$5");

I guess a proxy was generated for the method

final String CGLIB$sayHello$5(final String s) {
    return super.sayHello(s);
}

Many decompilers cannot parse the bytecode generated by cglib. The correctness of the code generated above is not guaranteed

Keywords: Java Design Pattern Back-end

Added by frog_ on Wed, 09 Feb 2022 20:14:11 +0200