设计模式(一) 动态代理初尝试
- 摘要
之前老是听说动态代理,一直没有机会好好看过,现在就把动态代理的实现逻辑和用处整理一下。
首先提两个概念,委托类和代理类。委托类就是实际业务逻辑的处理者,代理类是处于请求发起者与委托类之间的角色,所有对委托类的请求都会经过代理类。
就是委托类将请求处理委托给代理类,代理类可以起到方法拦截、功能增强的作用。
实现动态代理的方式有很多,现在主流的主要jdk和cglib这两个。下面就用示例代码说明下动态代理的过程,以及用动态代理实现拦截器。 - 用JDK实现动态代理
jdk实现动态代理的包是java.lang.reflect.*,jdk实现动态代理有限制,委托类必须要实现接口,所以先要创建一个接口
public interface MyInterface { //jdk public void tes1(); //cglib public void test2(String val); }
创建接口实现类public class MyTarget implements MyInterface { //jdk @Override public void tes1() { System.out.println("委托类业务处理!"); } //cglib @Override public void test2(String val) { System.out.println("业务处理结果:"+val); } }
动态代理逻辑代码package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyProxyTest implements InvocationHandler { //继承InvocationHandler,拦截方法 private Object target=null; //构造函数 public MyProxyTest(Object target){ this.target = target ; } //获取代理类的方法 public static Object getProxy(Object target){ //通过proxy创建代理类,需要三个参数,委托类的类加载器、委托类实现的接口、代理类 /** * 这是jdk的动态代理模式,必须要有接口 * proxy会把代理类挂载到所有接口下面 * 如果委托类没有实现任何接口会有问题,改用CGLIB的enhancer增强类做动态代理 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new MyProxyTest(target)); } //拦截方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理逻辑!"); System.out.println("代理类处理逻辑!"); Object result=null; result = method.invoke(target,args); System.out.println("委托类处理完后的逻辑!"); return result; } }
getProxy方法就是绑定委托类和代理类之间关系的方法,这里绑定的代理类是this当前对象,也就是MyProxyTest 的实例对象,由于实现了InvocationHandler接口,所以在方法调用之前都会
通过invoke方法,在这里就可以写功能增强的代码。method.invoke(target,args)是通过反射运行委托类的方法。
测试用例public class JunitTest { public static void main(String[] args) { /** * jdk动态代理 */ System.out.println("---------jdk动态代理--------"); //委托类 MyTarget target = new MyTarget(); //给委托类绑定代理类 MyInterface proxy = (MyInterface)MyProxyTest.getProxy(target); proxy.tes1(); } }
运行结果---------jdk动态代理-------- 进入代理逻辑! 代理类处理逻辑! 委托类业务处理! 委托类处理完后的逻辑!
我们发现进入了代理类的处理逻辑。
- CGLIB实现动态代理
CGLIB实现动态代理和JDK大同小异,不过CGLIB是通过创建增强类Enhancer,并且设置Enhancer的委托类和代理类来实现动态代理。CGLIB的委托类不需要实现接口。
动态代理逻辑
package proxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class MyCgLibProxy implements MethodInterceptor { public Object getProxy(Class target){ //创建增强类 Enhancer enhancer = new Enhancer(); //设置委托类 enhancer.setSuperclass(target); //设置代理类 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("进入代理逻辑!"); System.out.println("代理类处理逻辑!"); Object result=null; result = methodProxy.invokeSuper(o,objects); System.out.println("委托类处理完后的逻辑!"); return result; } }
这里的getProxy接收的不是委托类的实例对象而是委托类。代理类是this,MyCgLibProxy 的实例对象,由于实现了MethodInterceptor拦截器,所以方法调用都会经过intercept。
测试用例package proxy; public class JunitTest { public static void main(String[] args) { /** * cglib动态代理 */ System.out.println("---------cglib动态代理--------"); MyCgLibProxy cgLib = new MyCgLibProxy(); MyInterface cgLibProxy = (MyInterface)cgLib.getProxy(MyTarget.class); cgLibProxy.test2("cglib动态代理"); } }
运行结果
---------cglib动态代理-------- 进入代理逻辑! 代理类处理逻辑! 业务处理结果:cglib动态代理 委托类处理完后的逻辑!
简单的实现动态代理的两种方式就完成了,之后再讲解拦截器和责任链模式