SpringBoot 玩转 AOP

相信大家对AOP都不陌生,
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。
先简单了解一下AOP的基本概念:

  • Aspect(切面):通常是一个类,里面可以定义切入点和通知
  • JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
  • Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
  • Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
  • AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

现在我们看看SpringBoot 对于AOP的玩法:

  • 添加maven依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 实例 (用AOP控制ip对于一个接口在规定时间内的访问次数限制)

    • 首先可自定义一个注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {

    /**
     * ip允许访问的次数,默认值1000
     */
    int ipCount() default 5;

    /**
     * ip时间段,单位为毫秒,默认值一分钟
     */
    long ipTime() default 60000;

    /**
     * uri允许访问的次数,默认值600
     */
    int uriCount() default 600;

    /**
     * uri时间段,单位为毫秒,默认值一分钟
     */
    long uriTime() default 60000;

}
  • 接下来,实现AOP切面:
@Order(5)
@Aspect
@Component
public class RequestLimitAspect {

    private Logger logger = LoggerFactory.getLogger(RequestLimitAspect.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Before("@annotation(com.mention.shophelp.base.annotation.RequestLimit)")
    public Object requestLimit(JoinPoint pjp) throws Throwable {
        Object target = pjp.getTarget();
        //拦截的方法名称
        String methodName = pjp.getSignature().getName();
        //拦截的放参数类型
        Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getMethod().getParameterTypes();
        Class[] clazzs = target.getClass().getInterfaces();


        //1.获取类
        Class clazz = target.getClass();
        if (clazzs != null && clazzs.length > 0) {
            clazz = clazzs[0];
        }
        //2.获取方法
        Method m = clazz.getMethod(methodName, parameterTypes);
        //3.获取request、callback
        Object[] args = pjp.getArgs();
        HttpServletRequest request = null;
        if (args != null && args.length > 0) {
            if (args[0] instanceof HttpServletRequest) {
                request = (HttpServletRequest) args[0];
                if (request != null) {
                    String callback = request.getParameter("callback");
                }
            }
        }
        String reequestLimitRes = this.RequestLimitCheck(m, request);
        if ("fail".equals(reequestLimitRes)) {
            return "fail";//返回值改为自己的格式
        } else {
            Object obj = pjp.toString();
            return obj;
        }
    }

    private String RequestLimitCheck(Method m, HttpServletRequest request) throws IOException {
        //ip、user_phone+uri  两个维度的访问限制
        if (m != null && m.isAnnotationPresent(RequestLimit.class)) {
            RequestLimit requestLimit = m.getAnnotation(RequestLimit.class);
            //失效时间、访问次数
            int ipTime = (int) (requestLimit.ipTime());
            int ipCount = requestLimit.ipCount();
            InetAddress addr = InetAddress.getLocalHost();
            String ip_key = addr.getHostAddress();//获得本机IP
            String ipKey = redisTemplate.opsForValue().get((ip_key));//一次读取出多个key_value
            Integer ipNumCache = 0;//ip访问次数
            if (ipKey != null && ipKey.length() > 0) {
                if (StringUtils.isNotBlank(ip_key)) {
                    ipNumCache = Integer.parseInt(ipKey);
                }
            }
            //ip限制判断
            if (ipNumCache == 0) {
                redisTemplate.opsForValue().set(ip_key, "1", ipTime, TimeUnit.MILLISECONDS);
                request.setAttribute("fail", 0);
            } else if (ipNumCache >= ipCount) {
                request.setAttribute("fail", 1);
                logger.info("request_limit:用户IP[" + ip_key + "],超过了限定的次数[" + ipCount + "]");
            } else {
                redisTemplate.opsForValue().increment(ip_key, 1);//自增
                request.setAttribute("fail", 0);
            }
        }
        return "success";
    }

}
  • 这时已经大功告成,剩下就是我们在哪里方法上需要,添加上 @RequestLimit 注解即可,
	   int failNum = Integer.valueOf(request.getAttribute("fail").toString());
       if (failNum > 0){
           actionResult.setError(-1, "该ip超过了请求次数,请稍后再试");
           return actionResult;
       }

对于上边注解有不了解的可自行百度,每一次的尝试都是在进步!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XC_Aaron

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值