JAVA自定义注解

文章目录

  • 一、概念
  • 二、 4 种标准元注解
    • 1、@Target 修饰的对象范围
    • 2、@Retention 定义被保留的时间长短
    • 3、@Documented 描述-javadoc
    • 4、@Inherited 阐述了某个被标注的类型是被继承的
  • 三、(自定义注解)注解处理器
    • 1、定义注解
    • 2、Aspect切面类处理
    • 3、注解的使用

一、概念

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自定义注解_第1张图片

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

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

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

1、定义注解

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

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

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

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

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

根据注解是否包含成员变量,可以分为如下两类:
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();
    }

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);
    }

JAVA自定义注解_第2张图片

你可能感兴趣的:(java,自定义注解,spring,boot,面试)