Dynamic proxy(二)

前言

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

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

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(二))