序言
因为闲着无聊刚好想写点东西来打发时间,所以就写了个自定义注解+Aop+Zset实现一个请求排行榜来玩玩,如有写的不正确的地方还缺谅解,指出改正。
创建一个自定义注解LogRank
@Documented // 注解表明这个注解是由 javadoc记录的
@Target(ElementType.METHOD) // 这个枚举类型的常量提供了一个简单的分类
@Retention(RetentionPolicy.RUNTIME) // RetentionPolicy这个枚举类型的常量描述保留注解的各种策略,它们与元注解(@Retention)一起指定注释要保留多长时间
public @interface LogRank {
}
ElementType 介绍
package java.lang.annotation;
/**
* The constants of this enumerated type provide a simple classification of the
* syntactic locations where annotations may appear in a Java program. These
* constants are used in {@link Target java.lang.annotation.Target}
* meta-annotations to specify where it is legal to write annotations of a
* given type.
* @author Joshua Bloch
* @since 1.5
* @jls 9.6.4.1 @Target
* @jls 4.1 The Kinds of Types and Values
*/
public enum ElementType {
/** 类, 接口 (包括注解类型), 或 枚举 声明 */
TYPE,
/** 字段声明(包括枚举常量) */
FIELD,
/** 方法声明(Method declaration) */
METHOD,
/** 正式的参数声明 */
PARAMETER,
/** 构造函数声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包声明 */
PACKAGE,
/**
* 类型参数声明
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 使用的类型
*
* @since 1.8
*/
TYPE_USE
}
RetentionPolicy 介绍
package java.lang.annotation;
/**
* Annotation retention policy. The constants of this enumerated type
* describe the various policies for retaining annotations. They are used
* in conjunction with the {@link Retention} meta-annotation type to specify
* how long annotations are to be retained.
*
* @author Joshua Bloch
* @since 1.5
*/
public enum RetentionPolicy {
/**
* 注解只在源代码级别保留,编译时被忽略
*/
SOURCE,
/**
* 注解将被编译器在类文件中记录
* 但在运行时不需要JVM保留。这是默认的
* 行为.
*/
CLASS,
/**
*注解将被编译器记录在类文件中
*在运行时保留VM,因此可以反读。
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
注解将被编译器在类文件中记录
* 但在运行时不需要JVM保留。这是默认的
* 行为.
*/
CLASS,
/**
*注解将被编译器记录在类文件中
*在运行时保留VM,因此可以反读。
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
创建一个aop类LogAop
package com.lzw.redis.aop;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
/**
* @Author lzw
* @Date 2020/10/31
**/
@Aspect
@Component
@Slf4j
public class LogAop {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
private static Double num=1d;
// 前置增强我们的LogRank注解
@Before("@annotation(com.lzw.annotation.LogRank)")
public void logRank(JoinPoint point){
// 获取方法名
String method=point.getSignature().getName();
// 获取类的完整名
String className=point.getSignature().getDeclaringType().getName();
Rank rank=new Rank();
rank.setClassName(className);
rank.setMethod(method);
// 存入redis里
redisTemplate.opsForZSet().incrementScore(className,rank,num);
log.info("接口排行榜记录成功~");
}
@Data
public class Rank{
private String method;
private String className;
}
}
这里如果不懂Zset的可以看看我之前的文章
优雅的使用ZSet实现搜索排行榜
编写api类TestController
package com.lzw.redis.controller;
import com.lzw.Exception.BusinessException;
import com.lzw.annotation.LogRank;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("test")
@LogRank
public Object test(@RequestParam String name) {
if (!StringUtils.hasText(name)) {
throw new BusinessException("参数只能为字符串");
}
return name;
}
@GetMapping("test1")
@LogRank
public Object test1(@RequestParam String name) {
if (!StringUtils.hasText(name)) {
throw new BusinessException("参数只能为字符串");
}
return name;
}
}