「后端学习」- 自定义注解

89 阅读2分钟

目标

自定义接口屏蔽统一的登录拦截校验注解@LoginIgnore

实现

创建模块中定义注解类 @LoginIgnore

package com.server.common.annotation;

import java.lang.annotation.*;

/**
 * 该注解主要用于标记不需要登录的接口
 * 标注该注解的方法会自动屏蔽统一的登录拦截校验逻辑
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LoginIgnore {}

上面代码中存在三个元注解及一个简单的自定义注解声明。这三个元注解的含义为:

  • @Documented
    • 将该注解包含到 Javadoc 中。
  • @Retention(RetentionPolicy.RUNTIME)
    • @Retention 作用是指定该注解的生命周期。
    • RetentionPolicy.RUNTIME 则表示该注解在运行时依然存在。
  • @Target({ElementType.METHOD})
    • @Target 限制的该注解的作用范围。
    • ElementType.METHOD 表示该注解只能标记在方法上。

创建切面类

@Component
@Aspect
@Slf4j
public class CommonLoginAspect {

    /**
     * 切点表达式
     */
    private static final String POINT_CUT = "execution(* com.server.modules.*.controller..*(..))";

    /**
     * 切点模版方法
     */
    @Pointcut(value = POINT_CUT)
    public void loginAuth() {}

    /**
     * 切点环绕增强逻辑
     */
    @Around("loginAuth()")
    public Object loginAuthAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (checkNeedCheckLoginInfo(proceedingJoinPoint)) {
            // ...code
        }

        return proceedingJoinPoint.proceed();
    }

    /**
     * 校验是否需要校验登录信息
     * @param proceedingJoinPoint
     * @return true 需要检验登录信息。false 不需要
     */
    private boolean checkNeedCheckLoginInfo(ProceedingJoinPoint proceedingJoinPoint) {
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        return !method.isAnnotationPresent(LoginIgnore.class);
    }

    // ...code

}

这个切面类稍稍有些许复杂。

整体流程如下:

1.首先设置 @Component 该类标记为 Spring 容器的 Bean

2.设置 @Aspect 注解将该类标记为切面类。

3.声明切点表达式 POINT_CUT

  • "execution(* com.server.modules.*.controller..*(..))"
  • execution 表示切点类型为方法执行。
  • * 返回值可以是任意类型。
  • 包路径为 com.server.modules.* 下的任意子包。
  • 子包中所有 controller 下的所有方法。
  • *(..) 表示匹配任意方法名和参数的方法

4.声明切点模版方法

  • 将上述定义的切点表达式注入方法
  • @Pointcut(value = POINT_CUT)
  • 该方法不需要实现,只需要定义。
  • 要注意该方法返回值必须为 void,访问修饰符必须是 public,方法体和参数列表页都必须是空。

5.切点环绕增强

  • @Around("loginAuth()")
  • @Around 注解的作用是定义切点环绕增强逻辑。
  • 在上面示例中,loginAuthAround 方法中的代码会在被拦截方法执行前后运行

6.判断是否需要登录校验

  • checkNeedCheckLoginInfo 方法中基本属于固定写法。
  • 获取切点的相关信息
    • proceedingJoinPoint.getSignature();
  • 由于切点是方法,所以可以强转为 MethodSignature
  • 获取切点映射的方法对象
    • methodSignature.getMethod();
  • 判断该方法是否被 @LoginIgnore 标记,可以理解这里就是将切面与注解类做关联。
    • method.isAnnotationPresent(LoginIgnore.class);

通过以上操作即可完成自定义注解的大致流程。以上内容纯属个人刚学的理解,如果有啥问题欢迎大佬指出。