常用的代理模式有两种JDK动态代理(JDK自带的)和CGLIB(第三方提供的技术)
代理需要分为两个步骤:
1、建立代理对象和真实对象之间的代理关系。
2、实现代理对象中的代理逻辑方法。
一、JDK动态代理。
JDK动态代理必须借助一个接口才能产生代理对象,因此真实对象也就必须实现此接口。
一个接口
/* * JDK动态代理必须借助接口才能创建代理对象 * */ public interface IPerson { public void say(String name); }
接口的实现类(真实对象)
//真实对象 public class PersonImpl implements IPerson { @Override public void say(String name) { System.out.println("我的名字是"+name); } }
定义代理逻辑类,代理逻辑类必须实现InvocationHandler接口,并实现invoke方法
public class JDKPersonProxy implements InvocationHandler{ private Object target=null; /* * 建立代理对象和真实对象之间的代理关系并返回代理对象 * @param 真实对象或目标对象 * @return 代理对象 * */ public Object bind(Object target) { this.target=target; Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),//目标类的加载器 target.getClass().getInterfaces(),//将代理对象挂在哪些接口下,也就是要增强哪些接口的功能,这也是为什么JDK动态代理要借助接口的原因 this);//实现InvocationHandler接口的实例 return proxy; } /* 实现代理逻辑方法 * 当外界的代理对象调用相应方法时,就会回调到这里 * @param proxy 代理对象 * @param method 要调用的方法 * @param args 方法的参数 * @return 执行结果 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理逻辑方法"); System.out.println("在调用真实对象方法之前的操作"); Object obj=method.invoke(target, args);//通过反射来调用真实对象方法 System.out.println("在调用真实对象方法后的操作!"); return obj; } }
测试类
public class Test { public static void main(String[] args) { JDKPersonProxy jdkPersonProxy=new JDKPersonProxy(); IPerson proxy=(IPerson)jdkPersonProxy.bind(new PersonImpl()); //此时的proxy对象是一个代理对象调用say()方法会进入代理逻辑方法invoke()中 proxy.say("小明"); } }
打印结果
进入代理逻辑方法 在调用真实对象方法之前的操作 我的名字是小明 在调用真实对象方法后的操作!
二、CGLIB动态代理
如果我们的真实对象没有实现任何接口,但是我们还想给他设置一个代理对象怎么办呢,显然通过JDK动态代理是不行的,这里我们采用CGLIB动态代理的方式。注意:因为CGLIB是第三方提供的技术因此需要下载jar包并添加到项目中。
一个未实现任何接口的类
//未实现接口的真实对象 public class Person { public void play(String name) { System.out.println(name+"正在打篮球!"); } }
代理逻辑类
public class CGLIBPersonProxy implements MethodInterceptor{ /* * 获取代理对象 * @param c Class类 * @return Class类的代理对象 * */ public Object getProxy(Class c) { Enhancer enhancer=new Enhancer();//增强类对象 /* * 设置增强类型 * */ enhancer.setSuperclass(c); //定义代理逻辑对象为当前对象,当前对象要实现MethodInterceptor接口,并实现其中的代理逻辑方法 enhancer.setCallback(this); /* * 生成并返回代理对象。本质上其实是创建并返回了c的子类,通过子类来增强父类的功能。 * */ return enhancer.create(); } //返回的代理类调用相应方法会回调这里 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("已经进入逻辑代理方法"); System.out.println("调用真实对象方法前"); //CGLIB反射调用真实方法 Object res=methodProxy.invokeSuper(proxy, args); System.out.println("调用真实对象方法后"); return res; } }测试类
public class Test { public static void main(String[] args) { CGLIBPersonProxy cglibPersonProxy=new CGLIBPersonProxy(); Person proxy=(Person) cglibPersonProxy.getProxy(Person.class); proxy.play("小张"); } }
打印结果
已经进入逻辑代理方法 调用真实对象方法前 小张正在打篮球! 调用真实对象方法后