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

 

posted @ 2020-02-19 14:59  蟹烟客  阅读(703)  评论(0编辑  收藏  举报