6.1什么是AOP

Aspect Oriented Programming:面向切面编程
什么时候会出现面向切面编程的需求?
按照软件重构的思想,如果多个类中出现重复的代码,就应该考虑定义一个共同的抽象类,将这些共同的代码提取到抽象类中,比如Teacher,Student都有username,那么就可以把username及相关的get、set方法抽取到SysUser中,这种情况,我们称为纵向抽取。

但是如果,我们的情况是以下情况,又该怎么办?
给所有的类方法添加性能检测,事务控制,该怎么抽取?
PerformanceMonitor
TransactionManager
AOP就是希望将这些分散在各个业务逻辑代码中的相同代码,通过横向切割的方式抽取到一个独立的模块中,让业务逻辑类依然保存最初的单纯。

这里写图片描述

抽取出来简单,难点就是如何将这些独立的逻辑融合到业务逻辑中,完成跟原来一样的业务逻辑,这就是AOP解决的主要问题。

6.2 AOP术语

连接点(Joinpoint)
程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强

切点(PointCut)
每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点--数据库的记录,切点--查询条件

增强(Advice)
增强是织入到目标类连接点上的一段程序代码。
在Spring中,像BeforeAdvice等还带有方位信息

目标对象(Target)
需要被加强的业务对象

织入(Weaving)
织入就是将增强添加到对目标类具体连接点上的过程。

代理类(Proxy)
一个类被AOP织入增强后,就产生了一个代理类。

切面(Aspect)
切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。
userBiz(Service) add update del
couseBiz(Service) add update del
定义一个范围 给哪些类的哪些方法
增强:加事务的控制

6.3 AOP实现者

AspectJ
AspectJ是语言级的AOP实现,2001发布,扩展了Java语言,定义了AOP语法,能够在编译期通过提供横切代码的织入,所以它有一个专门的编译器用来生成遵守Java字节码规范的class文件

SpringAOP
SpringAOP使用纯Java实现,在运行期通过代理的方式向目标类织入增强代码。
代理  目标类   增强

6.4 SpringAOP代理机制

1.基于JDK 的动态代理,接口
2.基于CGlib的动态代理,类

6.4.1 什么是代理模式

这里写图片描述

6.4.2静态代理

    目标类:

这里写图片描述

    增强:

这里写图片描述

    代理:

这里写图片描述

    Test(测试):

这里写图片描述

6.4.3动态代理

    关键类:
InvocationHandler:其作用就是将横切逻辑代码和业务逻辑代码编织到一起的编织器。
Proxy则通过newProxyInstance根据handler来创建一个符合第三方接口的代理类基于接口的模式

    目标类:

这里写图片描述

    增强:

这里写图片描述
这里写图片描述

    代理:

这里写图片描述
这里写图片描述

    Test(测试):

这里写图片描述

6.4.4 CGlib动态代理

CGlib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有父类方法的调用,并织入横切逻辑

    导包

这里写图片描述

    目标类:

这里写图片描述

    增强:

这里写图片描述
这里写图片描述

    代理:

这里写图片描述
这里写图片描述

    Test(测试):

这里写图片描述

6.4.5 AOP小结

这种实现方式存在三个明显需要改进的地方:
1.目标类的所有方法都添加了性能监视横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑;

2.我们通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结束前织入代码;

3.我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的创建代码,无法做到通用。

Spring AOP的主要工作就是围绕以上三点展开:Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。此外,Spring通过Advisor(切面)将Pointcut和Advice两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。


6.4.6 JDK和CGlib代理区别

1.静态代理(每来一个 dao,都需要自己手动创建代理对象)
2.jdk动态代理(invocationHandler,proxy.newProxyInsatcn(handle),基于接口)
3.Cglib动态代理(创建子类,methodInterceptor接口,intectpt拦截方法,不能增强嵌套?)      

6.5 创建增强(Advice)

Spring使用增强类定义横切逻辑,同时由于Spring只支持方法连接点,增强还包括了在方法的哪一点加入横切代码的方位信息,所以增强既包含横切逻辑,还包含部分连接点的信息

6.5.1 导包

这里写图片描述
这里写图片描述

6.5.2 增强类型

AOP联盟为增强定义了org.aopalliance.aop.Advice接口,Spring支持5种类型的增强(通知)

前置增强:org.springframework.aop.BeforeAdvice代表前置增强,因为Spring只支持方法级的增强,所以MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强,而BeforeAdvice是为了将来版本扩展需要而定

这里写图片描述

后置增强:org.springframework.aop.AfterReturningAdvice代表后增强,表示在目标方法执行后实施增强;

这里写图片描述

环绕增强:org.aopalliance.intercept.MethodInterceptor代表环绕增强,表示在目标方法执行前后实施增强;

这里写图片描述

异常抛出增强:org.springframework.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强;
注意:异常抛出增强需要自己手写固定格式方法
public void afterThrowing(Method method, Object[] args, Object target, Exception e) throws Throwable {
        System.out.println("method=" + method.getName());
        System.out.println("抛出异常:" + e.getMessage());
        System.out.println("成功回滚事务");
}

这里写图片描述

6.5.3 目标类

这里写图片描述

6.5.4 应用

这里写图片描述

6.6 创建切面(Aspect)

我们可能注意到一个问题:增强被织入到目标类的所有方法中,假设我们希望有选择地织入到目标类某些特定的方法中,就需要使用切点进行目标连接点的定位了。描述连接点是进行AOP编程最主要的工作。
增强提供了连接点方位信息:如织入到方法前面、后面等,而切点进一步描述织入到哪些类的哪些方法上。
Spring通过org.springframework.aop.Pointcut接口描述切点,Pointcut由ClassFilter和MethodMatcher构成,它通过ClassFilter定位到某些特定类上,通过MethodMatcher定位到某些特定方法上,这样Pointcut就拥有了描述某些类的某些特定方法的能力。

Spring使用org.springframework.aop.Advisor接口表示切面的概念,一个切面同时包含横切代码和连接点信息。
从广义上说,增强其实就是一种最简单的切面,它既包括横切代码也包括切点信息,只不过它的切点只是简单的方法相对位置的信息。所以增强一般需要和切点联合才可以表示一个更具实用性的切面。

什么是切面?
包含两个关键信息(切点+增强)

6.7 AspectJ(Annotation)

Spring AOP,它包括基于XML配置的AOP和基于@AspcetJ注解的AOP,这两种方法虽然在配置切面时的表现方式不同,但底层都是采用动态代理技术(JDK代理或CGLib代理)。Spring可以集成AspectJ,但AspectJ本身并不属于Spring AOP的范畴。
Spring在处理@Aspect注解表达式时,需要将Spring的asm模块添加到类路径中。asm是轻量级的字节码处理框架,因为Java的反射机制无法获取入参名,Spring就利用asm处理@AspectJ中所描述的方法入参名。

6.7.1 导包

这里写图片描述
这里写图片描述

6.7.2 增强类型

    @Before
前置增强,相当于BeforeAdvice的功能

    @AfterReturning
后置增强,相当于AfterReturningAdvice

    @Around
环绕增强,相当于MethodInterceptor

    @AfterThrowing
抛出增强,相当于ThrowsAdvice

    @After
Final增强,不管是抛出异常或者是正常退出,该增强都会得到执行,该增强没有对应的增强接口,可以把它看成ThrowsAdvice和AfterReturningAdvice的混合物,一般用于释放资源,相当于try{}finally{} 

    环绕增强
    ProceedingJoinPoint
    proceed 

这里写图片描述

6.7.3 目标类

这里写图片描述

6.7.4 应用

这里写图片描述

6.7.5 扩展(切点表达式函数)

AspectJ 5的切点表达式由关键字和操作参数组成,如execution(* add(..))的切点表达式,execution为关键字,而“* add(..)”为操作参数。

常见案例:
execution(public * *(..))
匹配所有目标类的public方法,第一个*代表返回类型;第二个*代表方法名;而..代表任意入参的方法;

execution(* *To(..))
匹配目标类所有以To为后缀的方法。第一个*代表返回类型;而*To代表任意以To为后缀的方法。

execution(* com.dream.IUserDao.*(..))
匹配IUserDao接口的所有方法,第一个*代表返回任意类型;com.dream.IUserDao.*代表IUserDao接口中的所有方法

execution(*com.dream.*(..))
匹配com. dream包下所有类的所有方法;

6.8 AspectJ(Xml)

6.8.1 导包

这里写图片描述
这里写图片描述

6.8.2 增强

这里写图片描述

6.8.3 目标类

这里写图片描述

6.8.4 配置applicationContext.xml

这里写图片描述

6.8.5 应用

这里写图片描述

Logo

Authing 是一款以开发者为中心的全场景身份云产品,集成了所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务

更多推荐