java模拟火车站买票的过程_Java常用代理

在我们通常的应用中,代理模式也是我们常用的设计模式之一。所谓的代理模式是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。

为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

在我们现实生活中,这种情形也是非常常见非常常见的,就比如,黄牛买票,黄牛相当于是火车站的代理,我们可以通过黄牛买票,但只能去火车站进行改签和退票。

在代码实现中,相当于为一个委托对象Station(车站)提供一个代理对象Scalper(黄牛),通过Scalper(黄牛)可以调用Station(车站)的部分功能,并添加一些额外的业务处理,同时可以屏蔽Station(车站)中未开放的接口。

代理模式的UML图

6719abb61af7449d557b06c08ded9a0c.png

代理模式类图

1,Station(车站)是委托类,Scalper(黄牛)是代理类;

2,Subject是委托类和代理类的接口;

3,sell()是委托类和代理类的共同方法;

从UML图中,可以看出代理类与真正实现的类都是实现了抽象的接口,这样的好处的在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。

二 Java常用的三种代理

2.1 静态代理

      在代码实现中相当于为一个委托对象realSubject提供一个代理对象proxy,通过proxy可以调用realSubject的部分功能,并添加一些额外的业务处理,同时可以屏蔽realSubject中未开放的接口。

e3a8f061123034ab69b733c327e1b3be.png

1、RealSubject 是委托类,Proxy 是代理类;
2、Subject 是委托类和代理类的接口;
3、request() 是委托类和代理类的共同方法;

具体代码实现如下:

interface Subject {    void request();
}class RealSubject implements Subject {    public void request(){
       System.out.println("RealSubject");
   }
}class Proxy implements Subject {    private Subject subject;    public Proxy(Subject subject){        this.subject = subject;
   }    public void request(){
       System.out.println("begin");
       subject.request();
       System.out.println("end");
   }
}public class ProxyTest {    public static void main(String args[]) {
       RealSubject subject = new RealSubject();
       Proxy p = new Proxy(subject);
       p.request();
   }
}

静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。

eff04e4dfdf6e6e7248305be5625c449.png

2.2 动态代理

动态代理有以下特点:

  1. 在运行期,通过反射机制创建一个实现了一组给定接口的新类;

  2. 在运行时生成的class,必须提供一组interface给它,然后该class就宣称它实现了这些 interface。该class的实例可以当作这些interface中的任何一个来用。但是这个Dynamic Proxy其实就是一个Proxy, 它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

  3. 动态代理也叫做:JDK代理,接口代理

  4. 70702fe4678e32dec416f1fcb3cb51ba.png

  5. 接口中声明的所有方法都被转移到调用处理器(handler)一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。

JDK中生成代理对象的API
  代理类所在包:java.lang.reflect.Proxy
  JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

    static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler handler)

  注意该方法是在Proxy类中的静态方法,且接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用的类加载器,用null表示默认类加载器

  • Class [] interfaces:需要实现的接口数组

  • InvocationHandler handler:调用处理器,执行目标对象的方法时,会触发调用处理器的方法,从而把当前执行目标对象的方法作为参数传入

java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

    // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数是代理类实例,第二个参数是被调用的方法对象,第三个参数是方法参数的数组形式
   // 第三个方法是调用参数。
   Object invoke(Object proxy, Method method, Object[] args)

代码示例:

package model;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;interface IUserDao {    void save();
}class UserDao implements IUserDao {    public void save() {
       System.out.println("----已经保存数据!----");
   }
}class ProxyFactory {    private Object target;    public ProxyFactory(Object target) {        this.target = target;
   }    // 给目标对象生成代理对象,其class文件是由 JVM 在运行时动态生成
   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("开始");                        // 执行目标对象方法,方法参数是target,表示该方法从属于target
                       Object returnValue = method.invoke(target, args);
                       System.out.println("提交");                        return returnValue;
                   }
               });
   }
}public class Client {    public static void main(String[] args) {        // 目标对象
       IUserDao target = new UserDao();
       System.out.println(target.getClass());        // 代理对象
       IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
       System.out.println(proxy.getClass());
       proxy.save();
   }
}

输出:

class model.UserDaoclass model.$Proxy0开始
----已经保存数据!----
提交

总结:
  代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

721efb638ccc58f9242c8bfbe9ba9bae.png

2.3 Cglib代理

  上面的静态代理和动态代理模式都是要求目标对象实现一个接口或者多个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用构建目标对象子类的方式实现代理,这种方法就叫做:Cglib代理。
  Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

  • Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)

  • Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的子类

  • 代理的类不能为final,否则报错;目标对象的方法如果为final/static,那么就不会被拦截。

代码示例:
目标对象类:UserDao.java

    /**
    * 目标对象,没有实现任何接口
    */
   public class UserDao {        public void save() {
           System.out.println("----已经保存数据!----");
       }
   }

Cglib代理工厂:ProxyFactory.java

    /**
    * Cglib子类代理工厂
   * 对UserDao在内存中动态构建一个子类对象
   */
   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;
       }
   }

测试类:

    /**
    * 测试类
    */
   public class App {        @Test
       public void test(){            //目标对象
           UserDao target = new UserDao();            //代理对象
           UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();            //执行代理对象的方法
           proxy.save();
       }
   }

91fc0a3256be191e3e9b54ce7c1c43e4.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络繁杂,我们该如何准确获取所需信息?

全世界只有3.14 % 的人关注了爆炸吧知识网络已经成为了很多人发表言论的地方不少网站亦难免存在宣泄情绪的内容网络繁杂,该如何获取准确信息?下面为你推荐一些客观公号希望能让你扩展视野,增长见识!【关注方式 】1 - 搜索公众号ID…

被评为“影响世界千年的物理学家”,杨振宁的伟大,你根本不了解

全世界只有3.14 % 的人关注了爆炸吧知识2018年3月14日,英国科学家霍金去世,作为当代英国最杰出的科学家之一,英国用最规格的方式送别了这位伟大的科学家。霍金去世了,中国媒体沸腾了!有人说:这是全人类的损…

Blazor+Dapr+K8s微服务之服务调用

1.1 Dapr环境配置1.1.1 在开发机安装Docker Desktop并启用Kubernetes安装过程略,安装好后效果如下:(左下角两个绿色指示Docker和K8s正在运行)1.1.2 在开发机安装Dapr Cli安装命令:powershell -Command …

mysql 卸载插件_MySQL 插件安装或卸载(window validate_password 为例)

查看插件:mysql> show plugins;mysql> select plugin_name,plugin_status,plugin_type,load_option,plugin_library from information_schema.plugins;默认插件目录:mysql> show variables like plugin_dir;----------------------------------…

11部高分学科纪录片,助力孩子涨姿势拓视野~

全世界只有3.14 % 的人关注了爆炸吧知识▌导读本文为同学们整理了11部高分经典学科纪录片,对应文学、数学、经济学、地理、化学、生物、物理、历史、社会学、美学、天文学11个学科。这不仅是课堂学习的补充与延伸,更是开拓视野、激发学习内驱力的绝佳利器…

Istio 首次安全评估结果公布

本文译自 Istio 社区官方博客 Announcing the results of Istio’s first security assessment[1],作者 Neeraj Poddar,译者宋净超。Istio 服务网格已在各行各业获得广泛的生产应用。该项目的成功,以及其在基础设施中执行关键安全策略的重要用…

node 16位 转24位_同时将24位和32位BMP图像顺时针旋转90度

上一次我们将24位的皮卡丘旋转了90度,但是后来改需求了。。。要求把32位的.bmp文件也能够旋转90度。上次就懵逼的我继续懵逼,只好继续转向CSDN求助。浏览了各种求助帖(还找到了数年前的信科大一学长),终于发现了32位和…

这几个关乎我们一生教养的原则,每个人都应该知道。

▲ 点击查看最近刷到这样两条微博,让人心头一暖。一条是杭州一个小男孩给医院捐款千元,还附上了一封感谢信。临走时还给医生敬了个少先队礼。另一条是扬州一名女孩把自己的小黄鸭储蓄罐整个捐到派出所,留下一张写着“武汉加油”的纸条&#x…

怎么提交 checkbox 表单_8. html form表单

“仅供学习,转载请注明出处”form表单表单用于搜集不同类型的用户输入,表单由不同类型的标签组成,相关标签及属性用法如下:1、标签 定义整体的表单区域action属性 定义表单数据提交地址method属性 定义表单提交的方式,…

越来越多的人不刷朋友圈竟然是因为.....

全世界只有3.14 % 的人关注了爆炸吧知识有些人,生活离不开朋友圈朋友圈是他们展示自我、观察世界的一扇窗户而有些人,从来也不点开朋友圈他们更愿意利用地铁上的零散化时间看点有意义、有知识的公众号推送完成对自我知识库的更新今天为大家推荐以下优质订…

Java基础---变量(三)

简单的说,我们可以把变量看作是个盒子,可以将钥匙、手机、饮料等物品存放在这个盒子中,也可以在需要的时候换成我们想存放的新物品。在 Java 中,我们通过三个元素描述变量:变量类型、变量名以及变量值。如果我们把变量…

腾讯,1000 亿!

聊聊腾讯的开源技术大家好,我是鱼皮,最近一则新闻在公司内外闹得沸沸扬扬,就是下面这个:为了履行企业发展使命,促进高质量发展的共同繁荣,腾讯在投资 500 亿元启动 “可持续社会价值创新” 战略后&#xff…

php mysql 执行sql文件_PHP执行SQL文件并将SQL文件导入到数据库_PHP

//读取文件内容$_sql file_get_contents(test.sql);$_arr explode(;, $_sql);$_mysqli new mysqli(DB_HOST,DB_USER,DB_PASS);if (mysqli_connect_errno()) {exit(连接数据库出错);}//执行sql语句foreach ($_arr as $_value) {$_mysqli->query($_value.;);}$_mysqli->…

What?你还搞不懂什么是物体检测?

全世界只有3.14 % 的人关注了爆炸吧知识计算机视觉在上一个世纪60年代脱胎于人工智能与认知神经科学,并旨在通过设计算法来让计算机自动理解图像的内容。于是为了“解决”这类机器视觉的问题,麻省理工在1966年正式将这个问题作为一个夏季项目&#xff0c…

IIS服务器上增加mp4格式MIME 类型映射设置具体步骤

2019独角兽企业重金招聘Python工程师标准>>> 也许你会在纳闷,为什么我上传了flv或MP4文件到服务器,可输入正确地址通过http协议来访问总是出现“无法找到该页”的404错误呢?这就 表明mp4格式文件是服务器无法识别的,其…

WPAD原理介绍暨故障排查:ISA2006系列之三

WPAD的部署原理暨故障排查<?XML:NAMESPACE PREFIX O />WPAD是Web Proxy Auto Discovery的缩写&#xff0c;意思是Web代理服务器自动发现。WPAD的设计目的是让浏览器能自动发现代理服务器&#xff0c;这样用户可以轻松访问互联网而且无需知道哪台计算机是代理服务器。在…

Web服务器HttpServer(嵌入式设备)

HttpServer是一个轻量级Web服务器&#xff0c;用于在嵌入式设备以及客户端环境中提供简单Web服务。HttpServer支持路由映射到匿名委托、WebApi接口、静态文件&#xff0c;以及具有多个接口的控制器类。从简单到复杂&#xff0c;控制权交给开发者。源码&#xff1a;https://gith…

mysql同时查两张表数据库表_如何同时查询两个数据库表?

展开全部 sql多表关联查询跟条件查询大同小异,主要是要知道表与表之前的关系很重e69da5e6ba9062616964757a686964616f31333431353238要; 举例说明:(某数据库中有3张表分别为:userinfo,dep,sex) userinfo(用户信息表)表中有三个字段分别为:user_di(用户编号),user_name(用…

200万年薪,招不到清华姚班毕业生,能上姚班的都是什么人?

全世界只有3.14 % 的人关注了爆炸吧知识清华姚班可能很多人都没有听说过&#xff0c;不是我们孤陋寡闻&#xff0c;而是姚班确实是不一般的存在。即便是在清华&#xff0c;姚班的学霸也是可以碾压其他学霸的。在清华有一句话&#xff0c;半国英才聚清华&#xff0c;清华半英在姚…

分布式拒绝服务攻击(DDoS)原理及防范

转自:http://www.cnblogs.com/rootq/archive/2009/11/06/1597215.html http://www.ibm.com/developerworks/cn/security/se-ddos/ 2002 年 6 月 01 日 分布式拒绝服务攻击&#xff08;DDoS&#xff09;是目前黑客经常采用而难以防范的攻击手段。本文从概念开始详细介绍了这种攻…