[Java] Modo proxy de ASM Modo proxy Byte-Buddy Modo proxy Javassist

Inserte la descripción de la imagen aquí

1. Información general

Reimpresión: agregar descripción del enlace

Método de proxy ASM

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
 */

Índice: ⭐⭐⭐⭐⭐Escenario
: monitoreo de enlace completo, kit de herramientas de craqueo, CGLIB, Spring para obtener metadatos de clase, etc.
Comentarios: Este tipo de proxy usa programación de código byte para el procesamiento, y su implementación es relativamente complicada, y Necesita comprender el conocimiento relevante de la especificación de la máquina virtual Java. Debido a que cada paso de su operación de proxy está operando con instrucciones de código de bytes, como Opcodes.GETSTATIC, Opcodes.INVOKEVIRTUAL, además de estas, hay 200 instrucciones de uso común. Pero este enfoque que está más cerca de la capa inferior también es el más rápido. Por lo tanto, es muy común en algunos monitoreos de enlace completo que utilizan instrumentación de código de bytes.

4. Modo proxy Byte-Buddy

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
 */

Índice: ⭐⭐⭐⭐Escenario
: aspectos AOP, agentes de clase, componentes, supervisión, registros
Comentario: Byte Buddy también es una biblioteca de clases para la manipulación de códigos de bytes, pero Byte Buddy es más fácil de usar. No es necesario comprender las instrucciones del código de bytes, puede usar una API simple para manipular fácilmente el código de bytes, las clases de control y los métodos. En comparación con el proxy dinámico JDK y cglib, Byte Buddy tiene ciertas ventajas en el rendimiento. Además, en octubre de 2015, Byte Buddy recibió el premio Duke's Choice de Oracle. El premio elogia a Byte Buddy por su "gran innovación en tecnología Java".

5. Modo proxy de Javassist

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
 */

Índice: ⭐⭐⭐⭐ Escenario
: monitoreo de enlace completo, similar a un proxy, AOP
Comentario: Javassist es un marco de instrumentación de código de bytes muy utilizado, casi la mayoría de los monitoreos de enlace completo no invasivos optarán por usar este marco. Porque no quiere que ASM manipule el código de bytes para causar riesgos, y sus funciones también son muy completas. Además, este marco puede usar el método que proporciona para escribir directamente código de instrumentación, o usar instrucciones de código de bytes para controlar el código generado, por lo que también es un marco de código de bytes muy bueno en general.

Supongo que te gusta

Origin blog.csdn.net/qq_21383435/article/details/110704866
Recomendado
Clasificación