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;
        }
    }
}
View Code

  代码示例2

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface NoRepeatSubmit {
    /**
     * 默认1s以内算重复提交
     *
     * @return
     */
    int timeout() default 1;

    String msg() default "请勿重复操作";

}
View Code
@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());
        }
    }

}
View Code

 

posted on 2020-08-17 21:14  fuanfei  阅读(188)  评论(0)    收藏  举报