为什么JDK的动态代理一定要基于接口实现呢?
一句话解释为什么jdk动态代理必须要通过接口实现,是因为jdk在底层生成代理对象的时候,就默认继承了Proxy类,由于Java是单继承,所以只能通过接口的方式来对目标方法进行代理
代理模式:类结构的模式,优点就是不需要更改原有类(被代理类)就能增强原有类(被代理类)的功能,缺点就是必须实现原有类(被代理类)的接口
1.代理模式
代理模式的作用是:为对象提供一种代理以控制对这个对象的访问。 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到三个角色:
抽象角色 :声明真实对象和代理对象的共同接口;
代理角色 :代理对象角色 内部含有对真实对象的引用,从而可以操作真实对象 ,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色 :代理角色所代表的真实对象,是我们最终要引用的对象。
代理角色和真实角色都继承自抽象角色。
以下以《Java与模式》中的示例为例:
//抽象角色: abstract public class Subject{ abstract public void request(); }
//真实角色:实现了Subject的request()方法。 public class RealSubject extends Subject{ public void request(){ System.out.println("From real subject."); } }
//代理角色: public class ProxySubject extends Subject{ private RealSubject realSubject; //以真实角色作为代理角色的属性 public void request(){ //该方法封装了真实对象的request方法 preRequest(); if( realSubject == null ){ realSubject = new RealSubject(); } realSubject.request(); //此处执行真实对象的request方法 postRequest(); } private void preRequest(){ } private void postRequest(){ } }
//客户端调用: Subject sub=new ProxySubject(); Sub.request();
由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。
另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
2.动态代理
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1) Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:
它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口,以第一节中的示例为例:
抽象角色(之前是抽象类,此处应改为接口): public interface Subject { abstract public void request(); } 具体角色RealSubject: public class RealSubject implements Subject { public RealSubject() {} public void request() { System.out.println( " From real subject. " ); } }
//代理角色: import java.lang.reflect.Method; import java.lang.reflect.InvocationHandler; public class DynamicSubject implements InvocationHandler{ private Object sub; public DynamicSubject(Object sub){ this.sub = sub; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling " + method); method.invoke(sub,args); System.out.println("after calling " + method); return null; } }
也可以这样:
import java.lang.reflect.Method; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicSubject implements InvocationHandler{ private Object sub; public Object createProxyInstance(Object sub){ this.sub = sub; return Proxy.newProxyInstance(this.sub.getClass().getClassLoader(), this.sub.getClass().getInterfaces(), this); //此处注意是要代理的对象 } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before calling " + method); method.invoke(sub,args); System.out.println("after calling " + method); return null; } }
该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的
method.invoke(sub,args);
其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。
客户端:
public class Client { static public void main(String[] args) throws Throwable { RealSubject rs = new RealSubject(); // 在这里指定被代理类 InvocationHandler ds = new DynamicSubject(rs); Class cls = rs.getClass(); // 以下是一次性生成代理 Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds ); subject.request(); }
3.代理模式使用原因和应用方面
(1)授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.
(2)某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况:
如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.
如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.
总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系.
(3)现实中,Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用
代理模式,JDK动态代理,SpringAOP来龙去脉
http://fruitking.iteye.com/blog/601106 (重要参考)
相关推荐
C#面向对象设计模式纵横谈(13):Proxy 代理模式(结构型模式)
C#面向对象设计模式纵横谈(13):Proxy 代理模式(结构型模式) (Level 300)
设计模式C++学习之代理模式(Proxy)
2、代理模式(Proxy) 用意:为其它对象提供一种代理以控制对这个对象的访问
Android设计模式之代理模式(Proxy Pattern)
java 代理模式实现代码及设计详解:动态代理模式、静态代理模式
代理模式是一种设计模式,其定义是为其他对象提供一种代理以控制对这个对象的访问。 代理模式的核心在于提供一个代理来控制和限制对另一个对象的直接访问。这种模式通常用于以下几种情况: 远程代理:当对象位于...
代理模式java代码 Proxy(4) 开发宝典......
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
4.7 proxy(代理)—对象结构型 模式 137 4.8 结构型模式的讨论 144 4.8.1 adapter与bridge 144 4.8.2 composite、decorator与proxy 145 第5章 行为模式 147 5.1 chain of responsibil ity(职责链) —对象...
为其他对象提供一个代理以控制对这个对象的访问。
轻松快捷地管理和切换多个代理设置. 离线插件使用方法: 1. 打开Chrome -> 自定义及控制按钮(右上角) -> 更多工具 -> 扩展程序 (有可能需要打开开发者模式) 2. 拖拽Proxy-SwitchyOmega_2_5_15_0.crx到扩展管理界面 ...
代理模式java代码 Proxy(1) java 学习必备......
代码仅供参考学习 。
全部高质量代理模式proxy的java源程序 java.proxy,代理模式源码,设计模式,apache开源项目源码commons-proxy-1.0-src 各种代理模式操作的工具类源码以及代理模式案例源码,你会从中得到意想不到的效果! apache...
代理模式(Proxy) 定义: 为其他对象提供一种代理以控制对这个对象的访问 结构: 由三部分组成 1.RealSubject(真实对象): 真正会调用到的对象 2.Proxy(代理对象): 代理真实对象的地方 3.Subject(共同点): 代理对象...
NULL 博文链接:https://wy649898543.iteye.com/blog/1431997
代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法复制的资源。 著名...
JAVA Proxy 代理模式