5.1 Spring5源码--Spring AOP源码分析一

目标:

1.什么是AOP,什么是AspectJ,

2. 什么是Spring AOP

3. Spring AOP注解版实现原理

4. Spring AOP切面原理解析

 一. 认识AOP

1.1 什么是AOP

aop是面向切面编程,相比传统oop,aop能够在方法的前置,中置,后置中插入逻辑代码,对于项目中大量逻辑重复的代码,使用aop能很好的收口逻辑,将逻辑独立于业务代码之外,一处编写,多处使用。

AOP是Object Oriented Programming(OOP)的补充.

OOP能够很好地解决对象的数据和封装的问题,却不能很好的解决Aspect("方面")分离的问题。下面举例具体说明。

比如,我们有一个Bank(银行)类。Bank有两个方法,save(存钱)和withdraw(取钱)。

类和方法的定义如下:

package com.lxl.www.aop;

public class Bank {

  /**
   * 存钱
   */
  public Float save(Account account,float money) {
    // 增加account账户的钱数,返回账户里当前的钱数
    return null;
  }

  *
   * 取钱
   public Float withdraw(Account account,1)"> 减少account账户的钱数,返回取出的钱数
    ;
  }
};

 

这两个方法涉及到用户的账户资金等重要信息,必须要非常小心,所以编写完上面的商业逻辑之后,项目负责人又提出了新的要求--给Bank类的每个重要方法加上安全认证特性。

于是,我们在两个方法上增加安全代码

改后的类和方法如下:

 Bank {

  *
   * 存钱
   */
   money) {
    // 验证account是否为合法用户
    // 增加account账户的钱数,返回账户里当前的钱数
    ;
  }

  *
   * 取钱
    money) {
    // 验证account是否为合法用户
    // 减少account账户的钱数,返回取出的钱数
    ;
  }
};

 

这两个方法都需要操作数据库,为了保持数据完整性,项目负责人又提出了新的要求--给Bank类的每个操作数据库的方法加上事务控制。

于是,我们不得不分别在上面的两个方法中加入安全认证的代码。

类和方法的定义如下:

 验证account是否为合法用户
     begin Transaction
     增加account账户的钱数,返回账户里当前的钱数
     end Transaction
    取钱
    减少account账户的钱数,返回取出的钱数
    // end Transaction 
    ;
  }
};

 

我们看到,这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?

AOP就是为了解决这种问题而出现的。在不修改代码的情况下达到增强的效果

1.2 AOP的相关概念

  • 切面(Aspect): 封装通用业务逻辑的组件,即我们想要插入的代码内容. 在spring AOP中,切面可以使用通用类基于模式的方式,或者在普通类中标注@Aspect注解来实现
  • 连接点(Join point): 连接点是在应用执行过程中能够插入切面的点。简单理解,可以理解为需要增强的方法.
  • 通知(Advice): 用于指定具体产生作用的位置,是方法之前或之后等等
    • 前置通知(before) - 在目标方法被调用之前调用通知功能
    • 后置通知(after) - 在目标方法完成之后调用通知(不论程序是否出现异常),此时不会关心方法的输出是什么
    • 返回通知(after-returning) - 在目标方法成功执行之后调用通知
    • 异常通知(after-throwing) - 在目标方法抛出异常后调用通知
    • 环绕通知(around) - 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
  • 目标对象(target): 目标对象是指要被增强的对象,即包含主业务逻辑的类对象
  • 切点(PointCut): 指定哪些Bean组件的哪些方法使用切面组件. 例如:当执行某个特定名称的方法时.我们定义一个切点(execution com.lxl.www.aop.*.*(..)) . 切点表达式如何和连接点匹配是AOP的核心. spring默认使用AspectJ切点语义.
  • 织入(Weaving): 将通知切入连接点过程叫做织入
  • 引入(Introductions): 可以将其它接口或者实现动态引入到targetClass中

对照上图,来对应每一个区域,看看其具体含义

 

 

那么在Spring中使用AOP就意味着你需要哪些东西呢?我们来举个例子,就实现上面银行的例子.
  • 首先有一个bank银行类
    package com.lxl.www.aop.bank;
    
    interface Bank {
    
      */
      Float save(Account account, money) ;
    
      
      Float withdraw(Account account,1)"> money);
    };

     

     

  • 有一个银行类的实现方法. 这里面save,withdraw就是连接点. 最终会将各种通知插入到连接点中
    package com.lxl.www.aop.bank;
    
    import org.springframework.stereotype.Service;
    
    *
     * 工商银行
     *
     *
     * DATE 2020/12/6.
     *
     * @author lxl.
     
    @Service
     IcbcBank implements Bank{
        @Override
        public Float save(Account account,1)">float money) {
    // 主业务逻辑: 增加account账户的钱数,返回账户里当前的钱数 System.out.println(account.getName() + "账户存入" + money); ; } @Override public Float withdraw(Account account,1)"> 主业务逻辑: 减少account账户的钱数,返回取出的钱数 System.账户取出; } }

     

     

  • 接下来,要有一个切面,切面是一个类. 切面类里面定义了切点,通知,引用
    package com.lxl.www.aop.bank;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    *
     * 切面
     
    @Aspect  标记这是一个切面
    @Order
    @Component  将其放到ioc容器管理
     BankLogAspect {
    
      引入
       *
       * 这段话可以理解为,为com.lxl.www.aop.bank.IcbcBank 引入了一个接口 EnhanceFunctionOfBank,* 同时,引入了默认的实现类 IcbcEnhanceFunctionOfBank
       
      @DeclareParents(value = com.lxl.www.aop.bank.IcbcBank",1)"> 引入的目标类. 也就是需要引入动态实现的类
              defaultImpl = IcbcEnhanceFunctionOfBank.class)  引入的接口的默认实现
      static EnhanceFunctionOfBank enhanceFunctionOfBank;  引入的接口
    
    
      *
       * 定义一个切点
       
      @Pointcut(execution(* com.lxl.www.aop.bank.IcbcBank.*(..))")
      void pointCut() {}
    
      前置通知
       * @param joinPoint
       
      @Before(value = pointCut() beforeAdvice(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println(执行目标方法"+methodName+的前置通知);
      }
    
      *
       * 定义了一个后置通知
       
      @After(value =  afterAdvice(JoinPoint joinPoint) {
        String methodName =的后置通知返回通知
       
      @AfterReturning(value = result returningAdvice(JoinPoint joinPoint,Object result) {
        String methodName =的返回通知异常通知
       
      @AfterThrowing(value =  throwingAdvice(JoinPoint joinPoint) {
        String methodName =的异常通知);
      }
    
    }

    那么这里的目标对象是谁呢? 就是我们的IcbcBank类. 这里需要注意的是引入: 引入的概念是将一个接口动态的让另一个类实现了. 这样实现了接口的类,就可以动态的拥有接口实现类的功能.

  • 银行的额外功能. 也就是银行除了可以存钱,取钱. 还有一个额外的功能. 比如理财. 不是每个银行都有的. 
    *
     * 增强的功能
     */
     EnhanceFunctionOfBank {
    
         Financialanagement(Account account);
    }

     

  • 具体银行额外功能的实现类
    *
     * Description
      IcbcEnhanceFunctionOfBank implements EnhanceFunctionOfBank {
        *
         * 理财功能
         * @param account
         
        @Override
         Financialanagement(Account account) {
            System.out.println(account.getName() +的账户 增加 理财功能);
        }
    
    }

    这个功能我们可以通过引入,动态增加到IcbcBank类中,原本IcbcBank只有存钱和取钱的功能. 这样,就可以增加理财功能了. 这就是引入.

  • 整体配置类
    package com.lxl.www.aop.bank;
    
    import org.springframework.beans.factory.annotation.Configurable;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configurable
    // 使用注解的方式引入AOP
    @EnableAspectJAutoProxy
    @ComponentScan(com.lxl.www.aop.bank)
     BankMainConfig {
    
    }

     

    使用aop,需要引入AOP,这里使用的注解的方式引入的.

  • main入口方法
    package com.lxl.www.aop.bank;
    
    import com.lxl.www.aop.Calculate;
    import com.lxl.www.aop.MainConfig;
    import com.lxl.www.aop.ProgramCalculate;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
     BankMainClass {
      static  main(String[] args) {
    
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankMainConfig.);
    
        Account account = new Account(张三);
    
        Bank bank = (Bank) ctx.getBean(icbcBank);
        bank.save(account,100);
    
        System.out.println();
        EnhanceFunctionOfBank enhanceFunctionOfBank = (EnhanceFunctionOfBank) ctx.getBean();
        enhanceFunctionOfBank.Financialanagement(account);
      }
    }

    如上,运行结果:

        

 

  • 需要注意的地方: 是.gradle配置文件. 通常,我们在引入AspectJ的jar包的时候,会引入到父类项目的build.gradle中. 如下所示

     

    最后我们还需要引入到指定的项目中 

       

 

以上就是对整个AOP的理解. 接下来,分析AOP的源码.

详见第二篇文章

 

 

 

 

 

 

 

 

 

 

 

as

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下