设计模式10--代理模式

   代理是在我们日常开发中遇到的比较多的场景,虽然你可能自己在代码中不太常用代理,但是Spring里面很多的功能的实现都依托了代理,并且面试的时候面试官特别喜欢问这个问题。跟代理相关的包含了代理模式,静态代理,动态代理,正向代理,反向代理 。本篇文章主要将设计模式中的代理模式,内容来自于网络,我只是做一个收录整理,以便用时翻阅。

                                                               

1.代理模式的定义

       为其他对象提供一种代理,以控制对这个对象的访问,补充:代理对象在客户端和目标对象之间起到一个中介的作用。类型:结构型。

2.适用场景

  •  保护目标对象
  • 增强目标对象

3.代理模式的优点:

  •   代理模式能将代理对象与真实被调动用的目标对象分离
  •   一定程度上降低了系统的耦合度,扩展性好
  •   保护目标对象 、
  •  增强目标对象

4 .代理模式的缺点:

  •     静态代理对造成系统中类的数量增加
  •     客户端和目标对象之间增加代理类可能导致请求变慢
  •     增加系统的复杂度    

5.JDK动态代理与CGLIB动态代理

      JDK的动态代理是生成一个新类,利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

 代理类的生成是先通过生成代理的Class对象,然后利用反射生成代理对象,同时将InvocationHanlder作为构造参数传入。生成的代理类就是这样的:

 

      那么JDK动态代理是如何找到目标对象的?

      很明显了在代理类中,调用this.h.invoke方法,this就是代理类&Proxy0,h就是构造函数传进来的InvocationHanlder,然后调用invoke方法,invoke方法恰好是我们已经实现的,所以会调用到我们的invoke的实现类里面去,在 InvocationHanlder的invoke方法里面,就会调用到目标类的业务方法。

 

      

      CGLIB是生成一个子类,他的业务逻辑是通过调用超类的方法生成的。使用CGLIB的时候一定要注意final这个修饰符,实现的原理是利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

     当目标类的有实现接口的时候,可以使用JDK的动态代理,也可以使用CGLIB,当目标类没有实现接口的时候,只能使用CGLIB

     整个过程相比jdk动态代理简单了一些。不同的是JDK动态代理强制要求实现类必须最少实现一个接口,但是CGLIB则可以要求实现类不用实现任何接口。CGLIB动态生成的代理类会继承我们的业务类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。CGLIB是高效的代码生成包,底层依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。

代理类对象是由Enhancer类创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展

通过操作字节码的技术生成的代理类,生成的代理类会先调用拦截器的方法,再调用业务类的方法

   

   ​​​​​​​

 

       cglib里面是通过索引找到目标方法的。

   动态代理类根据我们业务类的每一个方法都生成了2个代理方法,第一个代理方法直接调用父类的方法,也就是我们业务类的方法,第二个方法也就是代理类真正调用的方法是经过封装的,他会去判断是否实现了MethodInterceptor 的intercept方法,如果实现了则会调用intercept方法。这个MethodInterceptor 就是我们在enhancer.setCallback(new UserMethodInterceptor());这边设置进去的。

   初始化完成后调用fci.f2.invoke(fci.i2, obj, args);方法。这个方法很像反射方法,其实它并不是通过反射找到指定的方法的,而是在创建代理类的时候为其中的方法建立hash索引,这样调用的时候通过索引调用提高了效率。

 

 6.Spring AOP里面的代理选择

    在最新版的 Spring 中,依然是如上策略不变。即能用 JDK 做动态代理就用 JDK,不能用 JDK 做动态代理就用 Cglib,即首选 JDK 做动态代理。    

 如果想指定,则:

但是在SpringBoot2.0之后,这个策略变了,Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。

spring.aop.proxy-target-class=false

我们可以在SpringBoot2.0中来验证这一点。

静态代理模式的实现

设计模式之禅学习笔记08--代理模式_时空恋旅人的博客-CSDN博客

JDK动态代理模式的实现

设计模式之禅学习笔记09--代理模式(动态代理)_时空恋旅人的博客-CSDN博客

CGLIB动态代理的实现

java基础--19动态代理_时空恋旅人的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值