Spring AOP(一)核心概念

465 阅读5分钟

Spring AOP(一)核心概念

spring的两大核心IOC和AOP,对于IOC在项目中会经常使用,但是对于AOP虽然每个人都用到过,但是不一定都会有自己动手来写AOP的实践,在近期的项目中有使用AOP的场景,刚好借此机会将AOP部分的知识记录下来巩固加深。特意写这篇文章来记录下AOP使用的一些感受。

核心概念

在学习AOP之前需要先知道什么是AOP,对于AOP的概念就不多余啰嗦了,网上资料很多这里就着重讲一下自己对于AOP的理解,AOP即面向切面编程,那么应该怎么理解面向切面编程呢。

举个列子我们在公司中会有很多业务部门,各个业务部门处理自己的业务,我们可以将业务部门理解为纵向的多条线,那在公司中也有一些部门他们不属于业务部门,但是他们的职能是管理一些人力等其他工作,我们一般叫做职能部,职能部的一些工作就像一把切刀一样,横向的插入所有业务部,来完成职能部的工作。这里的职能部我们就可以理解为面向切面编程的切面。 图片1.png 回到程序中来讲,面向切面编程就是当我们在项目中遇到一些可以为其他业务模块共同服务的功能时,这些功能又不属于我们自己的业务功能,我们可以将这部分代码抽离出来来为这些业务代码服务,这样我们就可以再不改动业务代码的前提下,进行新功能的开发后期如果不需要这样的功能或者需要修改的时候,我们也可以再不改动业务代码的前提下进行代码改动减少风险。最常见的场景就是在一个现有项目中要追加一些跟踪日志,那么AOP会是很好的一个实现方式。我们可以通过声明一个日志切面。然后只要在切面中指定需要在那些地方进行日志处理,以及处理的逻辑,那么我们就可以实现不修改当前代码的前提下,添加日志跟踪的需求,讲了这么多我们接下来看一下AOP中几个核心概念。 图片2.png

AOP关键名词

切面 aspect: 一般声明我们的AOP的功能代码,即声明该部分是一个AOP来对业务代码进行切割,进行AOP的业务逻辑。切面中一般都会包含我们的通知advice和切点pointcut

通知 advice: advice就是指我们在AOP中要进行处理的逻辑。一般有before,after/afterReturning,around,和afterThrowing分别对应前置,后置,围绕和异常。这里讲一下after和afterReturning的区别和执行顺序。

spring5.2.7RELEASE之前的执行顺序

graph LR 
A[Around]-->B[Before] 
B-->C[Around] 
C-->D[After] 
D-->E[AfterReturning]

spring5.2.7RELEASE之后的执行顺序

graph LR 
A[Around]-->B[Before] 
B-->C[AfterReturning] 
C-->D[After] 
D-->E[Around]

为什么会出现这种情况是因为spring调整了通知的Order执行顺序详细可以参考链接image.png 切点 pointcut: 声明切面作用的地方,一般都指定项目中特定包/类的方法(常用的都是指service层的一些方法),在spring中声明pointcut的方法是不需要写逻辑代码的,主要用来声明pointcut的作用范围。

/**
 * 只声明一个切点,不做任何逻辑处理
 * <p>
 * execution(): 表达式主体。
 * 一个*号:表示返回类型,*号表示所有的类型。
 * 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
 * 第二个*号:表示类名,*号表示所有的类。
 * *(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
 */
@Pointcut("execution(* com.troyqu.annotation.aop.aspectj.execcontroller..*.*(..))")
public void execPointCut() {}

连接点 jointpoint: 被拦截到的点,也就是AOP中命中了AOP声明规则的对象或者方法,一般项目中都对应到我们被切面命中的方法。通过JointPoint对象可以拿到被命中方法的一些关键参数。

@Before("execPointCut()")
public void beforePointCut(JoinPoint joinPoint) {
    logger.info("come in execPointCut before {}", joinPoint.getSignature());
    logger.info("come in execPointCut before");
}

目标对象 target object: 代理的目标对象,spring aop通过代理的方式来实现,目标对象就是我们需要被AOP逻辑处理的类,对应上图中的用户服务/资源服务/订单服务,大多数项目中都是就是我们的UserService这些类。

织入 weave: 指把切面应用到目标对象上,生成代理对象的过程。

代理 AOP Proxy: 一般编码时我们自己感受不到,spring都帮我们封装好了,常见的方式有(jdk动态代理或者CGlib)。

通知类型

  • 前置(Before):在目标方法被调用之前调用的处理逻辑;
  • 后置(After):在目标方法执行完成之后调用的通知;
  • 返回(After-returning):在目标方法成功return语句之后调用的通知,也就是说After-returning会在After之前触发;
  • 异常(After-throwing):在目标方法执行抛出异常时调用的通知;
  • 环绕(Around):在被通知的方法调用之前和调用之后执行的通知;
    @Before("execPointCut()")
    public void beforePointCut(JoinPoint joinPoint) {
        logger.info("come in execPointCut before {}", joinPoint.getSignature());
        logger.info("come in execPointCut before");
    }

    @After("execPointCut()")
    public void afterPointCut() {
        logger.info("come in execPointCut after");
    }

    @AfterReturning("execPointCut()")
    public void afterRetPointCut() {
        logger.info("come in execPointCut AfterReturning");
    }
}