Java动态代理(Dynamic Proxy)
2015-12-26 14:00
471 查看
1.Proxy定义
Dynamic Proxy API是在Java1.3中引入的。Proxy强制对象方法通过代理对象(Proxy Object)调用。代理对象被声明客户端对象没有迹象表明他们有代理对象的实例。一些常用的代理有:access proxy、facade、remote proxy和virtual proxy。
access proxy被用于在访问服务器或提供数据的对象时实施安全策略。
facade是连接多个底层对象的单一接口。
remote proxy被用于隐藏底层对象时远程的客户对象。
virtual proxy被用于延迟执行实际对象的实例化。
代理也是一个基础的设计模式,被经常用于编程中。但是,它的一个缺点是专一性或者代理和它的底层对象紧密耦合。
2.Dynamic Proxies
为了使用动态代理,你有两步要做:第一,必须有一个代理接口,这个代理接口是要被代理类实现的接口;第二,需要有一个代理类的实例。有意思地是,你可以有一个实现了多个接口的代理类。但是,当你创建动态代理时,有几个约束条件要记住。以下是对于你实现接口的几个约束条件:代理接口必须是一个接口。换句话说,它不能是一个类或者一个抽象类。
传给代理构造方法的接口数组必须不包含同一个接口的副本,即你不能同时实现一个接口两次。例如,{IPerson.class, IPerson.class}是非法的,但是{IPerson.class, IEmployee.class}(IEmployee继承了IPerson)是合法的。调用构造方法的代码应该检查过滤掉副本。
在构造调用ClassLoader期间,所有的接口必须对指定的ClassLoader是可见的。另外,这个ClassLoader必须能够为该代理加载这些接口。
所有非公有接口必须在同一个包中。你不能有一个private接口在com.xyz中,而它的代理类在com.abc中。你也不能用一个普通类实现其他包中的非公用接口。
代理接口不能有冲突的方法。你不能有两个拥有相同参数但返回值类型不同的方法。例如,public void foo()和public String foo()不能定义在同一个类里,因为他们有相同的签名,只是返回值不同而已。
生成的代理类不能超过虚拟机的限制。比如说,被实现的接口的数量的限制。
3.示例
上面说了一大堆,现在看下代码。创建动态代理类,你需要实现java.lang.reflect.InvocationHandler接口:public class MyDynamicProxyClass implements InvocationHandler { Object obj; public MyDynamicProxyClass(Object obj) { this.obj = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { String methodName = method.getName(); if(methodName.startsWith("get")){ String name = methodName.substring(methodName.indexOf("get") + 3); return method.invoke(obj, args); } else if(methodName.startsWith("set")){ String name = methodName.substring(methodName.indexOf("set") + 3); method.invoke(obj, args); return null; } else if(methodName.startsWith("is")){ String name = methodName.substring(methodName.indexOf("is") + 2); return null; } return null; } catch (Exception e) { throw e; } } }
假设我们已经有了一个IPerson接口和它的实现类Person。那么,我们来下如何使用动态代理:
IPerson person = new Person(); IPerson proxy = (IPerson) Proxy.newProxyInstance(person.getClass().getClassLoader(), new Class[] {IPerson.class}, new MyDynamicProxyClass(person));
没错,这样就创建了动态代理。代码看上去很丑陋对吗?如果每次都这样写很揪心不是吗?实际上,每次都这样写着实很丑陋。那么,我们换一种方式,把它给包装起来:
public class ViewProxy implements InvocationHandler{ private Map map = new HashMap(); private Object obj; public ViewProxy(Object obj) { this.obj = obj; } public static Object newInstance(Object obj, Class[] interfaces){ return Proxy.newProxyInstance(obj.getClass().getClassLoader(), interfaces, new ViewProxy(obj)); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub String methodName = method.getName(); if(methodName.startsWith("get")){ String name = methodName.substring(methodName.indexOf("get") + 3); // return map.get(name); return method.invoke(obj, args); } else if(methodName.startsWith("set")){ String name = methodName.substring(methodName.indexOf("set") + 3); // map.put(name, args[0]); method.invoke(obj, args); return null; } else if(methodName.startsWith("is")){ String name = methodName.substring(methodName.indexOf("is") + 2); return map.get(name); } return null; } }
IPerson:
public interface IPerson { public String getName(); public String getAddress(); public void setName(String name); public void setAddress(String address); }
Person:
public class Person implements IPerson { private String name; private String address; @Override public String getName() { // TODO Auto-generated method stub return name; } @Override public String getAddress() { // TODO Auto-generated method stub return address; } @Override public void setName(String name) { // TODO Auto-generated method stub this.name = name; } @Override public void setAddress(String address) { // TODO Auto-generated method stub this.address = address; } }
main方法:
public static void main(String[] args) { IPerson person = new Person(); IPerson proxy = (IPerson) ViewProxy.newInstance(person, new Class[] {IPerson.class}); proxy.setName("Bob Jones"); proxy.setAddress("Chicago");; System.out.println(proxy.getName() + ", " + proxy.getAddress()); }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树