AOP:面向切面编程;公共行为从业务逻辑分离进行统一处理;
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. new Aspect类
IDE是idea的话,不是右键后的那个选项,是class 添加注解和逻辑代码
@Aspect
@Component
public class ***Aspect{
@Before("execution()")//接触到业务代码之前处理
public void doBefore(){
}
@After("execution()")//接触到业务代码之后处理
public void doAfter(){
}
}
execution()的使用参考博客Spring-AOP @AspectJ切点函数之execution()
当存在公用切点时,可采用@Pointcut进行处理
@Aspect
@Component
public class ***Aspect{
@Pointcut("execution()")//统一公用代码
public void common(){
}
@Before("common()")//接触到业务代码之前处理
public void doBefore(){
}
@After("common()")//接触到业务代码之后处理
public void doAfter(){
}
@AfterReturning(returning="obj",pointcut="common()")//方法返回后处理
public void doAfterReturning(Object obj){
}
}
3. 其他
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}", request.getRequestURL());
//method
logger.info("method={}", request.getMethod());
//ip
logger.info("ip={}", request.getRemoteAddr());
//类方法
logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
logger.info("args={}", joinPoint.getArgs());
}
4.实例
下面这个例子是最近在公司用到的,做请求拦截 首先是注解代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {
/**
* 返回redis的key
* 默认类名+方法名
*
* @return redis的key
*/
String key() default "";
/**
* 请求限制后的提示语
*
* @return 提示语
*/
String msg() default "操作频繁";
/**
* redis超时时间
*
* @return 超时时间
*/
long timeout() default 1000L;
}
然后是切面的代码,只针对注解拦截,没有对方法做切入点。另外不提供userUtil和redisUtil,根据自己用到的替换这部分代码就好啦,不影响大局
@Aspect
@Component
@Slf4j
public class RequestLimitAspect {
@Resource
private UserUtil userUtil;
@Resource
private RedisUtils redisUtils;
@Pointcut("@annotation(cn.xxx.web.config.aspect.annotation.RequestLimit)")
public void executeService() {
}
@Around("executeService()&&@annotation(requestLimit)")
public Object around(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {
String errorMsg = requestLimit.msg();
String redisKey = requestLimit.key();
long timeout = requestLimit.timeout();
if (StringUtils.isBlank(redisKey)) {
redisKey = joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName();
}
redisKey = redisKey + userUtil.getOpenId();
if (redisUtils.exists(redisKey)) {
return MessageBean.fail(errorMsg);
}
try {
redisUtils.set(redisKey, userUtil.getSessionId(), timeout, TimeUnit.MILLISECONDS);
return joinPoint.proceed();
} finally {
redisUtils.delete(redisKey);
}
}
}
使用
@RequestLimit(key = WHEELING_REQUEST_PREFIX, msg = "正在抽奖,请稍后...", timeout = 4 * 1000L)
public MessageBean wheelPay() {
String sessionId = userUtil.getSessionId();
if (StringUtils.isBlank(sessionId)) {
return new MessageBean(ErrorCodeEnum.WEB_NOT_AUTHED);
}
return orderService.wheelPay(userUtil.getOpenId(), sessionId);
}
阿豆的闲暇时光 www.ibean.top/archives/20…