[Java] ASM proxy mode Byte-Buddy proxy mode Javassist proxy mode

Insert picture description here

1 Overview

Reprint: Add link description

ASM proxy method

public class ASMProxy extends ClassLoader {
    
    

    public static <T> T getProxy(Class clazz) throws Exception {
    
    

        ClassReader classReader = new ClassReader(clazz.getName());
        ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);

        classReader.accept(new ClassVisitor(ASM5, classWriter) {
    
    
            @Override
            public MethodVisitor visitMethod(int access, final String name, String descriptor, String signature, String[] exceptions) {
    
    

                // 方法过滤
                if (!"queryUserInfo".equals(name))
                    return super.visitMethod(access, name, descriptor, signature, exceptions);

                final MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);

                return new AdviceAdapter(ASM5, methodVisitor, access, name, descriptor) {
    
    

                    @Override
                    protected void onMethodEnter() {
    
    
                        // 执行指令;获取静态属性
                        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                        // 加载常量 load constant
                        methodVisitor.visitLdcInsn(name + " 你被代理了,By ASM!");
                        // 调用方法
                        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
                        super.onMethodEnter();
                    }
                };
            }
        }, ClassReader.EXPAND_FRAMES);

        byte[] bytes = classWriter.toByteArray();

        return (T) new ASMProxy().defineClass(clazz.getName(), bytes, 0, bytes.length).newInstance();
    }

}

@Test
public void test_ASMProxy() throws Exception {
    
    
    IUserApi userApi = ASMProxy.getProxy(UserApi.class);
    String invoke = userApi.queryUserInfo();
    logger.info("测试结果:{}", invoke);
}

/**
 * 测试结果:
 * 
 * queryUserInfo 你被代理了,By ASM!
 * 20:12:26.791 [main] INFO  org.itstack.interview.test.ApiTest - 测试结果:小傅哥,公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获!
 *
 * Process finished with exit code 0
 */

Index: ⭐⭐⭐⭐⭐Scenario
: full link monitoring, cracking toolkit, CGLIB, Spring to obtain class metadata, etc.
Comments: This kind of proxy uses bytecode programming for processing, and its implementation is relatively complicated, and Need to understand the relevant knowledge of the Java virtual machine specification. Because every step of your proxy operation is operating bytecode instructions, such as Opcodes.GETSTATIC, Opcodes.INVOKEVIRTUAL, in addition to these there are 200 commonly used instructions. But this approach that is closest to the bottom layer is also the fastest way. Therefore, it is very common in some full-link monitoring that uses bytecode instrumentation.

4. Byte-Buddy proxy mode

public class ByteBuddyProxy {
    
    

    public static <T> T getProxy(Class clazz) throws Exception {
    
    

        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(clazz)
                .method(ElementMatchers.<MethodDescription>named("queryUserInfo"))
                .intercept(MethodDelegation.to(InvocationHandler.class))
                .make();

        return (T) dynamicType.load(Thread.currentThread().getContextClassLoader()).getLoaded().newInstance();
    }

}

@RuntimeType
public static Object intercept(@Origin Method method, @AllArguments Object[] args, @SuperCall Callable<?> callable) throws Exception {
    
    
    System.out.println(method.getName() + " 你被代理了,By Byte-Buddy!");
    return callable.call();
}

@Test
public void test_ByteBuddyProxy() throws Exception {
    
    
    IUserApi userApi = ByteBuddyProxy.getProxy(UserApi.class);
    String invoke = userApi.queryUserInfo();
    logger.info("测试结果:{}", invoke);
}

/**
 * 测试结果:
 * 
 * queryUserInfo 你被代理了,By Byte-Buddy!
 * 20:19:44.498 [main] INFO  org.itstack.interview.test.ApiTest - 测试结果:小傅哥,公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获!
 *
 * Process finished with exit code 0
 */

Index: ⭐⭐⭐⭐Scenario
: AOP aspects, class agents, components, monitoring, logs
Comment: Byte Buddy is also a class library for bytecode manipulation, but Byte Buddy is easier to use. Without understanding bytecode instructions, you can use simple API to easily manipulate bytecode, control classes and methods. Compared with JDK dynamic proxy and cglib, Byte Buddy has certain advantages in performance. In addition, in October 2015, Byte Buddy was awarded the Duke's Choice Award by Oracle. The award commends Byte Buddy for his "great innovation in Java technology".

5. Javassist proxy mode

public class JavassistProxy extends ClassLoader {
    
    

    public static <T> T getProxy(Class clazz) throws Exception {
    
    

        ClassPool pool = ClassPool.getDefault();
        // 获取类
        CtClass ctClass = pool.get(clazz.getName());
        // 获取方法
        CtMethod ctMethod = ctClass.getDeclaredMethod("queryUserInfo");
        // 方法前加强
        ctMethod.insertBefore("{System.out.println(\"" + ctMethod.getName() + " 你被代理了,By Javassist\");}");

        byte[] bytes = ctClass.toBytecode();

        return (T) new JavassistProxy().defineClass(clazz.getName(), bytes, 0, bytes.length).newInstance();
    }

}

@Test
public void test_JavassistProxy() throws Exception {
    
    
    IUserApi userApi = JavassistProxy.getProxy(UserApi.class)
    String invoke = userApi.queryUserInfo();
    logger.info("测试结果:{}", invoke);
}

/**
 * 测试结果:
 * 
 * queryUserInfo 你被代理了,By Javassist
 * 20:23:39.139 [main] INFO  org.itstack.interview.test.ApiTest - 测试结果:小傅哥,公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获!
 *
 * Process finished with exit code 0
 */

Index: ⭐⭐⭐⭐Scenario
: full link monitoring, proxy-like, AOP
Comment: Javassist is a very widely used bytecode instrumentation framework, almost most non-invasive full link monitoring will choose to use this frame. Because it doesn't want ASM to manipulate bytecodes to cause risks, and its functions are also very complete. In addition, this framework can use the method it provides to directly write instrumentation code, or use bytecode instructions to control the generated code, so it is also a very good bytecode framework on the whole.

Guess you like

Origin blog.csdn.net/qq_21383435/article/details/110704866