[Java] ASMプロキシモードByte-BuddyプロキシモードJavassistプロキシモード

ここに写真の説明を挿入

1。概要

再印刷:リンクの説明を追加

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

インデックス:⭐⭐⭐⭐⭐シナリオ
:フルリンクモニタリング、クラッキングツールキット、CGLIB、クラスメタデータを取得するためのSpringなど。
コメント:この種のプロキシはバイトコードプログラミングによって処理され、その実装は比較的複雑であり、 Java仮想マシン仕様の関連知識を理解する必要があります。プロキシ操作のすべてのステップは、Opcodes.GETSTATIC、Opcodes.INVOKEVIRTUALなどのバイトコード命令を操作しているため、これらに加えて、200の一般的に使用される命令があります。しかし、最下層に最も近いこのアプローチも最速の方法です。したがって、バイトコード計測を使用する一部のフルリンク監視では非常に一般的です。

4.バイトバディプロキシモード

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

インデックス:⭐⭐⭐⭐シナリオ
:AOPアスペクト、クラスエージェント、コンポーネント、モニタリング、ログ
コメント:バイトバディはバイトコード操作用のクラスライブラリでもありますが、バイトバディの方が使いやすいです。バイトコード命令を理解する必要はありません。シンプルなAPIを使用して、バイトコードを簡単に操作し、クラスとメソッドを制御できます。JDK動的プロキシおよびcglibと比較して、ByteBuddyにはパフォーマンスにおいて特定の利点があります。さらに、2015年10月、バイトバディはオラクルからデュークスチョイスアワードを受賞しました。この賞は、ByteBuddyの「Javaテクノロジーの大きな革新」を称えるものです。

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

インデックス:⭐⭐⭐⭐シナリオ
:フルリンクモニタリング、プロキシのような、AOP
コメント:Javassistは非常に広く使用されているバイトコードインストルメンテーションフレームワークであり、ほとんどの非侵襲的フルリンクモニタリングはこれを使用することを選択しますフレーム。ASMがバイトコードを操作してリスクを引き起こすことを望まず、その機能も非常に完全であるためです。さらに、このフレームワークは、提供する方法を使用して計測コードを直接記述したり、バイトコード命令を使用して生成されたコードを制御したりできるため、全体として非常に優れたバイトコードフレームワークでもあります。

おすすめ

転載: blog.csdn.net/qq_21383435/article/details/110704866