• JAVA自定义注解


    一、概念

    Annotation(注解)是 Java 提供的一种对元程序中元素关联信息和元数据(metadata)的途径和方法。

    Annatation(注解)是一个接口,程序可以通过反射来获取指定程序中元素的 Annotation对象,然后通过该Annotation 对象来获取注解中的元数据信息。

    二、 4 种标准元注解

    元注解的作用是负责注解其他注解。 Java5.0 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明。

    1、@Target 修饰的对象范围

    @Target说明了Annotation所修饰的对象范围: Annotation可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)。在 Annotation 类型的声明中使用了 target 可更加明晰其修饰的目标

    2、@Retention 定义被保留的时间长短

    Retention 定义了该 Annotation 被保留的时间长短:表示需要在什么级别保存注解信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效),取值(RetentionPoicy)由:

    • SOURCE:在源文件中有效(即源文件保留)
    • CLASS:在 class 文件中有效(即 class 保留)
    • RUNTIME:在运行时有效(即运行时保留)

    3、@Documented 描述-javadoc

    @ Documented 用于描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因此可以被例如 javadoc 此类的工具文档化。

    4、@Inherited 阐述了某个被标注的类型是被继承的

    @Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该class 的子类。
    在这里插入图片描述

    三、(自定义注解)注解处理器

    Java 的基本注解和元注解,如果这两种注解不能满足你的需求,可以自定义注解。Java SE5 扩展了反射机制的 API,以帮助程序员快速的构造自定义注解处理器。默认情况下,注解可以在程序的任何地方使用,通常用于修饰类、接口、方法和变量等。

    下面实现一个注解处理器(自定义注解)。

    1、定义注解

    使用 @interface 关键字声明自定义注解:

    不包含任何成员变量的注解称为标记注解,基本注解中的 @Override 注解都属于标记注解。

    // 定义一个简单的注解类型
    public @interface Test {
    }
    
    • 1
    • 2
    • 3

    根据需要,注解中可以定义成员变量,成员变量以无形参的方法形式来声明,成员变量也可以有访问权限修饰符,但是只能有公有权限和默认权限。

    import java.lang.annotation.*;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    @Documented
    public @interface UvLogAnnotation {
        // 定义带成员变量的注解。注解中的成员变量也可以有默认值,可使用 default 关键字。
        // 注解中的成员变量以方法的形式来定义,其方法名和返回值定义了该成员变量的名字和类型
        String methodKey() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    根据注解是否包含成员变量,可以分为如下两类:
    1、标记注解:没有定义成员变量的注解类型被称为标记注解。这种注解仅利用自身的存在与否来提供信息,如前面介绍的 @Override、@Test 等都是标记注解。
    2、元数据注解:包含成员变量的注解,因为它们可以接受更多的元数据,所以也被称为元数据注解。

    2、Aspect切面类处理

    /**
     * 浏览量统计
     */
    @Aspect
    @Component
    @Slf4j
    public class UvLogAspect {
        @Autowired
        private RedisService redisService;
        @Autowired
        private UserLogService userLogService;
     
        // 拿到@UVlog注解注释的方法,这里就是切点
        @Pointcut("@annotation(com.aop.annotation.UvLogAnnotation)")
        private void serviceAspect() {
    
        }
    
        // 调用方法后都会进行统计操作,写入redis
        @After("serviceAspect()")
        public void afterMethod(JoinPoint joinPoint) {
            log.info("开始统计处理:**************");
            MethodSignature sign = (MethodSignature) joinPoint.getSignature();
            Method method = sign.getMethod();
            // 获取指定注解实例
            UvLogAnnotation annotation = method.getAnnotation(UvLogAnnotation.class);
            String methodKey = annotation.methodKey();
            String[] argNames = sign.getParameterNames();
            List<String> argNameList = Arrays.asList(argNames);
            Map<String, Object> paramsMap = new HashMap<>();
            //处理参数(将参数或者对象属性值统一放到paramsMap中)
            resolveArgs(joinPoint, argNameList, paramsMap);
            log.info("开始记录redis:{}", JSONObject.toJSONString(paramsMap));
            try {
                saveToRedis(methodKey, paramsMap);
            } catch (Exception e) {
                log.info("redis 异常,降级处理!");
            }
        }
    
     public void saveToRedis(String methodKey, Map<String, Object> paramsMap) {
            if (UvLogKeyEnum.DCZS_COUNT.getValue().equals(methodKey)) {
                userLogService.saveToRedis(methodKey, paramsMap);
            }
        }
    
        public static void resolveArgs(JoinPoint joinPoint, List<String> argNameList,
                                       Map<String, Object> paramsMap) {
            Object[] argObjects = joinPoint.getArgs(); // 参数对象集合
            for (int i = 0; i < argNameList.size(); i++) {
                Class<?> classo = argObjects[i].getClass();
                if (handleClassType(classo.getName())) {
                    paramsMap.put(argNameList.get(i), joinPoint.getArgs()[i]);
                    continue;
                }
                JSONObject object = (JSONObject) JSONObject.toJSON(joinPoint.getArgs()[i]);
                object.keySet().parallelStream().forEach(p -> {
                    if (!p.equals("grantedAuthorities")) {
                        paramsMap.put(p, object.get(p));
                    }
                });
            }
        }
    
        public static <T> T get(Class<T> clz, Object o) {
            if (clz.isInstance(o)) {
                return clz.cast(o);
            }
            return null;
        }
    
    
        public static boolean handleClassType(String name) {
            AtomicBoolean result = new AtomicBoolean(false);
            String[] className = {"String", "Integer", "Long", "int", "float", "double", "char"};
            Arrays.asList(className).forEach(n -> {
                if (name.contains(n)) {
                    result.set(name.contains(n));
                }
            });
            return result.get();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    3、注解的使用

    Controller中使用自定义注解@UvLogAnnotation:

    @RestController
    @RequestMapping("/api")
    @Slf4j
    @Api(tags = "统计用户流量次数")
    public class UserController {
    
        @Autowired
        private UserInfoService userInfoService;
        @Autowired
        private RedisService redisService;
    
        @ApiOperation(value = "统计用户流量次数")
        @GetMapping(value = "/user/count")
        // 使用带成员变量的注解时,需要为成员变量赋值
        @UvLogAnnotation(methodKey = "USER_COUNT")
        public Result<Integer> countUserViews(@ApiIgnore OauthUser user) {
            if (user == null) {
                return Result.error(BasicCodeMsg.AUTHORIZATION_ERROR);
            }
            user.setGmtCreate(new Date());
            Integer result = userInfoService.countUserViews(user);
            return Result.success(result);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

  • 相关阅读:
    .NET分布式Orleans - 9 - 贪吃蛇项目演示
    java 程序员工作问题
    TSINGSEE视频汇聚管理与AI算法视频质量检测方案
    【Cherno的C++视频】Continuous integration in C++
    信源编码 | 无线通信基础知识
    自适应滤波器更新算法-EP2
    Linux常用指令(十)——服务器相关与互传文件
    python文件操作之xml转txt
    盘点阿里、腾讯、百度大厂C#开源项目
    项目管理系统(Java+Web+MySQL)
  • 原文地址:https://blog.csdn.net/weixin_47061482/article/details/130882169