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…

.NET 6 新特性 WaitAsync

.NET 6 新特性 WaitAsyncIntro在 .NET 6 里新增加了一个 WaitAsync 的方法,用来异步地等待一个任务完成,异步等待的时候可以指定一个 Timeout 时间或者一个取消令牌 CancellationToken,在之前的版本中只有一个同步的 Wait 会等待任务的完成&a…

局域网dos命令集

开启服务命令:net start 服务名信使服务:先开启messenger服务。net send ip "消息文本"局域网dos命令集ls命令是我们常用的几个命令,但是其中有一些很有用的参数我们往往不是很清楚,现在介绍如下: -t -c 按照…

优秀编程网站收录集锦

陆续更新中,敬请关注: 中国开源网:http://www.yuanma.org/ 编程爱好者:http://blog.pfan.cn/vfdff/33993.html 全国嵌入式人才培训基地: http://learn.akae.cn/media/ch21s03.html 转载于:https://www.cnblogs.com/Jessy/archive…

jdbc连接mysql的语法_JDBC连接MySQL

JDBC连接MySQL加载及注册JDBC驱动程序Class.forName("com.mysql.jdbc.Driver");Class.forName("com.mysql.jdbc.Driver").newInstance();JDBC URL定义驱动程序与数据源之间的连接标准语法:::MySQL的JDBCURL格式:jdbc:mysql//[hostna…

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

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

[1197]约瑟夫问题 (循环链表)SDUT

约瑟夫问题 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 n个人想玩残酷的死亡游戏,游戏规则如下: n个人进行编号,分别从1到n,排成一个圈,顺时针从1开始数到m,数到m…

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

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

squid2.6加速WEB支持虚拟主机配置心得体会 .txt

人一台web服务器,日流量约10万,上面有好几个虚拟主机,近日装上Squid 2.6进行WEB加速,Squid 和Apache均在同一台服务器上面,效果非常明显,看到论坛上好多人问如何配置squid2.6支持,虚拟主机现在将安装过程贴…

IT职涯路

在51cto周刊上发现了这篇文章,不错,转载过来~~ 前段时间看了一篇文章,叫做《IT人为什么难以拿高薪》,颇有感触,于是写下这篇文章,希望与各位XDJM共勉~ 能够看到这个帖子的每个XDJM,…

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 服务网格已在各行各业获得广泛的生产应用。该项目的成功,以及其在基础设施中执行关键安全策略的重要用…

mile for gallon 汽车省油

计算汽车省油&#xff0c;用英里每加仑比较&#xff0c;允许重复比较//mile for gallon 汽车省油 #include<iostream>const double GALLON 0.264179; double milepergallon(double kilo,double mile);int main() {using namespace std;double kilo[2],mile[2],milebygal…

使用C#制作简易的注册表编辑器

本文节选自《21天学通C#》一书 下面来实现一个简易的注册表编辑器。它具备了Windows操作系统自带的注册表编辑器的一般功能。如示例代码19-7所示。示例代码19-7主窗体。主窗体在启动时&#xff0c;会在加载事件中加载注册表到树形控件中&#xff0c;就像在Windows操作系统中…

世博游览技巧

世博游览技巧 方案一&#xff1a; 一日进园 步骤1&#xff1a;4:50-5:30到达5号门3号口 07:00开园后最大速度向后面的安检口跑 看到少于30人就可以拿到中国的预约&#xff08;也就是安检的前3排&#xff09; 09:00安检后就会有人发中国的预约券&#xff08;可以不按预约的时间…

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

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

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

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

莫名其妙的主机名 VM_32_234_centos

在腾讯服务器上部署的时候出现的莫名其妙的错误, 我在配置文件上都写 master, node1, 但是运行mapredure的时候的时候老是出现 Job job_1409546978133_0001 failed with state FAILED due to: Application application_1409546978133_0001 failed 2 times due to Error launc…

如何通过提问成为更好的开发人员

如何通过提问成为更好的开发人员这是新的一年的开始&#xff0c;所以我想以一篇我已经计划写了一段时间但从未真正开始创作的帖子开始。我最近开始了一份新工作&#xff0c;加入Elastic[1]&#xff0c;负责开发他们的 .NET 语言客户端。因此&#xff0c;最终将这个主题编写并发…