SpringBoot Aop 简记
SpringBoot Aop
1. Aop
AOP(Aspect-Oriented Programming,面向切面编程),它利用一种”横切”的技术,将那些多个类的共同行为封装到一个可重用的模块。便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
2. AOP相关概念:
Aspect(切面):声明类似于Java中的类声明,在Aspect中会包含一些Pointcut及相应的Advice。
Joint point(连接点):表示在程序中明确定义的点。包括方法的调用、对类成员的访问等。
Pointcut(切入点):表示一个组Joint point,如方法名、参数类型、返回类型等等。
Advice(通知):Advice定义了在Pointcut里面定义的程序点具体要做的操作,它通过(before、around、after(return、throw)、finally来区别实在每个Joint point之前、之后还是执行 前后要调用的代码。
Before:在执行方法前调用Advice,比如请求接口之前的登录验证。
Around:在执行方法前后调用Advice,这是最常用的方法。
After:在执行方法后调用Advice,after、return是方法正常返回后调用,after\throw是方法抛出异常后调用。
Finally:方法调用后执行Advice,无论是否抛出异常还是正常返回。
AOP proxy:AOP proxy也是Java对象,是由AOP框架创建,用来完成上述动作,AOP对象通常可以通过JDK dynamic proxy完成,或者使用CGLIb完成。
Weaving:实现上述切面编程的代码织入,可以在编译时刻,也可以在运行时刻,Spring和其它大多数Java框架都是在运行时刻生成代理。
3、使用场景:日志收集、SQL耗时打印、重复提交处理等等
pom依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
代码示例1
@Aspect @Component public class LogAspect { @Pointcut("execution(* com.rui.controller..*.*(..))") public void webLog() { } @Before("webLog()") public void deBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录下请求内容 System.out.println("URL : " + request.getRequestURL().toString()); System.out.println("HTTP_METHOD : " + request.getMethod()); System.out.println("IP : " + request.getRemoteAddr()); System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 System.out.println("方法的返回值 : " + ret); } //后置异常通知 @AfterThrowing("webLog()") public void throwss(JoinPoint jp) { System.out.println("方法异常时执行....."); } //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 @After("webLog()") public void after(JoinPoint jp) { System.out.println("方法最后执行....."); } //环绕通知,环绕增强,相当于MethodInterceptor @Around("webLog()") public Object arround(ProceedingJoinPoint pjp) { System.out.println("方法环绕start....."); try { Object o = pjp.proceed(); System.out.println("方法环绕proceed,结果是 :" + o); return o; } catch(Throwable e) { e.printStackTrace(); return null; } } }
代码示例2
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Order(Ordered.HIGHEST_PRECEDENCE) public @interface NoRepeatSubmit { /** * 默认1s以内算重复提交 * * @return */ int timeout() default 1; String msg() default "请勿重复操作"; }
@Aspect @Component public class NoRepeatSubmitAop { public NoRepeatSubmitAop() { System.out.println("进入NoRepeatSubmitAop"); } @Pointcut("@annotation(NoRepeatSubmit)") public void noRepeat() { System.out.println("点击noRepeat"); } @Before("noRepeat()") public void before(JoinPoint point) throws Exception { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; HttpServletRequest request = servletRequestAttributes.getRequest(); //HttpServletResponse response = servletRequestAttributes.getResponse(); //获取出方法上的注解 MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); NoRepeatSubmit annotation = method.getAnnotation(NoRepeatSubmit.class); if(null != annotation) { //通过ip+接口地址作为key获取缓存 //存在则返回提示,不存在则存入缓存 //存入缓存设置过期时间 String key = request.getRequestURI() + request.getSession().getId(); RedisService redisService = SpringUtil.getBean(RedisService.class); Integer exist = redisService.getKey(key); if(null != exist) { throw new Exception(annotation.timeout() + "s内" + annotation.msg()); } redisService.setExpired(key, new Integer(1).toString(), annotation.timeout()); } } }
浙公网安备 33010602011771号