AOP:面向切面编程;公共行为从业务逻辑分离进行统一处理;
1. 添加依赖
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
|
2. new Aspect类
IDE是idea的话,不是右键后的那个选项,是class
添加注解和逻辑代码
1 2 3 4 5 6 7 8 9 10 11
| @Aspect @Component public class ***Aspect{ @Before("execution()") public void doBefore(){ }
@After("execution()") public void doAfter(){ } }
|
execution()的使用参考博客Spring-AOP @AspectJ切点函数之execution()
当存在公用切点时,可采用@Pointcut
进行处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @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. 其他
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void doBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest();
logger.info("url={}", request.getRequestURL());
logger.info("method={}", request.getMethod());
logger.info("ip={}", request.getRemoteAddr());
logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("args={}", joinPoint.getArgs()); }
|
4.实例
下面这个例子是最近在公司用到的,做请求拦截
首先是注解代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestLimit {
String key() default "";
String msg() default "操作频繁";
long timeout() default 1000L; }
|
然后是切面的代码,只针对注解拦截,没有对方法做切入点。另外不提供userUtil和redisUtil,根据自己用到的替换这部分代码就好啦,不影响大局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @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); } } }
|
使用
1 2 3 4 5 6 7 8
| @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); }
|