zoukankan      html  css  js  c++  java
  • (五)Spring 中的 aop

    目录


    AOP概念

    1. 浅理解 aop :面向切面编程,扩展功能不需要修改程序源代码 ;

    2. 深度理解 aop:采取了 横向抽取机制 ,取代了传统 纵向继承体系 复杂性代码 ;

      概念看完,不一定懂,aop 到底是怎么完成不修改源代码,,而进行功能扩展的 ;
      
      往下看 原理 ;
      

    AOP原理

    1. 传统的 纵向继承体系

      这里写图片描述

      想要对功能进行扩展,最原始的做法是:修改源代码,在源代码上直接添加功能代码;但是,这样做,会产生了一个 问题假如有几个方法,都要增加一个相同的功能,就务必会有重复性代码的产生

      后来有人想到了 纵向继承体系,就像图中的那样,要增强功能的时候,写一个基类,然后让要扩展的类,继承基类,达到扩展功能的目的 ;这样解决了重复代码的问题,但是还有问题,就是扩展类和基类绑定在一起了,耦合高,只要基类方法改名字,要扩展的类,就得相应的改名字 ;

    2. aop 的横向抽取一(有接口 JDK动态代理

      这里写图片描述

      Springaop 底层是使用 动态代理 实现的 ;动态代理 分为2中,有接口、无接口 ;

    3. aop 的横向抽取二(没有接口 cglib

      这里写图片描述

      动态代理 怎么操作的,这里不讲,这里主要表达 aop 底层是 动态代理


    AOP术语

    1. Joinpoint(连接点)

      官方解释:就是那些被拦截到的点,在 Spring 中这些点就是 方法,因为 spring 只支持方法类型的连接点 ;

      大白话:就是类里面,可以 被增强的方法 ;

    2. Pointcut(切入点)

      官方解释:对连接点进行拦截的定义 ;

      大白话:类中 实际 被增强的方法 ;

    3. Advice(通知、增强)

      官方解释:拦截到连接点以后,要做的事;通知分为:前置通知、后置通知、异常通知、最终通知、环绕通 重点内容`(切面要完成的功能)

      大白话:实际要扩展的功能 ;

      前置通知:在原方法执行之前,进行功能的扩展 ;
      后置通知:在原方法执行之后,进行功能的扩展 ;
      异常通知:在方法出现异常的还是,进行功能的扩展 ;
      最终通知:在 后置通知 之后,进行功能的扩展 ;
      环绕通知:在方法之前和之后,都进行功能的扩展 ;

    4. Introduction(引介)

      是一种特殊的通知,在不修改类代码的前提下,Introduction 可以在运行期为类动态的添加一些方法或者字段 ;

    5. Target(目标对象)

      代理的目标对象,即要增强的类 ;

    6. Weaving(植入)

      把要增强应用到目标的过程 ;

    7. Proxy(代理)

      一个类被 AOP 植入增强以后,就会产生一个代理类 ;

    8. Aspect(切面)

      官方解释:切入点和通知(引介)的结合;

      大白话:把扩展的功能,应用到要增强的方法上的过程 ;


    Spring 中的 aop 的操作

    AspectJ 框架

    • Aspect 是一个面向切面的框架(不是 Spring 里面的,是一个独立的框架,可以和Spring搭配使用),它扩展了 java 语言。AspectJ 定义了AOP语法,所以它有一个专门的编译器用来生成遵守java字节编码规范的Class文件 ;
    • AspectJ 是一个基于java语言的AOP框架;
    • Spring2.0 以后新增了对 AspectJ 切点表达式支持;
    • @AspectJAspectJ 1.5 新增功能,通过 JDK 注解技术,允许直接在 Bean 类中定义切面 ;
    • 新版本 Spring 框架,建议使用 AspectJ 方式来开发 AOP
    • 使用 AspectJ 需要导入 Spring aopAspectJ 相关的 jar 包 ;

    使用 AspectJ 实现 aop 的两种方式

    1. 基于 AspectJ 的配置方式

      1. 导包

        除了 Spring-aop 的包,还需要 AspectJaopalliance-1.0、aspectjweaver-1.8.11 两个包 ;

      2. 配置文件添加新的约束

        添加 aop 的相关约束

          xmlns:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation=
           "http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"
        
      3. 使用表达式配置切入点

        常用表达式:execution(<访问修饰符>?<返回类型><方法名>(参数)<异常>

        例如:

        写法: execution* +空格 +方法名全路径

        
        // 匹配 包路径xin.ijava.aop 下面的 Book 类的 add()方法
        
        // * 表示任意都匹配 写在这里匹配保护:public、private、abstract 
        // add(..) 表示匹配由于参数都行
        execution(* xin.ijava.aop.Book.add(..))
        
        -------------------------------------
        // 匹配 包路径xin.ijava.aop 下面的 Book 类的 所有方法
        execution(* xin.ijava.aop.Book.*(..)
        
        -------------------------------------
        // 匹配 包路径xin.ijava.aop 下面的所有方法(不包含子包)
        execution(* xin.ijava.aop.*(..)
        
        -------------------------------------
        // 匹配 包路径xin.ijava.aop 下面的所有方法(包含子包)
        execution(* xin.ijava.aop..*(..)
        
        
        -------------------------------------
        // 匹配 任意包路径下面的任意类的任意方法
        execution(* *.*(..)
        
        -------------------------------------
        // 匹配 所有以 add 开头的方法
        execution(* add*..)
        
        -------------------------------------
        // 匹配 实现特定接口(xin.ijava.aop.dao)的所有类方法
        execution(* xin.ijava.aop.dao+*..)
        
        
        
      4. 在配置文件中配置切入点

        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="bookPointCut" expression="execution(* ijava.xin.aop.Book.*(..))"/>
        
            <!--配置切面-->
            <!--ref 中是 增强对象,不是要增强的对象-->
            <aop:aspect ref="bookAdvice">
                <!--前置通知-->
                <aop:before method="beforeAdd" pointcut-ref="bookPointCut"></aop:before>
            </aop:aspect>
        
        </aop:config>
        
      5. 环绕通知

        环绕通知和其他通知,有点不一样
        

        增强对象中,环绕通知方法 的代码:

        	  /**
        	     * 环绕通知
        	     * @param proceedingJoinPoint 参数
        	     */
            public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        	        System.out.println("前置通知..");
        
        			//        调用增强的方法
        			        proceedingJoinPoint.proceed() ;
        
                System.out.println("后置通知..");
        
            }
        

    2. 基于 AspectJ 的注解方式

      1. Spring 配置文件 中开启 AOP 自动代理

        <!--开启aop自动代理-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        
      2. 然后在增强类上面写一个 @Aspect 注解 ;

      3. 在要增强类的增强方法上写注解,配置切入点

      @Component("bookAdvice")
      		@Aspect
      		public class BookAdvice {
      	
      		    @Before(value = "execution(* ijava.xin.aop.Book.*(..))")
      		    public void beforeAdd(){
      		        System.out.println("前置通知..");
      		    }
      		    /**
      		     * 环绕通知
      		     * @param proceedingJoinPoint 参数
      		     */
      		    @Around(value = "execution(* *.*(..))")
      		    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      	        System.out.println("前置通知1..");
      	
      			//        调用增强的方法
      			        proceedingJoinPoint.proceed() ;
      		
      			        System.out.println("后置通知1..");
      		
      			    }
      			   }
      

    border="0" src="//music.163.com/outchain/player?type=2&id=1297001123&auto=1&height=66" width="1" height="0">
  • 相关阅读:
    docker学习笔记(2)——docker常用命令
    docker学习笔记(1)——ubuntu16.04安装docker(含如何彻底卸载docker,docker拉取镜像失败解决)
    近期计划随笔
    程序员的自我修养:链接、装载与库(一本书,估计没时间看。。。哭。。。)
    str.format 学习
    pyqt5 线程 (QThread)启动、挂起、恢复、终止问题见解
    pyqt5 在非主线程(QThread线程)中实现弹窗QMessageBox
    807 · 回文数 II
    1334 · 旋转数组
    297 · 寻找最大值
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665688.html
Copyright © 2011-2022 走看看