猿来代理模式如此esay~

代理

为什么要使用代理

  1. 简化代码开发,应用场景例如:Spring中的AOP就使用了动态代理的思想,进一步降低了代码的耦合性

  2. 设想这样一个业务需求:现在有5本书为高等数学、线性代数、MySQL是怎么运行的、JAVA并发、图解TCP/IP这5本书,要统计每本书每次被阅读的时间,那么按照框架思想,因为这5本书都属于书类,都需要被阅读,那么可以创建一个Book()抽象类(创建接口统一框架,代理时会发挥作用,这一点很重要),创建一个抽象方法read(),如果编写5个书籍类,分别统计阅读时间,如下图:
    不使用代理

  3. 此时我们会想如果现在有100本书,那么不是得编写100次开始时间和结束时间了?那么此时代理这种设计模式就应运而生了,使我们可以专注编写书中read()的内容(因为每本书的内容不同,所以read()方法中的东西肯定不相同),而将重复的工作交由代理类去做即可,如下图:
    代理模式

  4. 代理的本质是:在不破坏源代码的情况增强其功能,也就是在某个模块上可以不断添加功能而无需改动该模块,降低耦合性,其实我们不单单可以添加开始时间和结束时间,例如我们可以在该类的方法执行前(例如执行read方法前)进行一些配置操作,执行方法完成后(如执行完成read方法后)回收一些资源、关闭IO操作等等,这些操作都是重复的,可以被抽取到方法体外,交由代理类去完成的操作

静态代理

我们可以根据上面内容写出下面的代码,而且我们把在编译阶段就确定代理类的方式称为静态代理

  1. 创建Book抽象类
    Book抽象类

  2. 继承Book抽象类实现其中的MySQL类
    MySQL类

  3. 计算时间
    计算阅读时间

  4. 注意:可能会有读者有疑问为什么要使用抽象类Book:从代码的角度我们可以这样解释,因为要统计各种书籍的阅读时间,因此肯定传入的参数类型是要统一的,即同个抽象类的子类,才能进行传入,这样才能减少代码编写,降低代码耦合性;从逻辑的角度,肯定是对同一类的东西进行统计我们才会去抽取其中重复的代码,将其放在代理类的方法中

动态代理

有了静态代理为什么还要有动态代理

静态代理的缺点:静态代理需要我们在编译阶段就确定代理类和被代理对象,这样其实已经很完美了,但是随着类的种别越来越多(例如需要创建配置和回收资源的代理类、需要创建计算总耗时的代理类),都是不同的类,因此需要创建不同的代理方法,这样就会产生越来越多的代理类,增加代码冗余,此时动态代理就应运而生了!

JDK动态代理

  1. 定义:在运行时动态生成的代理对象,也就是在运行时才去确定要代理的类是什么,例如:统计时间,无论是统计什么类型的时间,需要的是把该类告诉代理类即可,不用考虑该类是什么,从代码的角度也就是去掉了静态代理方法中的参数,这里我习惯把被代理类称为业务类,我们再画个图理解一下:
    动态代理模型

  2. 再重申一下代理(使用于静态和动态代理)的本质是:在不改变源代码的情况下增强其模块功能,那么动态代理则是在静态代理的思想上再进一步,不需要关心该业务类是什么,体现在代码里也就是不用写死代理方法中的参数,直接告诉代理类要被代理类是什么即可

  3. 动态代理在底层是使用反射进行对类中的方法进行调用的(如通过反射调用MySQL类中的read()方法),因为使用反射就可以更加灵活,只需指定类、方法和参数,反射根据条件会自动去找其对应的类中的对应参数方法,而无需写死,这也解释了为什么需要使用反射了

  4. 下面我们通过代码举个例子,这里我们使用了jdk代理模式,其实还有例如cglib的代理模式,以后再把cglib的坑填上~

  5. 演示代码前我们对jdk动态代理进行一些讲解:

    1. jdk动态代理要求被代理类必须实现接口
    2. jdk动态代理使用继承InvocationHandler的类来指定要代理的业务类(也就是被代理对象),在代理方法中通过反射的invoke执行业务方法,而在使用反射调用被代理类方法的前后可以添加一些操作,如调用前配置初始环境,调用后清理数据缓存等,从而增强其被代理类的功能
    3. jdk需要创建代理类,在代理类中传入InvocationHandler和被代理类,传入InvocationHandler是为了在我们调用业务类的方法时,代理类会自动调用invoike方法执行增强后的业务类;而传入被代理类是为了因为动态代理类是在程序运行中生成的,所以需要使用被代理类的类加载器和类接口来加载代理类并且实现该接口方法,然后当调用该方法时,就会跳转到InvocationHandler的invoke方法
    4. 我们可以通过在运行程序中输入该System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")即可在项目根目录的proxy包下看到生成的代理类,代理类的代理方法如下
      生成的代理类中的代理方法
  6. 代码演示:
    创建动态代理
    实现动态代理
    结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值