静态代理&动态代理
代理设计在Java开发中使用较多的一种设计模式,所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。
先来看看静态代理
1 package com.proxy.inter; 2 3 /** 4 * 定义Demo接口 5 */ 6 public interface Demo { 7 public void save(); 8 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 5 /** 6 * DemoImpl实现Demo接口并覆写save()方法 7 * 真实主题,执行具体业务 8 */ 9 public class DemoImpl implements Demo { 10 public void save() { 11 System.out.println("调用save()方法"); 12 } 13 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 /** 5 * DemoImplProxy 也实现了Demo接口,并覆写了save()方法,增加了自己的业务 6 * 代理主题,负责其他业务的处理 7 */ 8 public class DemoImplProxy implements Demo { 9 Demo demoImpl = new DemoImpl(); 10 11 public void save() { 12 System.out.println("开始记录日志"); 13 demoImpl.save(); 14 System.out.println("开始结束日志"); 15 } 16 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 5 /** 6 * 开始记录日志 7 * 调用save()方法 8 * 开始结束日志 9 */ 10 public class Test { 11 public static void main(String[] args) { 12 Demo demoImplProxy = new DemoImplProxy(); 13 14 demoImplProxy.save(); 15 } 16 }
你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持
java.lang.reflect.InvocationHandler接口的定义如下:
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
Object proxy:被代理的对象
Method method:要调用的方法
Object[] args:方法调用时所需要参数
java.lang.reflect.Proxy类的定义如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
CLassLoader loader:类的加载器
Class<?> interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类的实例
下面来看看动态代理的具体实现
1 package com.proxy.inter; 2 3 /** 4 * 定义DemoFirst接口 5 */ 6 public interface DemoFirst { 7 public void saveFirst(); 8 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.DemoFirst; 4 5 /** 6 * DemoFirstImpl实现DemoFirst接口,覆写saveFirst()方法 7 * 真实主题,负责执行具体业务 8 */ 9 public class DemoFirstImpl implements DemoFirst { 10 11 @Override 12 public void saveFirst() { 13 System.out.println("调用saveFirst()方法"); 14 } 15 16 }
1 package com.proxy.impl; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * InvocationHandlerImple实现InvocationHandler接口,覆写invoke()方法 8 * 代理主题的业务写在invoke()方法中 9 */ 10 public class InvocationHandlerImpl implements InvocationHandler { 11 12 private Object target; 13 14 public InvocationHandlerImpl(Object target) { 15 this.target = target; 16 } 17 18 @Override 19 public Object invoke(Object proxy, Method method, Object[] args) 20 throws Throwable { 21 System.out.println("target : " + target.getClass().getName()); 22 System.out.println("proxy : " + proxy.getClass().getName()); 23 System.out.println("method : " + method.getName()); 24 System.out.println("args : " + args); 25 System.out.println("开始记录日志"); 26 Object obj = method.invoke(target, args); 27 System.out.println("结束记录日志"); 28 /* 29 * System.out.println("obj : " + obj.getClass().getName()); 30 * 本例中saveXXX方法没有返回值所以obj会报空指针异常 31 */ 32 return obj; 33 } 34 }
1 package com.proxy.impl; 2 3 import java.lang.reflect.Proxy; 4 5 import com.proxy.inter.DemoFirst; 6 /*import com.proxy.inter.DemoSecond;*/ 7 8 public class Test { 9 public static void main(String[] args) { 10 DemoFirst first = new DemoFirstImpl(); 11 /*DemoSecond second = new DemoSecondImpl();*/ 12 13 //取得代理对象 14 DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first 15 .getClass().getClassLoader(), first.getClass().getInterfaces(), 16 new InvocationHandlerImpl(first)); 17 //通过动态代理调用方法 18 firstProxy.saveFirst(); 19 20 /*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second 21 .getClass().getClassLoader(), second.getClass().getInterfaces(), 22 new InvocationHandlerImpl(second)); 23 secondProxy.saveSecond();*/ 24 } 25 }
执行结果如图:
如果我们需要动态代理demoSecond对象,只需要像上面注释部分那样即可
执行结果如图:
我们会发现代理类Proxy会动态分配proxy对象,如图$Proxy0,$Proxy1...
动态代理的应用在很多地方都由体现,比如在开源框架Spring中的AOP(面向切面编程)...