【经典详解】Spring中的AOP(面向切面编程)

读完这篇AOP博文,你将学到以下内容:

目录

 

1、什么是AOP?

2、AOP底层原理

3、AOP操作术语

4、AOP具体操作

总结:


1、什么是AOP?

  (1)AOP是面向切面编程,是OOP(面向对象编程)的延续。AOP可以对业务的各个部分进行隔离,从而使业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,提高开发的效率。

  (2)通俗的讲:AOP主要作用就是在不修改源代码的前提下,对主干功能进行增强。

    下面是一个登录的功能,现在想在一个登录的情况下,在不修改源代码前提下,添加一个权限功能。

    假如添加功能,AOP可以另外写一个模块,和当前登录模块联系耦合度低,独立性较强。 

2、AOP底层原理

  关于底层原理,Spring5已经对动态代理进行封装,使用的时候只需要简单的配置就可以了

   AOP底层使用的是动态代理模式,有两种情况的动态代理。

   第一种是有接口的情况,使用的是JDK动态代理。第二种是没有接口的情况,使用的是CGLIB动态代理。

     ①有接口,使用JDK的动态代理,还是以UserService、UserDao、UserDaoImpl为例子。

   所谓代理对象,就是被增强对象的代理对象,通过代理对象对功能进行增强。

   创建UserDao接口实现类的代理对象,通过代理对象增强类中的方法,通过代理对象添加一些新的功能,代理UserDaoImpl类,通过代理对象增强实现类UserDaoImpl中的方法,添加一些新的功能。

  

   有接口的实现类,使用JDK动态代理,使用Proxy类里面的方法创建代理对象。

  

newProxyInstance(...)中的参数如下:

(1)ClassLoader loader:类加载器,这个类是当前代理对象所在类

(2)<?>[] interfaces:增强方法所在的类实现的接口,就是增强方法所在的接口,支持多个接口

(3)InvocationHandler h:实现这个接口InvocationHandler,创建代理对象,写增强的方法

编写代码步骤:

  <1>创建接口,定义方法

 <2>创建接口实现类,实现方法

 <3>使用Proxy类创建接口代理对象

每一个类都有Class类的对象,也就是我们编写一个类,在生成class文件后,就会产生一个Class对象,表示这个类的类型信息。一个类获取Class类的方法:

 <1>利用对象调用getClass()方法获取该类对象的Class的实例

 <2>使用Class的静态方法forName(),里面填写类,使用类的名字获取Class类的实例

 <3>使用类名.class方法获取Class的实例

②没有接口,使用CGLIB动态代理,以User为父类,Person为子类。创建动态代理模式

   User子类Person的代理对象,增强子类中方法。

以上是AOP的底层原理,底层原理知道功能是怎么增强的就行。Spring已经对底层做了封装,下面是项目开发中的配置。

3、AOP操作术语

 术语,一般是比较专业的说法。

举例:假如有User类,类中有4个方法。

Class User{
    add();
    update();
    select();
    delete();
}

 AOP共有4个操作术语:

  ①连接点:

  类里面有哪些方法可以被增强,这些方法叫做连接点。

  ②切入点:

  类里面假如有4个方法理论上是可以被增强的,实际上真正被增强的方法称为切入点。

  ③通知(增强):

    (1) 假如增强的是add()方法,想在add方法执行之后做一些其他的操作,实现增强的逻辑就叫做通知。

   举例:在登录过程中增加了权限判断,权限判断的整个过程就叫做通知,增加的部分就叫做逻辑增强。

    (2)通知有很多类型

    *前置通知:@Before,在增强方法之前执行

    *后置通知:@After,所增强方法之后执行

    *环绕通知:@Around,在增强方法的前面后面都做执行

    *异常通知:当增强方法出现异常就会被执行

    *最终通知:相当于异常里面的finally,永远都会被执行

  ④切面

  是一个动作的操作过程,把通知应用到切入点的过程就叫做通知,比如登录过程实现权限操作的过程,权限判断加到登录方法的过程叫做切面。

4、AOP具体操作

   ①Spring框架中一般基于AspectJ具体实现AOP的操作

   AspectJ不是Spring的组成部分,独立于AOP框架,一般把AspectJ和Spring一起使用,方便了AOP的操作。AspectJ是一个面向切面的框架,它扩展了Java语言,Aspect定义了AOP的语法,用编译器用来生成遵守Java字节码规范的class文件。也可以把AspectJ理解成实现AOP操作的工具。

   ②基于AspectJ实现AOP的操作,一般有两种方式:

   <1>基于XML配置方式的实现

   <2>基于注解方式实现(重点掌握)

   虽然现在大部分开发都是使用注解方式进行实现,但是注解方式开发是XML方式演变过来的,注解方式基于XML。

   ③在项目中引入jar包相关依赖

   ④切入点表达式

      <1>作用:设置对类里面哪一个方法进行增强。通俗的讲,就是定位需要增强的点。

      <2>语法结构:execution([权限修饰符][返回类型][类的全路径][方法名称]([参数列表]))

      举例1对com.it.dao.BookDao类里面的add方法进行增强。

      权限修饰符可以用*来代替,类和方法都是通过点(.)进行连接,方法里面的参数使用两个点(..)来代替

      实现:execution(*com.it.dao.BookDao.add(..))

      举例2:对com.it.dao.BookDao类里面的所有方法进行增强。

      权限修饰符可以用*来代替,类和方法都是通过点(.)进行连接,所有方法使用*来代替,方法里面的参数使用两个点(..)来代替

      实现:execution(*com.it.dao.BookDao.*(..))

      举例3:对com.it.dao里面的所有类,类里面的所有方法进行增强

      权限修饰符可以用*来代替,类和方法都是通过点(.)进行连接,所有方法使用*来代替,方法里面的参数使用两个点(..)来代替

      实现:execution(*com.it.dao.*.*(..))

   ⑤通过注解实现AspectJ里面的操作

    首先导包,具体包到  https://search.maven.org/  自行下载

     (1)创建一个User类,对类中的方法进行增强,这个类是被增强的类

     (2)创建增强类,编写增强逻辑。

     在增强类里面创建方法,让不同的方法代表不同的通知类型。

     (3)在spring配置文件中开启注解的扫描,需要配置context空间

     

   (4)使用注解创建User和UserProxy的对象

   

<!-- 开启组件扫描 -->
<context:component-scan base-package="com.test.cn.aopannoation"></context:component-scan>

<!-- 开启AspectJ代理对象扫描 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  (5)在增强类的上面添加注解@Aspect,表示生成类的代理对象

@Aspect
public class UserDaoImpl implements UserDao{
    
}

  (6)在spring配置文件中开启生成代理对象,使用aop的空间

    (7)配置不同类型的通知,在增强类的里面,在作为通知方法上面添加通知方法的注解,使用切入点表达式完成。意思是在通知的上面,添加注解,扫描到后可以确认是哪一个被增强类方法的注解

    在add()方法之前完成方法的增强,后置增强,环绕增强,有异常的话抛出异常。

注意:after是在方法执行之后执行,afterReturning是在实行方法获得方法返回值时候执行。环绕通知里面的参数是切入点(需要增强的方法)

小结:

①配置xml文件中的空间context的扫描创建对象和aop的开启生成代理对象

②在类上面添加注解@Component ,在增强类上添加@Aspect,生成代理对象。代理就是负责对原有的类的方法进行通知的,通过注解切入点表达式指定哪一个方法需要通知。

③测试的时候执行的是被增强类的方法

     (8)相同切入点的抽取,对需要增强的方法进行抽取

    (9)多个增强类对同一个方法进行增强,可以设定增强类的优先级,谁先执行,谁后执行。

      在增强类上面添加注解@Order(数字型类型),数字类型只越小,优先级越高。

     

     (10)完全注解开发

具体看:

https://www.cnblogs.com/coderxiaohei/p/11758239.html

@EnableAspectJAutoProxy(proxyTargetClass = true)是使用的CGLIB代理

@EnableAspectJAutoProxy(proxyTargetClass = false)是使用的jdk动态代理

总结:

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

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 

2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

猜你喜欢

转载自blog.csdn.net/Sunshineoe/article/details/112591386
今日推荐