zoukankan      html  css  js  c++  java
  • spring源码分析一:动态代理

    Jdk动态代理

     只有接口无实现类动态代理: 参考Mybatis中MapperProxy类, 用于动态代理Mapper接口

    public class Test {
    
        //需要动态代理的接口类
        interface DaynamicInteface {
            int getInt();
            String getString();
        }
    
        public static void main(String[] args) throws InterruptedException {
         //动态代理实例化接口
            DaynamicInteface daynamicInteface = (DaynamicInteface)Proxy.newProxyInstance(DaynamicInteface.class.getClassLoader(), new Class[]{DaynamicInteface.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //实现方法getInt
                    if (method.getName().equals("getInt")){
                        System.out.println(111);
                        return 1;
                    }
                    //实现方法getString
                    else if (method.getName().equals("getString")){
                        System.out.println("aaa");
                        return "a";
                    }
                    //java Objec默认方法实现 不实现会报错
                    else {
                        return invokeDefaultMethod(proxy, method, args);
                    }
                }
            });
            //执行自定义方法
            daynamicInteface.getString();
            //执行object默认方法
            daynamicInteface.toString();
        }
    
        public static Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
                throws Throwable {
            final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
                    .getDeclaredConstructor(Class.class, int.class);
            if (!constructor.isAccessible()) {
                constructor.setAccessible(true);
            }
            final Class<?> declaringClass = method.getDeclaringClass();
            return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
                    .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
        }
    
    }

    有接有实现类动态代理:常用于不修改代码的情况下 实现功能修改或者织入额外代码

    /** 这是一个额外打印日志的动态代理 */
    
    public class Test {
    
        //需要动态代理的接口类
        interface DaynamicInteface {
            int getInt();
            String getString();
        }
        public static class DaynamicImpl implements DaynamicInteface{
            @Override
            public int getInt() {
                System.out.println("执行了getInt");
                return 0;
            }
            @Override
            public String getString() {
                System.out.println("执行了getString");
                return null;
            }
        }
        public static void main(String[] args) throws InterruptedException {
            //原来的实现类实例化
            DaynamicInteface target = new DaynamicImpl();
            //代理类 在执行方法执行打印额外日志
            DaynamicInteface proxy = (DaynamicInteface)Proxy.newProxyInstance(DaynamicInteface.class.getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //打印额外日志
                    if (method.getName().equals("getInt")){
                        System.out.println("我打印了日志:getInt");
                    }
                    //打印额外日志
                    else if (method.getName().equals("getString")){
                        System.out.println("我打印了日志:getString");
                    }
                    return method.invoke(target, args);
                }
            });
            //执行自定义方法
            proxy.getString();
            //执行object默认方法
            proxy.toString();
        }
    
    }
    
    结果:
    我打印了日志:getString
    执行了getString

    Cglib动态代理:通常用于没有接口的情况使用

    public class Test {
    
        public static class DaynamicImpl{
            public int getInt() {
                System.out.println("执行了getInt");
                return 0;
            }
            public String getString() {
                System.out.println("执行了getString");
                return null;
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(DaynamicImpl.class);
            //设置回调函数
            enhancer.setCallback(new MethodInterceptor(){
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    //打印额外日志
                    if (method.getName().equals("getInt")){
                        System.out.println("我打印了日志:getInt");
                    }
                    //打印额外日志
                    else if (method.getName().equals("getString")){
                        System.out.println("我打印了日志:getString");
                    }
                    Object object = proxy.invokeSuper(obj, args);
                    return object;
                }
            });
    
            //这里的creat方法就是正式创建代理类(实际为目标类的子类) 因为系统环境参数设置了反编译文件存储路径 此时会讲实际的反编译文件写入D:\java
            DaynamicImpl proxyImpl = (DaynamicImpl)enhancer.create();
    
            proxyImpl.getInt();
            proxyImpl.getString();
        }
    
    }
    
    结果:
    CGLIB debugging enabled, writing to 'D:java'
    我打印了日志:getInt
    执行了getInt
    我打印了日志:getString
    执行了getString

     

    区别:

      JDK动态代理方式: 利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

      CGLIB动态代理方式: 生成一个目标类的子类, 编译到JVM中, 在使用的时候则是利用父类申明子类调用的方式

  • 相关阅读:
    C#和C实现通过CRC-16 (Modbus)获取CRC值并校验数据(代码)
    c#串口通信类代码可以直接调用
    栈的理解以及如何计算程序所需栈的大小并在IAR中设置栈
    Heap堆的理解以及在IAR中如何设置堆的大小
    ARM Cortex-M0权威指南高清中文版pdf免费分享下载
    如何重新划分linux分区大小
    Using Internal EEPROM of PIC Microcontroller
    树莓派Odroid等卡片式电脑上搭建NAS教程系列6-miniDLNA
    './mysql-bin.index' not found (Errcode: 13) 的解决方法
    移植mysql到嵌入式ARM平台
  • 原文地址:https://www.cnblogs.com/xieyanke/p/12326096.html
Copyright © 2011-2022 走看看