欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot 的面向切面编程(AOP)

程序员文章站 2022-07-12 14:55:29
...

1、确定连接点

 
连接点:对应的是具体被拦截的对象。在什么地方使用AOP,也就是项目需要使用AOP的是哪个类的哪个方法。Spring               AOP只能对方法进行拦截,所以我们采用@AspectJ注解实现AOP时,首先要确定需要拦截的方法,让它能织入
              到约定的流程中。

 

2、定义切点

 
代码中,我们使用注解@Pointcut来定义切点(具体看示例代码)。
 

以一个表达式来举例说明:executiong(* com.springboot.pro.service.impl.UserServiceImpl.printUser(…))

  • execution 表示在执行的时候,拦截里面的正则匹配的方法;
  • * 表示任意返回类型的方法;
  • com.springboot.pro.service.impl.UserServiceImpl 表示指定目标对象的全限定名称;
  • printUser 表示指定目标对象的方法;
  • (…) 表示任意参数进行匹配。
     
     

                                                                         AspectJ的指示器

项目类型 描述
arg() 限定连接点方法参数
executing() 用于匹配值连接点的执行方法
@args() 通过连接点方法参数上的注解进行限定
this 限制连接点匹配AOP代理Bean引用为指定的类型
target 目标对象(即被代理对象)
@target() 限制目标对象的配置了指定的注解
within 限制连接点匹配指定的类型
@within 限定连接点带有匹配注解类型
@annotation() 限定带有指定注解的连接点

 

3、开发切面

 
通过切面可以描述AOP其他的信息,用于描述流程的织入。通俗点讲,切面就是AOP在连接点方法上的一些扩展。
开发切面时,有5种通知。
 

3.1 AspectJ 支持 5 种类型的通知注解

 

3.1.1 前置通知 @Before

@Before: 前置通知, 在方法执行之前执行。需要注意的是,前置通知无法返回响应。

 

3.1.2 后置通知 @After

        @After: 后置通知, 在方法执行之后执行。无论是否发生异常,都进行执行的通知。需要注意的是,在后置通知中,不能访问目标方法的执行结果。原因可能在执行过程中发生异常而无法得到结果。

 

3.1.3 返回通知 @AfterRunning

        @AfterRunning: 返回通知, 在方法返回结果之后执行。在目标方法正常结束时,才执行的通知。返回通知可以访问到方法的返回值。

 

3.1.4 异常通知 @AfterThrowing

@AfterThrowing: 异常通知, 在方法抛出异常之后。

 

3.1.5 环绕通知 @Around

        @Around: 环绕通知, 围绕着方法执行。环绕通知类似于动态代理。在使用环绕通知时,需要明确调用 ProceedingJoinPoint的proceed()方法来执行被代理的方法。否则会导致通知被执行了,但是目标方法没有被执行。同时需要注意的是,环绕通知的方法需要有返回值(该返回值就是返回目标方法执行之后的结果,即调用ProceedingJoinPoint.proceed()的返回值),否则会出现空指针异常。

 

4、示例代码

 



import com.alibaba.fastjson.JSON;
import com.github.pagehelper.util.StringUtil;
import com.huajie.servera.common.CommonResult;
import com.huajie.servera.enu.ResultEnum;
import com.huajie.servera.util.CookieUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpServletRequest;

/**
 * @title: ControllerAop
 * @description: TODO
 * @date 2019/5/29 17:17
 */
@Configuration
@Order(1)//设置切面的优先级,数字越小优先级越高
@Aspect
public class ControllerAop {

   private final static Logger logger = LoggerFactory.getLogger(ControllerAop.class);


    public ControllerAop(){
        logger.info("=============初始化ControllerAop===============");
    }

   @Pointcut("execution(* com.pro.servera.controller.*.*(..))")
   public void pointCut() {

   }

    /**
     * 环绕通知
     */ 
    @Around("pointCut()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) {
        Object result = null;
        // 获取将要执行的方法名称
        String methodName = pjp.getSignature().getName();
        // 获取执行方法的参数
        Object[] argst = pjp.getArgs();
        if (argst.length > 0) {
          // 获取第一个参数的类型
          String firstType = argst[0].getClass().getName();
        }
        try {
            // 执行原方法
            result = pjp.proceed();
        } catch (Throwable t) {
            logger.info("=========环绕通知异常=============");
            t.printStackTrace();
        }
        return result;

    }


    /**
     * 声明该方法是一个前置通知,
     * 方法执行之前执行
     */
    @Before("pointCut()")
    public void before(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
    }

    /**
     * 声明该方法是一个后置通知,目标方法执行后执行,
     * 就算目标方法抛出异常也会执行
     * 但是后置通知不能访问目标方法返回的结果
     */
    @After("pointCut()")
    public void after(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
    }

    /**
     * 在目标方法正常执行完了之后执行,
     * 可以访问到方法的返回值:result
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(ProceedingJoinPoint joinPoint, Object result) {
    }

    /**
     * 在目标方法抛出异常执行,也可以指定出现制定异常时执行,
     * Exception改为需要指定的一场类型
     */
    @AfterThrowing(value = "pointCut()",throwing = "e")
    public void afterThorwing(ProceedingJoinPoint joinPoint, Exception e) {
    }



}

 
不要忘记SpringBoot启动类添加注解@EnableAspectJAutoProxy(proxyTargetClass=true)
  
SpringBoot 的面向切面编程(AOP)