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

  • 相关阅读:
    Django测试开发-20-settings.py中templates配置,使得APP下的模板以及根目录下的模板均可生效
    Django测试开发-19-auth模块之session,cookie
    Django测试开发-19-引入xadmin
    Django测试开发-17-报错:No module named 'django.contrib.staticfiles.templatetags'
    Django测试开发-16-ImportError: cannot import name 'six' from 'django.utils'
    Django测试开发-15-django.utils.encoding未发现 python_2_unicode_compatible包
    Django测试开发-14-数据库表设计:多对多,一对一,一对多
    Django测试开发-13-优化表单提交(GET、POST、登录、注册)
    Django测试开发-12-优化admin (2020-03-13 18:57)
    Django测试开发-11-返回json数据
  • 原文地址:https://www.cnblogs.com/xieyanke/p/12326096.html
Copyright © 2011-2022 走看看