详讲Spring的面向切片编程(AOP)二
作者:mmseoamin日期:2024-03-20

详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第1张


个人名片:

详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第2张


🐼作者简介:一名大三在校生,喜欢AI编程🎋

🐻‍❄️个人主页🥇:落798.

🐼个人WeChat:hmmwx53

🕊️系列专栏:🖼️

  • 零基础学Java——小白入门必备🔥
  • 重识C语言——复习回顾🔥
  • 计算机网络体系———深度详讲
  • HCIP数通工程师-刷题与实战🔥🔥🔥
  • 微信小程序开发——实战开发🔥
  • HarmonyOS 4.0 应用开发实战——实战开发🔥🔥🔥
  • Redis快速入门到精通——实战开发🔥🔥🔥
  • RabbitMQ快速入门🔥

    🐓每日一句:🍭我很忙,但我要忙的有意义!

    欢迎评论 💬点赞👍🏻 收藏 📂加关注+



文章目录

    • 面向切面:AOP
      • 5.1、场景模拟
        • 5.1.1、声明接口
        • 5.1.2、创建实现类
        • 5.1.3、创建带日志功能的实现类
        • 5.1.4、提出问题
        • 5.2、代理模式
          • 5.2.1、概念
          • 5.2.2、静态代理
          • 5.2.3、动态代理
          • 5.2.4、测试
          • 写在后面🔥🔥🔥:
          • 欢迎添加微信,加入我的核心小队,请备注来意

            面向切面:AOP

            5.1、场景模拟

            搭建子模块:spring6-aop

            5.1.1、声明接口

            声明计算器接口Calculator,包含加减乘除的抽象方法

            public interface Calculator {
                
                int add(int i, int j);
                
                int sub(int i, int j);
                
                int mul(int i, int j);
                
                int div(int i, int j);
                
            }
            
            5.1.2、创建实现类

            详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第3张

            public class CalculatorImpl implements Calculator {
                
                @Override
                public int add(int i, int j) {
                
                    int result = i + j;
                
                    System.out.println("方法内部 result = " + result);
                
                    return result;
                }
                
                @Override
                public int sub(int i, int j) {
                
                    int result = i - j;
                
                    System.out.println("方法内部 result = " + result);
                
                    return result;
                }
                
                @Override
                public int mul(int i, int j) {
                
                    int result = i * j;
                
                    System.out.println("方法内部 result = " + result);
                
                    return result;
                }
                
                @Override
                public int div(int i, int j) {
                
                    int result = i / j;
                
                    System.out.println("方法内部 result = " + result);
                
                    return result;
                }
            }
            
            5.1.3、创建带日志功能的实现类

            详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第4张

            public class CalculatorLogImpl implements Calculator {
                
                @Override
                public int add(int i, int j) {
                
                    System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
                
                    int result = i + j;
                
                    System.out.println("方法内部 result = " + result);
                
                    System.out.println("[日志] add 方法结束了,结果是:" + result);
                
                    return result;
                }
                
                @Override
                public int sub(int i, int j) {
                
                    System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);
                
                    int result = i - j;
                
                    System.out.println("方法内部 result = " + result);
                
                    System.out.println("[日志] sub 方法结束了,结果是:" + result);
                
                    return result;
                }
                
                @Override
                public int mul(int i, int j) {
                
                    System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);
                
                    int result = i * j;
                
                    System.out.println("方法内部 result = " + result);
                
                    System.out.println("[日志] mul 方法结束了,结果是:" + result);
                
                    return result;
                }
                
                @Override
                public int div(int i, int j) {
                
                    System.out.println("[日志] div 方法开始了,参数是:" + i + "," + j);
                
                    int result = i / j;
                
                    System.out.println("方法内部 result = " + result);
                
                    System.out.println("[日志] div 方法结束了,结果是:" + result);
                
                    return result;
                }
            }
            
            5.1.4、提出问题

            ①现有代码缺陷

            针对带日志功能的实现类,我们发现有如下缺陷:

            • 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
            • 附加功能分散在各个业务功能方法中,不利于统一维护

              ②解决思路

              解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。

              ③困难

              解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。

              5.2、代理模式

              5.2.1、概念

              ①介绍

              二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

              详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第5张

              使用代理后:

              详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第6张

              ②生活中的代理

              • 广告商找大明星拍广告需要经过经纪人
              • 合作伙伴找大老板谈合作要约见面时间需要经过秘书
              • 房产中介是买卖双方的代理

                ③相关术语

                • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
                • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。
                  5.2.2、静态代理

                  创建静态代理类:

                  public class CalculatorStaticProxy implements Calculator {
                      
                      // 将被代理的目标对象声明为成员变量
                      private Calculator target;
                      
                      public CalculatorStaticProxy(Calculator target) {
                          this.target = target;
                      }
                      
                      @Override
                      public int add(int i, int j) {
                      
                          // 附加功能由代理类中的代理方法来实现
                          System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
                      
                          // 通过目标对象来实现核心业务逻辑
                          int addResult = target.add(i, j);
                      
                          System.out.println("[日志] add 方法结束了,结果是:" + addResult);
                      
                          return addResult;
                      }
                  }
                  

                  静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。

                  提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

                  5.2.3、动态代理

                  详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第7张

                  生产代理对象的工厂类:

                  public class ProxyFactory {
                      private Object target;
                      public ProxyFactory(Object target) {
                          this.target = target;
                      }
                      public Object getProxy(){
                          /**
                           * newProxyInstance():创建一个代理实例
                           * 其中有三个参数:
                           * 1、classLoader:加载动态生成的代理类的类加载器
                           * 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
                           * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
                           */
                          ClassLoader classLoader = target.getClass().getClassLoader();
                          Class[] interfaces = target.getClass().getInterfaces();
                          InvocationHandler invocationHandler = new InvocationHandler() {
                              @Override
                              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                  /**
                                   * proxy:代理对象
                                   * method:代理对象需要实现的方法,即其中需要重写的方法
                                   * args:method所对应方法的参数
                                   */
                                  Object result = null;
                                  try {
                                      System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                                      result = method.invoke(target, args);
                                      System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                                  } catch (Exception e) {
                                      e.printStackTrace();
                                      System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                                  } finally {
                                      System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                                  }
                                  return result;
                              }
                          };
                          return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
                      }
                  }
                  
                  5.2.4、测试
                  @Test
                  public void testDynamicProxy(){
                      ProxyFactory factory = new ProxyFactory(new CalculatorLogImpl());
                      Calculator proxy = (Calculator) factory.getProxy();
                      proxy.div(1,0);
                      //proxy.div(1,1);
                  }
                  

                  写在后面🔥🔥🔥:

                  林纳斯·托瓦兹(Linus Torvalds)说:“我从心底认为,优秀的程序员与平庸的程序员之间的区别,是在于认为自己的代码重要还是数据结构更加重要。平庸的程序员眼里只有代码,优秀的程序员则关注数据结构及之前的关系。”

                  《spring技术内幕:深入解析spring架构与计原理(第2版)》是国内一本系统分析spring源代码的经典著作,也是spring领域的问鼎之作,由业界拥有10余年开发经验的资深java专家亲自执笔,java开发者社区和spring开发者社区联袂推荐。本书第1版不仅在内容上获得了读者的广泛好评,而且在销量上也摘取了同类书的桂冠,曾经一度掀起java类图书的销售热潮。第2版不仅继承了第1版在内容组织和写作方式上的优点,而且还根据广大读者的反馈改进了若干细节上的不足。更为重要的是,结合spring的最新版本对过时的内容进行了更新,并增加了大量新内容,使本书更趋近于完美。

                  本专栏是自己深入学习并结合Spring技术内幕一经典图书内容做出的的心得与总结,将其精简编写成一篇专栏供大家学习,希望对新学习Spring框架技术的小伙伴有所帮助。

                  图书推荐:

                  详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第8张


                  详讲Spring的面向切片编程(AOP)二,在这里插入图片描述,第9张

                  欢迎添加微信,加入我的核心小队,请备注来意

                  👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇