按照代理的创建时期,代理类可以分为两种。
静态代理:就是为了在不入侵原本类的基础上,对功能进行扩展,或者过滤等等,是在编译期间已经存在于class文件里面。
动态代理:在程序运行时,运用反射机制动态创建。
今天我们只说动态代理,并分别讲述两种实现方式:
首先,我们先说明要被代理的对象,为接下来的工作做铺垫。
我们有这样一个接口(jdk动态代理必须有接口,后面说):
public interface MyInterface { public String getName(); public int getAge(); }
有这么一个实现类:
public class MyInterfaceImpl implements MyInterface { @Override public String getName() { System.out.println("tom"); return "Tom"; } @Override public int getAge() { System.out.println(11); return 11; } }代理就是在被代理的类的方法执行之前或者执行之后做一些事情,甚至过滤掉。所以我们在方法里输出一句话,便于展示。
JDK的动态代理
jdk的动态代理只有一个类和一个接口
InvocationHandler接口中只有一个方法
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
Proxy类是专门用来完成代理的操作类,可以为一个或多个接口生成实现类,具体方法为:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); }参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:全部的接口
InvocationHandler h:InvocationHandler接口的实现类对象
动态代理类的字节码在程序运行时由Java反射机制动态生成,不需要手动编写代码,java反射机制可以生成任意类型的代理类,所以不仅用起来简单,而且扩展性得到了提高。我们看一个实例:
InvocationHandler接口的实现类:
public class MyInvocationHandler implements InvocationHandler { //要被代理的对象 private Object target; MyInvocationHandler(){ } MyInvocationHandler(Object target){ super(); this.target=target; } /** * * @param proxy 代理者 * @param method 被执行的方法 * @param args 执行方法时,要用到的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); if("getName".equals(name)){ System.out.println("----before "+method.getName()); Object res = method.invoke(target, args); System.out.println("----after"+method.getName()); return res; }else{ return method.invoke(target,args); } } }
我们只在getName方法之前和之后输出一些东西。
测试代码:
public static void main(String[] args) { MyInterface myInterface=new MyInterfaceImpl(); MyInvocationHandler myInvocationHandler= new MyInvocationHandler(myInterface); MyInterface inter= (MyInterface) Proxy.newProxyInstance(myInterface.getClass().getClassLoader(),myInterface.getClass().getInterfaces(),myInvocationHandler); inter.getName(); inter.getAge(); }
结果:
----before getName
tom
----aftergetName
11
从上述测试代码可以看出,要想使用JDK的动态代理,被代理类一定要实现某个接口,这是一个很大的缺陷。对于没有实现接口的类,我们要动态代理,就要使用下面的方法。
Cglib动态代理
Cglib是针对实现类来代理的,被代理者不需要实现接口,它对目标类生成一个子类,并覆盖其中的方法,以实现方法的增强。
cglib的主要方法拦截接口 MethodInterceptor,需要用户自己实现:
public interface MethodInterceptor extends Callback { Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable; }
参数说明:
前三个参数与jdk中InvocationHandler中的Invoke相同:
Object var1:指被代理的对象。
Method var2:要调用的方法
Object[] var3:方法调用时所需要的参数
MethodProxy var4: JDK的java.lang.reflect.Method类的代理类,可以实现对源对象方法的调用。后面的例子将会帮助理解。
net.sf.cglib.proxy.Enhancer:cglib主要的增强类,下面简单看下其中方法:
setSuperclass: 设置被代理的对象。
setCallback: 设置回调函数,一般为MethodInterceptor的实现类。
creat: 创建一个代理对象,你可以直接使用创建的代理对象调用原本的方法。
看个实例:
public class MyCglibInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("----------before----"+method.getName()); Object o1 = methodProxy.invokeSuper(o, objects); System.out.println("----------after----"+method.getName()); return o1; } }
之前说了,cglib是创建一个子类,并覆盖目标类方法,所以我们调用方法时,是使用methodProxy.invokeSuper()。我们在每个方法之前之后都输出一些语句。
测试代码:
MyCglibInterceptor myCglibInterceptor=new MyCglibInterceptor(); Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(myInterface.getClass()); enhancer.setCallback(myCglibInterceptor); MyInterface res = (MyInterface) enhancer.create(); res.getName(); res.getAge();
结果:
----------before----getName
tom
----------after----getName
----------before----getAge
11
----------after----getAge