栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

动态代理你知道几种?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态代理你知道几种?

相信大家脱口而出的就是JDK、CGLIB这两种最熟悉的代理模式,其实代理模式除了这两种之外,还有三种代理模式.下面就一一列举.

准备一个基础的接口和类作为演示的对象.

    // 接口
    public interface CatAPI{
        
       void skin(String color);
       
    }
   // 目标对象 
   public class blackCat implements  CatAPI{

        @Override
        public void skin(String color) {

            System.out.println("我是一只" + color + "的小猫咪");

        }
    }

一、JDK代理

    public static class JdkProxy implements InvocationHandler{

        // 目标对象
        private static Object target;

        public static Object getProxy(Object obj) throws Exception {
            target = obj;
            // 获取类加载器
            ClassLoader classLoader = obj.getClass().getClassLoader();
            // 获取目标对象实现的接口
            Class[] interfaces = obj.getClass().getInterfaces();
            return Proxy.newProxyInstance(classLoader, interfaces,new JdkProxy());
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 增强语句
            System.out.println("我是一只聪明的小猫咪");
            // 执行原方法
            return method.invoke(target,args);
        }
    }



    public static void main(String[] args) throws Exception {
        BlackCat blackCat = new BlackCat();
        CatAPI proxy = (CatAPI)JdkProxy.getProxy(blackCat);
        proxy.skin("黑色");

    }

测试结果 

二、CGLIB代理

依赖

        
            cglib
            cglib
            3.3.0
            compile
        
public static class CGLIBProxy implements MethodInterceptor {

        private static Object target;

        public static Object getProxy(Object obj){
            target = obj;
            return Enhancer.create(obj.getClass(), new CGLIBProxy());
        }


        @Override
        public Object intercept(Object p, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 参数说明:
            //  1、p 代理对象
            //  2、method 目标方法
            //  3、args 方法参数
            //  4、methodProxy 代理方法 :使用methodProxy的好处是内部不会反射
            System.out.println("我是一只聪明的小猫咪");
            //  return methodProxy.invokeSuper(p,args); // 内部没有反射,需要代理对象
            return method.invoke(target,args);  // 内部没有反射,需要目标对象
        }
    }

    public static void main(String[] args) throws Exception {
        BlackCat blackCat = new BlackCat();
        CatAPI proxy = (CatAPI)CGLIBProxy.getProxy(blackCat);
        proxy.skin("黑色");
    }

测试结果

三、 ASM代理方式

依赖

      
            asm
            asm-all
            3.3.1
        
    public static class ASMProxy extends ClassLoader {

        public static  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 (!"skin".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();
        }

    }
    
    public static void main(String[] args) throws Exception {
        
        CatAPI proxy = (CatAPI) ASMProxy.getProxy(BlackCat.class);
        proxy.skin("黑色");
    }

测试结果

四、 Byte-Buddy代理方式

依赖

        
            net.bytebuddy
            byte-buddy
            1.10.13
        
    private static CatAPI createByteBuddyDynamicProxy() throws Exception {
        return (CatAPI) new ByteBuddy().subclass(BlackCat.class)
            .implement(CatAPI.class)
            .method(ElementMatchers.named("skin"))
            .intercept(MethodDelegation.to(new SingerAgentInterceptor()))
            .make()
            .load(Thread.currentThread().getContextClassLoader())
            .getLoaded()
            .getDeclaredConstructor()
            .newInstance();
    }

    public static class SingerAgentInterceptor {

        public Object interceptor(@This Object proxy,
                                  @Origin Method method,
                                  @SuperMethod Method superMethod,
                                  @AllArguments Object[] args) throws Exception {
            System.out.println("我是一只聪明的小猫咪 ");
            Object ret = superMethod.invoke(proxy, args);
            return ret;
        }
    }


    public static void main(String[] args) throws Exception {
        CatAPI proxy = createByteBuddyDynamicProxy();
        proxy.skin("黑色");
        System.out.println(proxy.toString());
    }

测试结果

五、Javassist代理方式

依赖

        
            org.javassist
            javassist
            3.21.0-GA
        
    public static class JavassistProxy extends ClassLoader {

        public static  T getProxy(Class clazz) throws Exception {

            ClassPool pool = ClassPool.getDefault();
            // 获取类
            CtClass ctClass = pool.get(clazz.getName());
            // 获取方法
            CtMethod ctMethod = ctClass.getDeclaredMethod("skin");
            // 方法前加强
            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();
        }

    }

    public static void main(String[] args) throws Exception {
        CatAPI proxy = (CatAPI) JavassistProxy.getProxy(BlackCat.class);
        proxy.skin("黑色");
    }

 测试结果

 以上列举了五种代理方式,对于ASM、Byte-Buddy和Javassist一层一层封装,使用起来也越来越简单,后续会有文章对这三种方式进行一个详细的讲解,这里只做一个例子展示.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/844490.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号