一个Hello引发的Spring AOP 实战用法解析

实战用法:

  • 1:接口方法
package com.xxx.xxx.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api/open")
public class OpenController {
   
    @RequestMapping(value = "/hello", method = { RequestMethod.GET })
    public JsonResult hello() {
        return new JsonResult("welcome to HOME");
    }

}

  • 2:定义切面
package com.xxx.xxx.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.net.URLDecoder;
import java.util.List;
import java.util.Map;

@Aspect
@Component
@Order(2)
public class TestAspect {

    protected static Logger logger = LoggerFactory.getLogger(TestAspect.class);

    /**
     * 第一个.*:相当于com.mdtech.zfbw.controller下的所有类 第二个。*:相当于类下的所有方法 (..):所有方法的参数
     */
    //可监听在controller包中,也可监听server包中
    @Pointcut("execution(public * com.xxx.xxx.controller.OpenController.hello(..))")
    public void hello() {

    }

    /**
     * 前置通知,请求方法之前去做拦截,走完前置(打印请求信息),才会进行目标方法
     *
     * @param joinPoint
     */
    @Before("hello()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("test1");
    }

    /**
     * 后置通知,调用完目标方法后,执行此方法(打印返回信息)
     *
     * @param ret
     */
    @AfterReturning(returning = "ret", pointcut = "hello()")
    public void doAfterReturning(JoinPoint joinPoint,Object ret) {
        logger.info("test2");
    }

}

  • 3:预期结果

    test1

    welcome to HOME

    test2

结果分析

  • 接口处定义了 hello 的方法,正常输出应该是 welcome to HOME

  • 随后定义的 切面Aspect @Before注解会在方法调用之前先执行,也就是执行了 logger.info("test1"); @AfterReturning 注解会在方法调用之后执行,也就是目标方法(hello())执行后,执行了logger.info("test2");

切面类全面分析

  • @Aspect 定义了一个切面类

  • @Component 定义了一个bean,并把他交由spring进行管理

  • @Order(2) 定义了这个切面类的执行顺序

    • 比如定义了两个切面类 Aspect1 和 Aspect2

      • 大家都会对hello()这个方法进行输出,那么,@order()这个注解就可以定义了执行的先后顺序,数值越小,越先执行
  • @Pointcut("execution(public * com.xxx.xxx.controller.OpenController.hello(..))")

    • 定义了一个切点,切点就是连接点的集合,而连接点指的就是一个方法,比如 hello方法就是一个连接点,证明切点包含了连接点

    • execution用法说明

      • 格式:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

        • 其中后面跟着“?”的是可选项
        • 修饰符匹配(modifier-pattern?)
        • 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
        • 类路径匹配(declaring-type-pattern?)
        • 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
        • 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数
        • 异常类型匹配(throws-pattern?)
      • 具体例子说明

        • execution(* *(..))

          • 表示匹配所有方法
        • execution(public * com. xxx.xxx.xxxService.*(..))

          • 表示匹配com. xxx.xxx.xxxService中所有的公有方法
        • execution(* com.xxx.xxx...(..))

          • 表示匹配com.xxx.xxx包及其子包下的所有方法
    • 从execution的定义上来看,可以知道,确实一个切点是可以包含很多连接点的

  • 在Spring 2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature)

    • 比如:
@Pointcut("execution(public * com.xxx.xxx.controller.OpenController.hello(..))")
public void hello() {

}
- 这个hello()的这个方法就是Pointcut的签名,可以说以后hello()等同于execution(public * com.xxx.xxx.controller.OpenController.hello(..))这个用法,比如下面这里
@Before("hello()")
public void doBefore(JoinPoint joinPoint) {
    logger.info("test1");
}
  等同于==
@Before("execution(public * com.xxx.xxx.controller.OpenController.hello(..))")
public void doBefore(JoinPoint joinPoint) {
    logger.info("test1");
}
  • 通知类型注解合集

    • @Before

      • 参数:切点签名

      • 如:@Before("hello()")

    • @AfterReturning

      • 参数:returning(返回参数的定义), pointcut(切点)

      • 如:

@AfterReturning(returning = "ret", pointcut = "hello()")
    public void doAfterReturning1(JoinPoint joinPoint,Object ret) {
        logger.info("test2");
    }
  • @AfterThrowing

    • 参数:切点签名

    • 如:@AfterThrowing("hello()")

  • @After

    • 参数:切点签名

    • 如:@AfterThrowing("hello()")

  • @Around

    • 这种最灵活,既能做 @Before 的事情,也可以做 @AfterReturning 的事情

    • 参数:切点签名

    • 如:@Around("hello()")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值