当前位置:首页 > CN2资讯 > 正文内容

代理(Proxy)模式spring 代理模式

2天前CN2资讯

  代理(Proxy)模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

  所谓代理,可以理解为一个人或者机构代表另一个人或者机构采取行动。

1.  种类     

按照使用目的划分,分为以下几种:   

远程(Remote)代理:为一个位于不同地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器。远程代理又叫做大使。

虚拟代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。

Copy-on-Write代理:虚拟代理的一种,把复制拖延到客户端需要时才真正采取行动。

保护代理:控制一个对象的访问,如果需要,可以给不同的用户不同级别的访问权。

Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

防火墙代理:保护目标,不让恶意用户接近。

同步化代理:使几个用户能够同时使用一个对象而不会冲突。

智能引用:当一个对象呗调用时,提供一些额外的操作,比如将此对象调用的次数记录下来。

  在所有的代理模式中,虚拟代理、远程代理、智能引用代理和保护代理模式最为常见。

2.  代理模式

UML类图如下:

设计到的角色:

抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题。

代理主题角色:代理主题角色内部含有真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便在任何时候可以代理主题角色;

真实主题角色:定义了代理角色所代表的真实对象。

 

 代码如下:

package cn.qlq.proxy; public abstract class Subject { abstract void request(); } package cn.qlq.proxy; public class RealSubject extends Subject { @Override void request() { System.out.println("request"); } } package cn.qlq.proxy; public class ProxySubject extends Subject { private RealSubject realSubject; public ProxySubject() { realSubject = new RealSubject(); } @Override void request() { preRequest(); realSubject.request(); postRequest(); } private void postRequest() { System.out.println("postRequest"); } private void preRequest() { System.out.println("preRequest"); } }

客户端代码:

package cn.qlq.proxy; public class Client { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.request(); } }

 代理模式工作过程:

  首先,代理主题并不改变主题的接口,因为模式的用意是不让客户端感觉到代理的存在;

  其次,代理事宜委派将客户端的调用委派给真实的主题对象,换言之,代理主题起到的是一个传递请求的作用;

  最后,代理主题在传递请求之前和之后都可以执行特定的操作,而不是单纯传递请求。

3. Java中对代理模式的支持

3.1    静态代理

  静态代理类似于装饰模式,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。其实上面就可以理解为一个静态代理。

3.2  JDK代理(接口代理)-动态代理

  从JDK1.3以来,Java在java.lang.reflect包下提供下面三个类支持代理模式:Proxy、InvocationHandler和Method。

  Proxy类使得设计师能够在运行时间创建代理对象。当系统有了代理对象之后,对原方法的调用会首先被分派给一个调用处理器(InvocationHandler)。程序可以在调用处理器的invoke()方法中进行额外的操作。

  显然,Java语言所提供的这一支持是建立在反射基础上的。

  创建代理对象如下:

(1)指明一系列的接口来创建一个代理对象。

 (2)创建一个调用处理器(InvocationHandler)对象。

(3)将这个代理指定为某个其他对象的引用。

(4)在调用处理器的invoke方法中采取代理,一方面将调用传递给真实对象,另一方面执行所需的操作。

注意:此模式是基于接口的代理,所以被代理对象必须有接口,代码如下:

package cn.qlq.proxy; public interface Subject { void request(); } package cn.qlq.proxy; public class RealSubject implements Subject { @Override public void request() { System.out.println("request"); } } package cn.qlq.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 创建动态代理对象 动态代理不需要实现接口,但是需要指定接口类型 */ public class ProxyFactory { // 维护一个目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 给目标对象生成代理对象 public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始执行之前"); // 运用反射执行目标对象方法 Object returnValue = method.invoke(target, args); System.out.println("开始执行之后"); return returnValue; } }); } }

客户端代码:

package cn.qlq.proxy; public class Client { public static void main(String[] args) { Subject target = new RealSubject(); Subject proxyInstance = (Subject) new ProxyFactory(target).getProxyInstance(); proxyInstance.request(); } }

结果:

开始执行之前
request
开始执行之后

3.2  cglib代理(继承代理)-动态代理

 需要的jar包:

  上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

  • JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
  • Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
  • Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.

Cglib子类代理实现方法:

1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
5.如果方法为static,private则无法进行代理。

例如:(RealSubject不实现接口)

package cn.qlq.proxy; public class RealSubject { public void request() { System.out.println("request"); } }

代理工厂:

package cn.qlq.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 创建动态代理对象 动态代理不需要实现接口,但是需要指定接口类型 */ public class ProxyFactory implements MethodInterceptor { // 维护一个目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 给目标对象生成代理对象 public Object getProxyInstance() { // 1.工具类 Enhancer en = new Enhancer(); // 2.设置父类 en.setSuperclass(target.getClass()); // 3.设置回调函数 en.setCallback(this); // 4.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行前..."); // 执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("执行后..."); return returnValue; } }

或者:

package cn.qlq.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 创建动态代理对象 动态代理不需要实现接口,但是需要指定接口类型 */ public class ProxyFactory2 { // 维护目标对象 private Object target; public ProxyFactory2(Object target) { this.target = target; } // 给目标对象创建一个代理对象 public Object getProxyInstance() { // 1.工具类 Enhancer en = new Enhancer(); // 2.设置父类 en.setSuperclass(target.getClass()); // 3.设置回调函数 en.setCallback(new MethodInterceptor() { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行前..."); // 执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("执行后..."); return returnValue; } }); // 4.创建子类(代理对象) return en.create(); } }

客户端:

package cn.qlq.proxy; public class Client { public static void main(String[] args) { RealSubject target = new RealSubject(); RealSubject proxyInstance = (RealSubject) new ProxyFactory(target).getProxyInstance(); System.out.println(proxyInstance.getClass()); proxyInstance.request(); } }

结果:

class cn.qlq.proxy.RealSubject$$EnhancerByCGLIB$$2f221c0c
执行前...
request
执行后...

总结:

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】
    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/24400.html

    分享给朋友:

    “代理(Proxy)模式spring 代理模式” 的相关文章

    WordPress登录验证设置:提升网站安全性与用户体验

    在使用WordPress构建网站时,登录验证设置是确保用户身份安全和信息保护的重要环节。它不仅涉及用户从何处进入网站,更关乎整个网站的安全性能。在这章中,我将为你详细解析什么是WordPress登录验证,它的重要性以及基本的流程。 什么是WordPress登录验证 WordPress登录验证主要是通...

    如何利用阿里云24元优惠活动体验云计算服务

    阿里云是一家全球知名的云计算服务提供商,致力于为用户提供多样化的云计算产品与服务。最近推出的24元优惠活动,更是为不少用户带来了新的机遇。这项优惠活动的主要目标是让更多的个人和企业体验到优质的云服务,尤其是在数字化转型日益重要的今天。用户可以通过这一活动以超低价格体验阿里云的强大功能。 在参与这个优...

    选择最佳印度尼西亚 VPS 服务商的终极指南

    在了解印度尼西亚的虚拟专用服务器(VPS)之前,我们先来讲讲VPS的基本概念。简单来说,VPS是一种将一台物理服务器划分为多个虚拟服务器的技术。每个虚拟服务器都有独立的操作系统、资源和配置,让用户可以像使用独立服务器一样,获得更高的灵活性和控制权。这种方式不但能满足各种规模的业务需求,还能显著降低成...

    Virmach Coupons: 轻松获取超值优惠,优化你的VPS选择

    Virmach成立于2014年,作为一家美国VPS服务商,在业内享有良好的声誉。它的总部位于加利福尼亚州洛杉矶,正是这样得天独厚的地理位置让它能迅速成长并服务全球用户。到现在为止,Virmach已经发展成为一家提供各种配置和价格方案的服务商,特别以低价VPS而闻名,吸引了大量希望降低运营成本的个人和...

    宝塔面板PHP扩展新增指南:提升网站性能的实用技巧

    在日常网站管理和服务器配置中,宝塔面板的出现让这一切变得更为简单直观。作为一个流行的服务器控制面板,宝塔面板以其用户友好的界面和丰富的功能备受欢迎。对于没有技术背景的用户来说,它提供了极大的便利,而对于开发者来说,宝塔也能高效管理复杂的服务器配置。 宝塔面板不仅支持多种服务器环境,还能够轻松管理数据...

    AS4837线路概述与技术特点解析,适合预算有限用户的高速网络选择

    AS4837线路的概述 当我开始了解AS4837线路时,就会发现它不仅仅是一个技术名词,更是中国联通的一部分。AS4837,简称为China169,是中国联通的骨干网线路,诞生于20世纪90年代。这条线路架起了中国大陆与全球之间的桥梁,特别是连接了香港、美国、日本和韩国等重要地区。对于那些追求高速互...