代理模式
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在考虑到性能或安全等因素的情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
Proxy代理类:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
Target目标类:代理角色所代表的真实对象,是我们最终要引用的对象。
动态代理
假如要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色对应一个代理角色,假如大量使用会导致类的急剧膨胀;此外,假如事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
java动态类的实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
static InvocationHandler |
getInvocationHandler(Object proxy) 返回指定代理实例的调用处理程序。 |
static Class<?> |
getProxyClass(ClassLoader loader, Class<?>... interfaces)
返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。 |
static boolean |
isProxyClass(Class<?> cl)
当且仅当指定的类通过 getProxyClass 方法或
newProxyInstance 方法动态生成为代理类时,返回 true。 |
static Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
- 参数:
loader
- 定义代理类的类加载器interfaces
- 代理类要实现的接口列表h
- 指派方法调用的调用处理程序
InvocationHandler
是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke
方法。
Object |
invoke(Object proxy, Method method, Object[] args) 在代理实例上处理方法调用并返回结果。 |
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
根据自己理解画的动态代理原理图
示例代码
写一个动态代理,其内部可以实现 ArrayList 和HashMap中完全相同的功能,并可以计算每个方法运行的时间。
定义代理工具类,可以根据目标和建议的不同生成不同的代理类对象。
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 import java.util.ArrayList; 5 import java.util.List; 6 public class ProxyUtil { 7 //抽取方法,接收不同的目标和建议,返回一个代理 8 public static Object getProxy(final Object target,final Advice advice) { 9 /*参数: 10 定义代理类的类加载器 11 代理类要实现的接口列表 12 指派方法调用的调用处理程序*/ 13 Object proxy = Proxy.newProxyInstance( 14 target.getClass().getClassLoader(), 15 target.getClass().getInterfaces(), 16 new InvocationHandler(){ 17 18 public Object invoke(Object proxy, Method method, Object[] args) 19 throws Throwable { 20 advice.beforeMethod(method); 21 Object retVal = method.invoke(target, args); 22 advice.afterMethod(method); 23 return retVal; 24 } 25 } 26 ); 27 return proxy; 28 } 29 }
定义建议接口
1 import java.lang.reflect.Method; 2 public interface Advice { 3 void beforeMethod(Method method); 4 void afterMethod(Method method); 5 }
自定义建议类实现建议接口
1 import java.lang.reflect.Method; 2 public class MyAdvice implements Advice { 3 long beginTime = 0; 4 public void afterMethod(Method method) { 5 long endTime = System.currentTimeMillis(); 6 System.out.println("["+method.getName() + "]耗时" + (endTime - beginTime)+"毫秒"); 7 } 8 public void beforeMethod(Method method) { 9 beginTime = System.currentTimeMillis(); 10 } 11 }
客户端测试
1 import java.util.*; 2 class TargetDemo 3 { 4 public static void main(String[] args) 5 { 6 //定义target 7 List<String> target = new ArrayList<String>(); 8 //获取target的代理类对象 9 List proxy = (List)ProxyUtil.getProxy(target,new MyAdvice()); 10 //代理类对象实现添加等方法 11 proxy.add("hello"); 12 proxy.add("hehe"); 13 proxy.add("hello"); 14 System.out.println("size="+proxy.size()); 15 for(Object tar : proxy){ 16 System.out.println(tar); 17 } 18 19 System.out.println("================"); 20 21 Map<String,Integer> target1 = new HashMap<String,Integer>(); 22 Map proxy1 = (Map)ProxyUtil.getProxy(target1,new MyAdvice()); 23 proxy1.put("zhangsan1",21); 24 proxy1.put("zhangsan2",22); 25 proxy1.put("zhangsan2",22); 26 System.out.println("size="+proxy1.size()); 27 Set<Map.Entry<String,Integer>> entrySet = proxy1.entrySet(); 28 29 Iterator<Map.Entry<String,Integer>> it = entrySet.iterator(); 30 31 while(it.hasNext()) 32 { 33 Map.Entry<String,Integer> me = it.next(); 34 String key = me.getKey(); 35 Integer value = me.getValue(); 36 37 System.out.println(key+"="+value); 38 } 39 } 40 }
运行结果:
---------- 运行 ----------
[add]耗时1毫秒
[add]耗时0毫秒
[add]耗时0毫秒
[size]耗时0毫秒
size=3
[iterator]耗时1毫秒
hello
hehe
hello
================
[put]耗时0毫秒
[put]耗时0毫秒
[put]耗时0毫秒
[size]耗时0毫秒
size=2
[entrySet]耗时0毫秒
zhangsan1=21
zhangsan2=22
输出完成 (耗时 0 秒) - 正常终止