zoukankan      html  css  js  c++  java
  • spring 重复注解和aop拦截

    前言:

      1:jdk1.8开始支持重复注解@Repeatable实现

      2:aop拦截需要拦截当前注解和@Repeatable指向的包装注解才可以完全拦截到,因为:1.当在在方法上只有一个注解时,aop拦截认为是非包装类型注解。2.当方法上有多个重复注解时,aop拦截认为是包装类型注解。

    重复注解实现方式(RequestLimit为原始注解,RequestLimitPack为包装注解):

      

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Repeatable;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 接口限流
     *
     * @author wulm
     */
    @Repeatable(RequestLimit.RequestLimitPack.class)
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RequestLimit {
    
        /**
         * 最大次数,比如 每分钟100次、每小时500次、每天1000次
         */
        int maxTimes();
    
        /**
         * 频率更新时间,比如 60:每分钟、  3600:每小时、  86400:每天
         **/
        int seconds();
    
        @Target({ElementType.METHOD})
        @Retention(RetentionPolicy.RUNTIME)
        @interface RequestLimitPack {
            RequestLimit[] value();
        }
    
    }

    重复注解效果:

    aop拦截(设置了两处@Around):

    @Aspect
    @Configuration
    public class RequestLimitAop {
        private static final Logger LOGGER = LoggerFactory.getLogger(RequestLimitAop.class);
    
        public static final String REDIS_SPLIT_STR = "#";
        public static final String SUB_MODULE = "API";
    
        @Pointcut(value = "@annotation(com.zxy.product.hr.sync.web.config.annotation.RequestLimit)")
        public void pointcut() {
        }
    
        @Pointcut(value = "@annotation(com.zxy.product.hr.sync.web.config.annotation.RequestLimit" +
                ".RequestLimitPack)")
        public void pointcutRequestLimitOuts() {
        }
    
    
        @Around(value = "pointcut()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            // 获取拦截的方法名
            MethodSignature msig = (MethodSignature) joinPoint.getSignature();
            // 获取到注解
            RequestLimit requestLimit = msig.getMethod().getAnnotation(RequestLimit.class);
    
            ResultInfo resultInfo = checkFrequency(requestLimit, false);
            if (ResultInfo.isSuccess(resultInfo)) {
                // 继续执行方法
                return joinPoint.proceed();
            } else {
                return resultInfo;
            }
        }
    
        @Around(value = "pointcutRequestLimitOuts()")
        public Object aroundRequestLimitOuts(ProceedingJoinPoint joinPoint) throws Throwable {
            // 获取拦截的方法名
            MethodSignature msig = (MethodSignature) joinPoint.getSignature();
            // 获取到注解
            RequestLimit.RequestLimitPack requestLimitPack = msig.getMethod()
                    .getAnnotation(RequestLimit.RequestLimitPack.class);
            for (RequestLimit requestLimit : requestLimitPack.value()) {
                ResultInfo resultInfo = checkFrequency(requestLimit, false);
                if (!ResultInfo.isSuccess(resultInfo)) {
                    //失败立即返回
                    return resultInfo;
                }
            }
            //没问题则继续执行
            return joinPoint.proceed();
        }
    
    
        public static ResultInfo checkFrequency(RequestLimit requestLimit, boolean isInnerApi) {
         //代码忽略...... } }
  • 相关阅读:
    Mbps、Kbps、bps、kb、mb区别和换算
    Python导入模块方法
    C# WinForm 程序免安装 .NET Framework(XP/win7/win10环境运行)
    生成缩略图
    WCF 的优势和特点
    不要在using语句中调用WCF服务
    pb getchild获取DropDownDW子窗体后进行取值
    Bootstrap后台管理模板调研
    PB调用C#编写的DLL
    PowerBuilder与嵌入浏览器交互
  • 原文地址:https://www.cnblogs.com/wulm/p/14386372.html
Copyright © 2011-2022 走看看