美文网首页
Dynamic proxy(二)

Dynamic proxy(二)

作者: lqsss | 来源:发表于2018-01-04 23:22 被阅读0次

    前言

    继上篇文章,得知动态代理需解决的问题,通过一个代理类完成全部的代理功能。

    • 静态代理是在编译时,就确定了要代理的对象。
    • 动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

    JDK的动态代理

    修改上篇文章的代码为动态代理

    • LogProxy
    package ProxyPattern.dynamicProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * Created by liqiushi on 2018/1/4.
     */
    public class LogProxy implements InvocationHandler {
        private Object targetObject;
    
        public Object newProxyInstance(Object targetObject) {
            this.targetObject = targetObject;
            //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("invoke() call!");
            System.out.println();
            Object res = null;
            System.out.println("before realSubject!");
            res = method.invoke(targetObject, args);
            System.out.println("after realSubject!");
            return null;
        }
    }
    
    • TestRunner
    package ProxyPattern.dynamicProxy;
    
    public class TestRunner {
        public static void main(String[] args) {
            LogProxy logProxy = new LogProxy();
            Subject subjectProxy = (Subject) logProxy.newProxyInstance(new RealSubject());
            subjectProxy.otherFun();
        }
    }
    
    • 结果
    before realSubject!
    other something! 
    after realSubject!
    

    cglib的动态代理

    • LogProxy
    package ProxyPattern.dynamicProxy.CGLib;
    
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * Created by liqiushi on 2018/1/4.
     */
    public class LogProxy implements MethodInterceptor {
    
        /**定义一个拦截器。在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
         * 代理对象调用方法时,被此拦截
         * @param o 动态生成的代理对象
         * @param method 委托对象的方法
         * @param objects 委托对象的参数
         * @param methodProxy  CGlib方法代理对象的方法引用 
         * @return 调用方法返回值
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            Object result = null;
            System.out.println("before realSubject");
            //调用代理类实例上的proxy方法的父类方法(即委托类的方法)
            result = methodProxy.invokeSuper(o,objects);
            System.out.println("after realSubject");
            return result;
        }
    }
    
    • TestRunner
    package ProxyPattern.dynamicProxy.CGLib;
    
    import net.sf.cglib.proxy.Enhancer;
    
    public class TestRunner {
        public static void main(String[] args) {
            //Enhancer 这里Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展
            Enhancer enhancer = new Enhancer();
            //将委托类设置父类
            enhancer.setSuperclass(RealSubject.class);
            //设置回调拦截
            enhancer.setCallback(new LogProxy());
            //生成代理对象,需要转型
            Subject subject  = (RealSubject) enhancer.create();
            subject.otherFun();
        }
    }
    

    jdk和cglib的不同

    1. java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
    2. cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

    JDK动态代理和CGLIB字节码生成的区别?

    • JDK动态代理只能对实现了接口的类生成代理,而不能针对类
    • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
      因为是继承,所以该类或方法最好不要声明成final

    参考

    AOP的底层实现-CGLIB动态代理和JDK动态代理
    CGLIB介绍与原理

    相关文章

      网友评论

          本文标题:Dynamic proxy(二)

          本文链接:https://www.haomeiwen.com/subject/qcolnxtx.html