利用分布式共享锁实现防止方法重复调用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhou920786312/article/details/89187080

利用分布式共享锁实现防止方法重复调用

版本记录

| version:
| date: 20190410
| description:
| Author: 周飞

功能介绍

防止一个方法,在方法参数值相同的情况下,短时间频繁调用

流程

在这里插入图片描述

代码

	package com.lolaage.common.annotations;

import java.lang.annotation.*;

/**
 * @Author feizhou
 * @Description 防止同一个方法被频繁执行(是否需要频繁执行看参数params是否不一样)
 * @Date 19:35 2019/4/9
 * @Param
 * @return
 **/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SameMethodFrequentlyRun {
	/**
	 * @Author feizhou
	 * @Description 当方法的参数是实体对象,对象必须对象重写equal和hashcode方法
	 **/
	String params()  default "";
	String description()  default "";
	/**
	 * @Author feizhou
	 * @Description
	 **/
	long milliseconds()  default 30000L;
}

		package com.lolaage.common.aop;

import com.lolaage.base.po.JsonModel;
import com.lolaage.common.annotations.SameMethodFrequentlyRun;
import com.lolaage.helper.util.RedisLockTemplate;
import com.lolaage.util.StringUtil;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author feizhou
 * @Description  防止同一个方法被频繁执行AOP(是否需要频繁执行看参数params是否不一样)
 **/

@Aspect
@Component
public class SameMethodFrequentlyRunAop {
	private static Logger logger = Logger.getLogger(SameMethodFrequentlyRunAop.class);


	// 配置接入点,即为所要记录的action操作目录
	@Pointcut("execution(* com.lolaage.helper.web.controller..*.*(..))")
	private void controllerAspect() {

	}

	@Around("controllerAspect()")
	public Object around(ProceedingJoinPoint pjp) {
		Object returnObj=null;
		StringBuilder sb=new StringBuilder();

		// 拦截的实体类,就是当前正在执行的controller
		Object target = pjp.getTarget();
		//获取全类名
		String className=target.getClass().getName();
		// 拦截的方法名称。当前正在执行的方法
		String methodName = pjp.getSignature().getName();
		// 拦截的方法参数
		Object[] args = pjp.getArgs();

		// 拦截的放参数类型
		Signature sig = pjp.getSignature();
		MethodSignature msig = (MethodSignature) sig ;

		Class[] parameterTypes = msig.getMethod().getParameterTypes();
		sb.append(className);
		for (Object o : args) {
			if(o==null){
				continue;
			}
			int i = o.hashCode();
			sb.append(":");
			sb.append(i);
		}
		// 获得被拦截的方法
		Method method = null;
		try {
			method = target.getClass().getMethod(methodName, parameterTypes);
			SameMethodFrequentlyRun sameMethodFrequentlyRun = method.getAnnotation(SameMethodFrequentlyRun.class);
			if (sameMethodFrequentlyRun != null) {
				String description = sameMethodFrequentlyRun.description();
				String params = sameMethodFrequentlyRun.params();
				if(StringUtil.isEmpty(params)){
					params=sb.toString();
				}
				long milliseconds = sameMethodFrequentlyRun.milliseconds();
				Boolean isGetLock = RedisLockTemplate.distributedLock_v2(params, description, milliseconds, false);
				if(!isGetLock){
					//提示不要重复操作
					JsonModel result = new JsonModel();
					return result.setErrCode(5004);
				}
			}
		} catch (NoSuchMethodException e) {
			logger.error("分布式防重复操作异常:AOP只会拦截public方法,非public会报异常,如果你要将你的方法加入到aop拦截中,请修改方法的修饰符:"+e.getMessage());
		}
		try {
			  returnObj = pjp.proceed();
		} catch (Throwable e) {
			logger.error("分布式防重复操作异常Throwable:"+e.getMessage());
			e.printStackTrace();
		}
		return returnObj;
	}


}

		/**
	 * 分布式锁压力测试,和防重复测试
	 * @return
	 */
	@SameMethodFrequentlyRun(description="查询操作日志",milliseconds = 10000L)
	@RequestMapping("/pressureLock")
	public void pressureLock(String key,QuitParam quitParam) {

		System.out.println(this.hashCode()+"---"+Thread.currentThread().getName()+":测试开始");
		System.out.println(this.hashCode()+"---"+Thread.currentThread().getName()+"测试结束");
	}

方案优点

  1. 解决表单防重复提交
  2. 将防方法重复执行的功能和业务逻辑区分开发
  3. 可以解决计划任务中方法重复执行的问题。

方案缺点

对实现方案的缺点进行说明,以便后续改进

待改善点

对待完善点进行列举,以便后续改进

其他说明

猜你喜欢

转载自blog.csdn.net/zhou920786312/article/details/89187080