写点什么

Java 注解 - 一文就懂,java 程序设计与实践教程王薇

用户头像
极客good
关注
发布于: 刚刚

@Target(ElementType.METHOD)


@Retention(RetentionPolicy.RUNTIME)


public @interface Log {


String value() default "";


/**


  • 是否启用


*/


boolean enable() default true;


LogActionType type() default LogActionType.SELECT;


}


日志类型


public enum LogActionType {


ADD("新增"),


SELECT("查询"),


UPDATE("更新"),


DELETE("删除");


private String value;


LogActionType(String value) {


this.value = value;


}


public String getValue() {


return value;


}


public void setValue(String value) {


this.value = value;


}


}


定义注解处理器 - 切面


@Component


@Aspect


@Slf4j


public class LogAspect {


// 保存日志信息服务


private final LogService logService;


// 线程隔离,用于计算每个方法的执行时间


ThreadLocal<Long> currentTime = new ThreadLocal<>();


public LogAspect(LogService logService) {


this.logService = logService;


}


/**


  • 配置切入点

  • 该方法无方法体,主要为了让同类中其他方法使用此切入点


*/


@Pointcut("@annotation(com.liziba.annotation.Log)")


public void logPointcut() {


}


/**


  • 配置环绕通知,使用在方法 logPointcut()上注册的切入点

  • @param joinPoint join point for advice


*/


@Around("logPointcut()")


public Object logAro


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


und(ProceedingJoinPoint joinPoint) throws Throwable {


Object result;


// 计算方法操作时间


currentTime.set(System.currentTimeMillis());


result = joinPoint.proceed();


Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get());


currentTime.remove();


HttpServletRequest request = RequestHolder.getHttpServletRequest();


// 记录用户名、浏览器信息、ip 地址、切入点、日志信息


logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);


return result;


}


/**


  • 配置异常通知

  • @param joinPoint join point for advice

  • @param e exception


*/


@AfterThrowing(pointcut = "logPointcut()", throwing = "e")


public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {


Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get());


currentTime.remove();


// 获取日志堆栈信息,并设值


log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());


HttpServletRequest request = RequestHolder.getHttpServletRequest();


// 记录用户名、浏览器信息、ip 地址、切入点、日志信息


logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);


}


/**


  • 获取用户名信息


*/


public String getUsername() {


try {


return SecurityUtils.getCurrentUsername();


}catch (Exception e){


return "";


}


}


}

4.3 限流注解 - redis+lua 限流

注解定义


@Target(ElementType.METHOD)


@Retention(RetentionPolicy.RUNTIME)


public @interface Limit {


// 资源名称,用于描述接口功能


String name() default "";


// 资源 key


String key() default "";


// key prefix


String prefix() default "";


// 时间的,单位秒


int period();


// 限制访问次数


int count();


// 限制类型


LimitType limitType() default LimitType.CUSTOMER;


}


注解类型


public enum LimitType {


// 默认


CUSTOMER,


// IP 限流


IP


}


定义注解处理器 - 切面


@Aspect


@Component


public class LimitAspect {


// redis 用于执行 lua 脚本


private final RedisTemplate<Object,Object> redisTemplate;


private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);


public LimitAspect(RedisTemplate<Object,Object> redisTemplate) {


this.redisTemplate = redisTemplate;


}


/**


  • 配置切入点

  • 该方法无方法体,主要为了让同类中其他方法使用此切入点


*/


@Pointcut("@annotation(com.liziba.annotation.Limit)")


public void pointcut() {


}


@Around("pointcut()")


public Object around(ProceedingJoinPoint joinPoint) throws Throwable {


HttpServletRequest request = RequestHolder.getHttpServletRequest();


// 获取方法的 Limit 注解


MethodSignature signature = (MethodSignature) joinPoint.getSignature();


Method signatureMethod = signature.getMethod();


Limit limit = signatureMethod.getAnnotation(Limit.class);


LimitType limitType = limit.limitType();


String key = limit.key();


if (StringUtils.isEmpty(key)) {


if (limitType == LimitType.IP) {


key = StringUtils.getIp(request);


} else {


key = signatureMethod.getName();


}


}


// 通过方法或者 ip 结合资源请求路径定义限流 key


ImmutableList<Object> keys = ImmutableList.of(StringUtils.join(limit.prefix(), "", key, "", request.getRequestURI().replaceAll("/","_")));


// Lua 限流脚本


String luaScript = buildLuaScript();


RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);


// Redis 执行 Lua 脚本


Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period());


// 判断是否超过访问次数


if (null != count && count.intValue() <= limit.count()) {


logger.info("第{}次访问 key 为 {},描述为 [{}] 的接口", count, keys, limit.name());


return joinPoint.proceed();


} else {


throw new BadRequestException("访问次数受限制");


}


}


/**


  • Lua 限流脚本


*/


private String buildLuaScript() {


return "local c" +


"\nc = redis.call('get',KEYS[1])" +


"\nif c and tonumber(c) > tonumber(ARGV[1]) then" +


"\nreturn c;" +


"\nend" +


"\nc = redis.call('incr',KEYS[1])" +


"\nif tonumber(c) == 1 then" +


"\nredis.call('expire',KEYS[1],ARGV[2])" +


"\nend" +

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java注解-一文就懂,java程序设计与实践教程王薇