代理到底是什么?

  • Post author:
  • Post category:其他



大家好,我是本周的值班编辑 江南一点雨 ,本周将由我为大家排版并送出技术干货,大家可以在公众号后台回复“springboot”,获取最新版 Spring Boot2.1.6 视频教程试看。



之前星球的球友面试,问了我一些问题,说让我写一下这个代理,和代理到底是根据什么来进行区分,又该在什么地方使用。这篇文章我细致的讲解一下关于代理的一些问题。

代理分类



  1. 静态代理



  2. 动态搭理

静态代理

我们先说静态代理的实现方式,为什么不推荐使用静态代理?

1.继承方式实现代理(静态代理中的继承代理)






  1. //目标对象







  2. public




    class




    UserImpl




    {










  3. public




    void


    system


    (){










  4. System


    .


    out


    .


    println


    (


    "输出测试"


    );









  5. }







  6. }







  7. //代理对象







  8. public




    class




    Proxy




    extends




    UserImpl




    {










  9. @Override









  10. public




    void


    system


    ()




    {










  11. super


    .


    system


    ();









  12. System


    .


    out


    .


    println


    (


    "增强之后的输出"


    );









  13. }







  14. }







  15. //测试类







  16. public




    class




    TestMain




    {










  17. public




    static




    void


    main


    (


    String


    []


    args


    )




    {










  18. UserImpl


    user


    =




    new




    Proxy


    ();







  19. user


    .


    system


    ();









  20. }







  21. }



静态代理可以看出来一点问题吧?

每次代理都要实现一个类,导致项目中代码很多;你每次想要代理,都要去实现一个类,代码就会成堆的增加,然后你就会发现项目的类就会越来越多,就会导致你们的项目显得很臃肿。而且代码的复用性太低了,并且耦合度非常高,这个我们所说的高内聚低耦合是相悖的。

动态代理

我们在看一下这个动态代理:








  1. //接口类









  2. public




    interface




    Italk




    {










  3. public




    void


    talk


    (


    String


    msg


    );









  4. }









  5. //实现类









  6. public




    class




    People




    implements




    Italk




    {










  7. public




    String


    username


    ;









  8. public




    String


    age


    ;









  9. public




    String


    getName


    ()




    {










  10. return


    username


    ;









  11. }









  12. public




    void


    setName


    (


    String


    name


    )




    {










  13. this


    .


    username


    =


    name


    ;









  14. }









  15. public




    String


    getAge


    ()




    {










  16. return


    age


    ;









  17. }









  18. public




    void


    setAge


    (


    String


    age


    )




    {










  19. this


    .


    age


    =


    age


    ;









  20. }









  21. public




    People


    (


    String


    name1


    ,




    String


    age1


    )




    {










  22. this


    .


    username


    =


    name1


    ;









  23. this


    .


    age


    =


    age1


    ;









  24. }









  25. public




    void


    talk


    (


    String


    msg


    )




    {










  26. System


    .


    out


    .


    println


    (


    msg


    +


    "!你好,我是"


    +


    username


    +


    ",我年龄是"


    +


    age


    );









  27. }









  28. }









  29. //代理类









  30. public




    class




    TalkProxy




    implements




    Italk




    {










  31. Italk


    talker


    ;









  32. public




    TalkProxy




    (


    Italk


    talker


    )




    {










  33. //super();









  34. this


    .


    talker


    =


    talker


    ;









  35. }









  36. public




    void


    talk


    (


    String


    msg


    )




    {








  37. talker


    .


    talk


    (


    msg


    );









  38. }









  39. public




    void


    talk


    (


    String


    msg


    ,


    String


    singname


    )




    {








  40. talker


    .


    talk


    (


    msg


    );







  41. sing


    (


    singname


    );









  42. }









  43. private




    void


    sing


    (


    String


    singname


    ){










  44. System


    .


    out


    .


    println


    (


    "唱歌:"


    +


    singname


    );









  45. }









  46. }









  47. //测试









  48. public




    class




    MyProxyTest




    {










  49. //代理模式









  50. public




    static




    void


    main


    (


    String


    []


    args


    )




    {










  51. //不需要执行额外方法的









  52. Italk


    people1


    =


    new




    People


    (


    "湖海散人"


    ,


    "18"


    );







  53. people1


    .


    talk


    (


    "No ProXY Test"


    );









  54. System


    .


    out


    .


    println


    (


    "-----------------------------"


    );









  55. //需要执行额外方法的









  56. TalkProxy


    talker


    =


    new




    TalkProxy


    (


    people1


    );







  57. talker


    .


    talk


    (


    "ProXY Test"


    ,


    "七里香"


    );









  58. }









  59. }



上面代码解析

一个


Italk


接口,有空的方法


talk


()


(说话),所有的


people


对象都实现(implements)这个接口,实现


talk


()


方法,前端有很多地方都将


people


实例化,执行


talk


方法,后来发现这些前端里有一些除了要说话以外还要唱歌(sing),那么我们既不能在


Italk


接口里增加


sing


()


方法,又不能在每个前端都增加


sing


方法,我们只有增加一个代理类


talkProxy


,这个代理类里实现


talk





sing


方法,然后在需要


sing


方法的客户端调用代理类即可,

这也是实现动态代理的方式,是通过实现(implements)的方式来实现的,这种方法的优点,在编码时,代理逻辑与业务逻辑互相独立,各不影响,没有侵入,没有耦合。

cgLib代理

还有一种是cgLib的代理,这种代理则是适合那些没有接口抽象的类代理,而Java 动态代理适合于那些有接口抽象的类代理。

我们来通过代码了解一下他到底是怎么玩的。






  1. //我们实现一个业务类,不实现任何的接口









  2. /**







  3. * 业务类,







  4. */









  5. public




    class




    TestService




    {










  6. public




    TestService


    ()




    {










  7. System


    .


    out


    .


    println


    (


    "TestService的构造"


    );









  8. }









  9. /**







  10. * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的







  11. */









  12. final




    public




    String


    sayOthers


    (


    String


    name


    )




    {










  13. System


    .


    out


    .


    println


    (


    "TestService:sayOthers>>"


    +


    name


    );









  14. return




    null


    ;









  15. }









  16. public




    void


    sayHello


    ()




    {










  17. System


    .


    out


    .


    println


    (


    "TestService:sayHello"


    );









  18. }









  19. }







  20. /**







  21. * 自定义MethodInterceptor







  22. */







  23. public




    class




    MethodInterceptorTest




    implements




    MethodInterceptor




    {










  24. @Override









  25. public




    Object


    intercept


    (


    Object


    o


    ,




    Method


    method


    ,




    Object


    []


    objects


    ,




    MethodProxy


    methodProxy


    )




    throws




    Throwable




    {










  26. System


    .


    out


    .


    println


    (


    "======插入前置通知======"


    );









  27. Object




    object




    =


    methodProxy


    .


    invokeSuper


    (


    o


    ,


    objects


    );









  28. System


    .


    out


    .


    println


    (


    "======插入后者通知======"


    );









  29. return




    object


    ;









  30. }







  31. }









  32. /**







  33. * 测试







  34. */









  35. public




    class




    Client




    {










  36. public




    static




    void


    main


    (


    String


    []


    args


    )




    {










  37. // 代理类class文件存入本地磁盘方便我们反编译查看源码









  38. System


    .


    setProperty


    (


    DebuggingClassWriter


    .


    DEBUG_LOCATION_PROPERTY


    ,




    "D:\\code"


    );









  39. // 通过CGLIB动态代理获取代理对象的过程









  40. Enhancer


    enhancer


    =




    new




    Enhancer


    ();









  41. // 设置enhancer对象的父类







  42. enhancer


    .


    setSuperclass


    (


    TestService


    .


    class


    );









  43. // 设置enhancer的回调对象









  44. MethodInterceptorTest


    t


    =




    new




    MethodInterceptorTest


    ();







  45. enhancer


    .


    setCallback


    (


    t


    );









  46. // 创建代理对象









  47. TestService


    proxy


    =




    (


    TestService


    )


    enhancer


    .


    create


    ();









  48. // 通过代理对象调用目标方法







  49. proxy


    .


    sayHello


    ();









  50. }









  51. }







  52. 上面代码想要运行,需要


    cglib





    jar





    asm





    jar


    不要忘记找



运行结果






  1. CGLIB debugging enabled


    ,


    writing to


    'D:\code'







  2. TestService


    的构造







  3. ======插入前置通知======







  4. TestService


    :


    sayHello







  5. ======插入后者通知======



实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,

这个接口只有一个intercept()方法,这个方法有4个参数:



  • obj表示增强的对象,即实现这个接口类的一个对象;



  • method表示要被拦截的方法;



  • args表示要被拦截方法的参数;



  • proxy表示要触发父类的方法对象;

代理的使用

那么什么时候使用静态态代理,什么时候使用动态代理和cgLib代理呢?

一般情况静态代理是很少是用的,因为他对代码的复用性或者说是耦合度都非常不友好,不推荐使用。

如果目标对象至少实现了一个接口,那么就用JDK动态代理,所有由目标对象实现的接口将全部都被代理。

如果目标对象没有实现任何接口,就是个类,那么就用CGLIB代理。

我是懿,一个正在被打击还在努力前进的码农。欢迎大家关注我们的公众号,加入我们的知识星球,我们在知识星球中等着你的加入。





往期精彩回顾:



浅谈Java中字符串的初始化及字符串操作类



MyBatis 核心配置综述之 ParameterHandlers



spring 注解编程之注解属性别名与覆盖





分布式下必备神器之分布式锁



640?wx_fmt=jpeg






于加入知识星球的同学提供


基本的福利:


文章有疑问的地方可以提问,其他工作问题都可以提问出来,作者免费作答。


https://t.zsxq.com/Y3fYny7


每周都有大牛分享一些面试题,和面试注意的知识点!




https://t.zsxq.com/2bufE2v



每周由


Java极客技术独家编制的设计模式与大家分享!


https://t.zsxq.com/3bUNbEI


每两周还会分享一个话题,和大家一起成长!


https://t.zsxq.com/BI6Unm2


还有Java极客技术团队亲自录制了一套 Spring Boot 视频,这套视频加密,加密后放到云盘上,下载链接加密之后,一机一码,每个星球的用户一个播放授权码。



我们做知识星球的目的和其他星主一样,就是为了帮助大家一起更好的成长,与高手拉近距离,减少差距,其实你也是高手!

640?wx_fmt=png
640?wx_fmt=jpeg
640?wx_fmt=jpeg
640?wx_fmt=jpeg
640?wx_fmt=jpeg






1000人,50元/每年,现在大约还剩不到300个名额。



长按二维码

640?wx_fmt=png



版权声明:本文为javageektech原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。