首页 > 技术文章 > springboot中aop的尝试

adroitwolf 2021-01-21 20:12 原文

我们在项目中如果使用spring的框架的话,aop技术多多少少也接触过,所以打算在这里总结一下AOP的技术核心和常用方法。

AOP的基本使用方法 --> 全局AOP监听

我们现在要在Controller层做一个监听,每次进入controller的方法的时候,都启动AOP进行方法检查等操作。

接下来我们看一下源代码:

Controller层:


@RestController
public class PageController {  //这个类在com.demo.controller包下
@RequestMapping("/hello")

   public Map<String,String> helloWorld(){
       Map<String,String > map = new HashMap<>();

       System.out.println("代码执行中");
       map.put("hello","world");
       System.out.println("继续执行");
       return map;
   }
}

AOP:



/**
 * Created with IntelliJ IDEA.
 * User: WHOAMI
 * Time: 2019 2019/6/2 16:06
 * Description: ://TODO ${END}
 */
@Slf4j
@Aspect
@Component
public class WebLogAspect {

 @Pointcut("execution(public * com.demo.controller.*.*(..))")
    private void weblog(){}

    @Before("weblog()")
    private void doBefore(JoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        log.info("URL: "+request.getRequestURL().toString());
        log.info("Method" + request.getMethod());
        log.info("HTTP_METHOD: "+request.getMethod());

        log.info("IP: "+request.getRemoteAddr());
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            log.info("name:{},value:{}", name, request.getParameter(name));
        }
    }

    @AfterReturning(returning = "ret", pointcut = "weblog()")
    public void doAfterReturning(Object ret) throws Throwable {
        log.info("RESPONSE: " + ret);
    }
}

  • 下面讲解一下这个AOP的常用技术

@Aspect
标记这是一个切面,如果没有这个注解,那么这个方法不启动

Pointcut
切点,后面的execution是决定监听哪里的方法

Befoe
前置通知

After
后置通知

下面是我常用的AOP方法

利用自定义注解决定切点

下面我们自定义一个注解

@Target(ElementType.METHOD)
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
  boolean ifDelete() default false;
}

在我们的Controller层方法上加入这个注解


@RequestMapping("/hello")
   @Cache(ifDelete = true)
   public Map<String,String> helloWorld(){
       Map<String,String > map = new HashMap<>();

       System.out.println("代码执行中");
       map.put("hello","world");
       System.out.println("继续执行");
       return map;
   }

AOP层:


@Slf4j
@Aspect
@Component
public class TestAsp {

    @Around("@annotation(com.demo.flag.Cache)")
    public Object testJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("进入aop");

        return joinPoint.proceed();
        System.out.println("代码执行aop后");
    }
}

我们访问一下这个地址,结果是这个样子的

>进入aop
>代码执行中
>继续执行
>代码执行aop后

这里不需要PointCut,而是利用@annotation将所有有上面这个注解的方法都会进入这个AOP方法。

其实这个@Around是一个环绕通知,你可以在这里通过jionPoint获得到访问者IP,变量参数等等。

这个joinPoint.proceed()方法是让controller方法的必要条件。

joinPoint.proceed()方法后的代码是处理完方法后需要执行的代码,这样就可以想象成这个Around将controller层的某个方法'包裹'起来了。

JoinPoint的常用方法

  • 获取到方法的注解
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        Cache annotation = methodSignature.getMethod().getAnnotation(Cache.class);

推荐阅读