• Java的代理:静态代理、JDK/CGLIB的动态代理


        其实所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook,而普通网络无法直接访问,网络代理帮助用户先FQ,然后再访问facebook。这就是代理的作用了。

    静态代理:

    1. public class StaticPxory {
    2. public static void main(String[] args) {
    3. AProxy aProxy = new AProxy(new A1());
    4. aProxy.method();
    5. }
    6. }
    7. interface A{
    8. void method();
    9. }
    10. class A1 implements A{
    11. @Override
    12. public void method() {
    13. System.out.println("A1----------------");
    14. }
    15. }
    16. class AProxy implements A{
    17. private A a;
    18. public AProxy(A a) {
    19. this.a = a;
    20. }
    21. @Override
    22. public void method() {
    23. System.out.println("AProxy----------------start");
    24. a.method();
    25. System.out.println("AProxy----------------end");
    26. }
    27. }
    28. 打印结果:
    29. AProxy----------------start
    30. A1----------------
    31. AProxy----------------end
        在上面的示例中,一个静态代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。   
        在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持。
        如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。
    
    动态代理:
    
    1. public class DynamicProxy {
    2. public static void main(String[] args) {
    3. ProxyHandler proxyHandler = new ProxyHandler(new B1());
    4. B b = (B) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
    5. new Class[]{B.class},
    6. proxyHandler);
    7. b.method();
    8. }
    9. }
    10. interface B{
    11. void method();
    12. }
    13. class B1 implements B{
    14. @Override
    15. public void method() {
    16. System.out.println("B1----------------");
    17. }
    18. }
    19. class ProxyHandler implements InvocationHandler{
    20. private B b;
    21. public ProxyHandler(B b) {
    22. this.b = b;
    23. }
    24. @Override
    25. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    26. System.out.println("start----------------");
    27. method.invoke(b,args);
    28. System.out.println("end----------------");
    29. return null;
    30. }
    31. }
    32. 打印结果:
    33. start----------------
    34. B1----------------
    35. end----------------
        动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。
        纵观静态代理与动态代理,它们都能实现相同的功能,而我们看从静态代理到动态代理的这个过程,
    我们会发现其实动态代理只是对类做了进一步抽象和封装,使其复用性和易用性得到进一步提升而这不仅仅符合了面向对象的设计理念,其中还有AOP的身影,这也提供给我们对类抽象的一种参考。关于动态代理与AOP的关系,个人觉得AOP是一种思想,而动态代理是一种AOP思想的实现!
        JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类,JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。

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

        JDK代理使用的是反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

        JDK创建代理对象效率较高,执行效率较低;

        JDK动态代理机制是委托机制,只能对实现接口的类生成代理,通过反射动态实现接口类;

    2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理

        CGLIB代理使用字节码处理框架asm,对代理对象类的class文件加载进来,通过修改字节码生成子类。

        CGLIB创建代理对象效率较低,执行效率高。

        CGLIB则使用的继承机制,针对类实现代理,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,因为是继承机制,不能代理final修饰的类

    3、使用JDK还是CGLIB

    1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,可以强制使用CGLIB实现AOP
    2)如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    3、强制使用CGLIB实现AOP的方法
    1)添加CGLIB库(aspectjrt-xxx.jar、aspectjweaver-xxx.jar、cglib-nodep-xxx.jar)
    2)在Spring配置文件中加入






     

  • 相关阅读:
    Unittest和Pytest的区别在哪?
    在Springboot HandlerInterceptor中获取GET和POST请求参数
    STL常用算法——查找算法
    刷爆力扣之较大分组的位置
    深度神经网络预测模型,人工神经网络回归分析
    Anaconda + VS Code 的安装与使用
    [极客大挑战 2020]Roamphp2-Myblog - 伪协议+文件上传+(LFI&ZIP)||(LFI&Phar)【***】
    【80天学习完《深入理解计算机系统》】第十六天 4.2 Y86-64的顺序实现
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java小区宠物管理系统k8n96
    网络运维与网络安全 学习笔记2023.11.18
  • 原文地址:https://blog.csdn.net/tianruozhaomi/article/details/125893676