SpringBoot自定义注解实现(配合AOP、反射机制、拦截器使用)

timo-nbktp 1年前 ⋅ 847 阅读

1、注解类型

Java 注解用于为 Java 代码提供元数据,可以通过反射来获取指定注解对象,然后获取注解中的元数据信息。

Java注解有四个标准的元注解:@Target、@Retention、@Documented、@Inherited。

1.1 @Target

@Target说明了Annotation所修饰的对象范围,常用如下:

  • @Target(ElementType.TYPE): 作用接口、类、枚举、注解

  • @Target(ElementType.FIELD) :作用属性字段、枚举的常量

  • @Target(ElementType.METHOD): 作用方法

  • @Target(ElementType.PARAMETER): 作用方法参数

1.2 @Retention

Retention 定义了该 Annotation 被保留的时间长短,表示需要在什么级别保存注解信息,用于描

述注解的生命周期(即:被描述的注解在什么范围内有效)

  • @Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在class字节码文件中不包含

  • @Retention(RetentionPolicy.CLASS) 默认的策略,在class字节码文件中存在,但运行时无法获得

  • @Retention(RetentionPolicy.RUNTIME) 在class字节码文件中存在,在运行时可以通过反射获取到

开发中在进行自定义注解的使用时,是在程序运行期间,所以默认就使用@Retention(RetentionPolicy.RUNTIME)

1.3 @Documented

@ Documented它的作用是能够将注解中的元素包含到 Javadoc 中去。

1.4 @Inherited

@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。

拥有@Inherited元注解的注解,修饰的一个类并且该类的子类没有被其他注解修饰,则它的子类会继承了父类的注解。

2、自定义注解实现

  • 自定义注解可以配合AOP使用,比如:记录日志。
  • 自定义注解可以直接在某个方法中,配合反射机制使用。
  • 自定义注解可以配合拦截器使用,是否验证token。

2.1 创建注解

创建自定义注解:SysLog

注解可以没有任何属性字段

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {

    /**
     * 所属模块
     */
    String model() default "";

    /**
     * 接口名称
     */
    String name() default "";

    /**
     * 功能code
     *
     * @return
     */
    String[] code() default "";
}

2.2 AOP实现

创建AOP类SysLogAspect,将自定义注解SysLog作为切入点,如下:

@Aspect
@Component
public class SysLogAspect {
    /**
     * 过滤类
     * 指定自定义注解为切入点
     **/
    @Pointcut("@annotation(com.lhz.mail.test.SysLog)")
    public void logPoint() {
    }

    /**
     * 环绕通知,调用目标方法
     */
    @Around("logPoint()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            SysLog sysLog = method.getAnnotation(SysLog.class);
            // 获取注解的属性值
            String[] code = sysLog.code();
            String name = sysLog.name();
            String model = sysLog.model();
            System.out.println("code:" + Arrays.toString(code));
            System.out.println("name:" + name);
            System.out.println("model:" + model);
        }
        return proceedingJoinPoint.proceed();
    }

}

2.3 反射实现

可以直接利用,反射机制判断,某个类、某个方法、某个字段是否存在注解,如下:

    public static void main(String[] args) {
        // 判断@SysLog是否存在于Person类上:
        Class<Person> clazz = Person.class;
        boolean isAnnotation = clazz.isAnnotationPresent(SysLog.class);
        if (isAnnotation) {
            SysLog sysLog = clazz.getAnnotation((SysLog.class));
            String model = sysLog.model();
            String name = sysLog.name();
        }
    }
    
    public static void main2(String[] args) {
        // 判断@SysLog是否存在于Person类的方法上:
        Class<Person> clazz = Person.class;
        // 方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            boolean isAnnotation = method.isAnnotationPresent(SysLog.class);
            if (isAnnotation) {
                System.out.println("方法:" + method.getName() + "存在自定义注解");
                SysLog sysLog = method.getAnnotation((SysLog.class));
                String model = sysLog.model();
                String name = sysLog.name();
            }
        }
    }

    public static void main3(String[] args) {
        // 判断@SysLog是否存在于Person类的字段中:
        Class<Person> clazz = Person.class;
        // 方法
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            boolean isAnnotation = field.isAnnotationPresent(SysLog.class);
            if (isAnnotation) {
                System.out.println("字段:" + field.getName() + "存在自定义注解");
                SysLog sysLog = field.getAnnotation((SysLog.class));
                String model = sysLog.model();
                String name = sysLog.name();
            }
        }
    }

2.4 拦截器实现

配合拦截器判断某个请求是否不需要进行token校验,逻辑如下:

1、创建注解IgnoreToken

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreToken {
}

2、Controller加载注解:

    @IgnoreToken
    @GetMapping("test")
    public Object test() {
    	return object;
    }

3、拦截器判断注解:

@Component
public class AuthenticationHandlerInterceptor implements HandlerInterceptor {
@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.debug("进入拦截器,URL:{}", request.getServletPath());
        
        Method method = ((HandlerMethod) handler).getMethod();
        // 判断请求接口的方法是否存在IgnoreToken注解
        if (method.isAnnotationPresent(IgnoreToken.class)) {
            return true;
        }else{
          // token验证逻辑
          ...
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

 

 

--end--

 

 

版权 本着开源共享、共同学习的精神,本文转载自 https://blog.csdn.net/zhuocailing3390/article/details/123029172 , 如果侵权之处,请联系博主进行删除,谢谢~