• 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中, 在使用的时候则是利用父类申明子类调用的方式

  • 相关阅读:
    Silverlight 5 系列学习之一
    WPF中数据绑定问题
    细说ASP.NET Forms身份认证 别人写的不过很透彻就转来了以后用时再看
    再学IHanlder 类----------------关于Asp.net与iis原理网上看博客收获写一个验证码用一般处理程序记的好长时间前就写过不过现在再看有点不一样的感觉
    Oracle常用查看表结构命令
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。(遇到了这个问题网上查了下保存下来)
    TxetBox PasswordChar 模式解除
    屏幕抖动一 下
    oracle 日期问题 网上找到自己查阅时方便
    day5-Dns
  • 原文地址:https://www.cnblogs.com/xieyanke/p/12326096.html
Copyright © 2020-2023  润新知