文章目录

  • SpringBoot aop自定义注解
  • 1 添加AOP依赖的包
  • 2 AOP基本概念
  • 3 AOP使用
  • 3.1 JDK中的元注解
  • 3.1.1 @Target
  • 3.1.2 @Retention
  • 3.1.3 @Document
  • 3.1.4 @Inherited
  • 3.2 核心注解介绍
  • 3.2.1 自定义注解定义规范
  • 3.2.2 定义切入点-重点
  • 3.2.2.1 注解介绍
  • 3.2.2. JoinPoint 与 ProceedingJoinPoint
  • 3.3 案例
  • 3.3.1 自定义注解
  • 3.3.2 自定义切入点及切入点执行的验证或业务代码
  • 3.3.3 在指定的方法或者是对象上标注@AnnPageHelper
  • 3.3.4 单元测试


SpringBoot aop自定义注解

1 添加AOP依赖的包

<!-- 版本号随parent中的pom.xml文件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2 AOP基本概念

  1. Aspect(切面):通常是一个类,里面可以定义切入点和通知
  2. JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
  3. Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
  4. Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
  5. AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

3 AOP使用

3.1 JDK中的元注解

主要有@Target,@Retention,@Document,@Inherited用来修饰注解。

3.1.1 @Target

表示注解可用于什么地方

springboot aop获取getmapping注解值 springboot aop 注解_java

3.1.2 @Retention

表明该注解的生命周期,在开发过程中99%使用的是RetentionPolicy.RUNTIME

springboot aop获取getmapping注解值 springboot aop 注解_自定义注解_02

3.1.3 @Document

表明该注解标记的元素可以被Javadoc 或类似的工具文档化

3.1.4 @Inherited

表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解

3.2 核心注解介绍

3.2.1 自定义注解定义规范
/**
 * @author Administrator
 * @Documented –注解是否将包含在JavaDoc中
 * @Retention –什么时候使用该注解
 * @Target –注解用于什么地方
 * @Inherited – 是否允许子类继承该注解
 */

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {
}
3.2.2 定义切入点-重点
3.2.2.1 注解介绍
  1. @Pointcut
    定义切入点,可批量设置,也可单个方法设置,同时支持多个表达式使用&&(且),||(或)连接
    execution(* * *):三个参数含义:
  1. 第一个参数,表示方法类型,例public,private
  2. 第二个参数,切面方法的返回对象类型,表示所有,一般设置*
  3. 第三个参数,指定批量切面包路径(package),或者是package下的.java文件
    @annotation(@interface):结合注解使用,表示某方法标有该@interface注解,该方法为切入点
    @within(@interface):结合注解使用,表示某对象标有该@interface注解,该对象中的任意方法都会为切入点
  1. @Before
    在被代理对象的方法前先调用。简单的说在方法执行之前,执行该方法
  2. @After
    在被代理对象的方法后调用。简单的说在方法执行之后,return之前执行该方法
  3. @AfterReturning
    在被代理对象的方法正常返回后调用,简单的说在方法执行之后,return之后执行该方法
  4. @Around
    将被代理对象的方法封装起来,用环绕通知取代他,简单的说执行两次,该方法必须执行
    joinPoint.proceed();表示执行目标方法
// 各个注解执行周期如下
 @Before
 @Around (joinPoint.proceed)之前
 执行目标方法(即切入点方法)
 @Around (joinPoint.proceed)之后
 @After
 @AfterReturning
  1. @AfterThrowing
    在被代理对象的方法抛出异常后调用,简单的说执行的方法抛任何异常,执行切面方法
  2. 切入点定义举例介绍
    @Pointcut(“execution(public * com.xxx.xxx.TestController.*(…)) && @annotation(com.test.my.annotation.OperationLog )” ) || execution(public * com.xxx.xxx.Controller.(…))
    说明:在包com.xxx.xxx.TestController.java下的所有public方法且方法需要标注@OperationLog或者是com.xxx.xxx包下后缀为Controller.java的所有方法定义为切入点
3.2.2. JoinPoint 与 ProceedingJoinPoint
  1. JoinPoint
    @Before,@After,@AfterReturning,@AfterThrowing标注的方法上使用

方法

描述

Signature getSignature();

获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息

Object[] getArgs();

获取传入目标方法的参数对象

Object getTarget();

获取被代理的对象

Object getThis();

获取代理对象

  1. ProceedingJoinPoint
    @Around标注的方法上使用

方法

描述

Signature getSignature();

获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息

Object[] getArgs();

获取传入目标方法的参数对象

Object getTarget();

获取被代理的对象

Object getThis();

获取代理对象

Object proceed()

执行目标方法

Object proceed(Object[] newArgs)

传入的新的参数去执行目标方法

3.3 案例

本次使用案例,MyBatis分页查询,自动注入分页参数功能

添加分页查询依赖

<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>
3.3.1 自定义注解
/**
 * @author
 * 分页插件自定义注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnnPageHelper {

    /**
     * 第几页
     * @return
     */
    int pageNum() default 1;

    /**
     * 每页条数
     * 默认20
     * @return
     */
    int pageSize() default 20;

}
3.3.2 自定义切入点及切入点执行的验证或业务代码

核心分为三个步骤

  1. 定义切入点
  2. 指定切入点需要执行的周期@Before,@After,@Around等
  3. 编写切入点执行的验证或业务代码
/**
 *  @author Administrator
 * 日志操作切面具体逻辑
 * order的值越小,优先级越高,默认值Integer.MAX
 */
@Aspect
@Order(-1)
@Component
public class PageHelperAspect {

    public static final Logger logger = LoggerFactory.getLogger(PageHelperAspect.class);

	// 定义切入点,在对象或者是方法上标注@AnnPageHelper为切入点
    @Pointcut("@annotation(com.sifisense.annotation.AnnPageHelper) || @within(com.sifisense.annotation.AnnPageHelper)")
    public void cutLog(){};


	// 指定切入点需要执行的周期
    // @Before("cutLog()") 方式一
    // @Before("@annotation(pageHelper) || @within(pageHelper)")  方式2
    @Before("cutLog()")
    public void before(JoinPoint point, AnnPageHelper pageHelper){
        setPageHelper(point, pageHelper);
    }

    /**
     * 切面执行的方法,设置分页查询参数
     * @param joinPoint
     * @param pageHelper
     */
    public void setPageHelper(JoinPoint joinPoint, AnnPageHelper pageHelper) {
        logger.info("目标方法名为:" + joinPoint.getSignature().getName());
        logger.info("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
        logger.info("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
        logger.info("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
        logger.info("被代理的对象:" + joinPoint.getTarget());
        logger.info("代理对象自己:" + joinPoint.getThis());
        BaseRequest request = null;
        //获取传入目标方法的参数
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            if(args[i] instanceof BaseRequest) {
                request = (BaseRequest) args[i];
                break;
            }
        }

        if(null != request) {
            // 参数1:第几页索引从1开始,参数2:每页几条
            PageHelper.startPage(request.getPageNum(), request.getPageSize());
        } else {
            PageHelper.startPage(pageHelper.pageNum(), pageHelper.pageSize());
        }
    }


}
3.3.3 在指定的方法或者是对象上标注@AnnPageHelper
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private TbUserMapperExt tbUserMapperExt;


    @AnnPageHelper
    @Override
    public List<TbUser> findPager(BaseRequest request) {
        return tbUserMapperExt.selectByExample(new TbUserExample());
    }
}
3.3.4 单元测试
@Test
    public void test() {
        BaseRequest baseRequest = new BaseRequest();
        // 第二页,期望结果limit 5,5
        baseRequest.setPageNum(2);
        // 每页5条
        baseRequest.setPageSize(5);
        userService.findPager(baseRequest);
    }

结果

springboot aop获取getmapping注解值 springboot aop 注解_自定义注解_03