zoukankan      html  css  js  c++  java
  • 使用aop去自定义注解,实现用户在请求的时候记录下来,如日志功能等

    首先搞清楚aop的几个概念:

    AOP即是面向切面,是Spring的核心功能之一,主要的目的即是针对业务处理过程中的横向拓展,以达到低耦合的效果。

    「切面(Aspect)」:一个关注点的模块化。以注解@Aspect的形式放在类上方,声明一个切面。

    「连接点(Joinpoint)」:在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候都可以是连接点。

    「通知(Advice)」:通知增强,需要完成的工作叫做通知,就是你写的业务逻辑中需要比如事务、日志等先定义好,然后需要的地方再去用。增强包括如下五个方面:

    1. @Before:在切点之前执行
    2. @After:在切点方法之后执行
    3. @AfterReturning:切点方法返回后执行
    4. @AfterThrowing:切点方法抛异常执行
    5. @Around:属于环绕增强,能控制切点执行前,执行后,用这个注解后,程序抛异常,会影响@AfterThrowing这个注解。

    「切点(Pointcut)」:其实就是筛选出的连接点,匹配连接点的断言,一个类中的所有方法都是连接点,但又不全需要,会筛选出某些作为连接点做为切点。

    「引入(Introduction)」:在不改变一个现有类代码的情况下,为该类添加属性和方法,可以在无需修改现有类的前提下,让它们具有新的行为和状态。其实就是把切面(也就是新方法属性:通知定义的)用到目标类中去。

    「目标对象(Target Object)」:被一个或者多个切面所通知的对象。也被称做被通知(adviced)对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。

    「AOP代理(AOP Proxy)」AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

    「织入(Weaving)」:把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

    Spring Boot 如何整合AOP自定义一个注解?

    在实际开发中对于横向公共的逻辑需要抽取出来,这时候就需要使用AOP,比如日志的记录、权限的验证等等,这些功能都可以用注解轻松的完成。

    添加依赖starter:

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    自定义一个注解:

    package com.example.demo.config;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SysLog {
    
        OperationType operationType() default OperationType.SELECT;
    
        String value() default "";
    }
    package com.example.demo.config;
    
    /**
     * @author Albert.Yang
     */
    
    public enum OperationType {
        SELECT,SAVE,UPDATE,DELETE
    }

    定义一个切面:

    package com.example.demo.config;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    @Configuration
    public class SysLogAspect {
    
        @Pointcut("@annotation(com.example.demo.config.SysLog)")
        public void pointCut() {}
    
        @Around("pointCut()")
        //@Around("@annotation(sysLog)") //2种写法,一种可以不单独写@Pointcut,而以SysLog sysLog作为入参。
        public Object around(ProceedingJoinPoint point) throws Throwable {
            long beginTime = System.currentTimeMillis(); //逻辑开始时间
            System.out.println("@Around:执行目标方法之前...");
            Object result = point.proceed(); //执行方法
            System.out.println("@Around:执行目标方法之后...");
            saveLog(point,beginTime);//todo,保存日志,自己完善
            return result;
        }
    
        private void saveLog(ProceedingJoinPoint point, long beginTime) {
            System.out.println("Around-----" + beginTime + point.getSignature());
        }
    
        @Before("@annotation(sysLog)")
        public void doBefore(JoinPoint joinPoint, SysLog sysLog) {
            System.out.println("doBefore-----" +joinPoint.getSignature() + sysLog.value());
        }
    
        @AfterReturning(pointcut = "@annotation(sysLog)", returning = "returnValue")
        public void releaseResource(JoinPoint joinPoint, SysLog sysLog, Object returnValue) {
            System.out.println("AfterReturning-----" +joinPoint.getSignature() + sysLog.operationType().toString());
        }
    
    }

    测试:

    以上配置完成后即可使用,只需要在需要的方法上标注@SysLog注解即可,如下:

    package com.example.demo.controller;
    
    import com.example.demo.config.SysLog;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author Tim
     * @Date 2020/11/20 11:40
     */
    @RestController
    public class Controller1 {
    
        @SysLog
        @GetMapping("/add")
        public String add(){
            System.out.println("请求成功");
            return "请求成功";
        }
    
    
    }
    package com.example.demo.controller;
    
    import com.example.demo.config.OperationType;
    import com.example.demo.config.SysLog;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author Tim
     * @Date 2020/11/20 11:40
     */
    @RestController
    public class ControlleDemo {
    
        @SysLog(operationType = OperationType.UPDATE, value = "請求2")
        @GetMapping("/add2")
        public String add(){
            System.out.println("请求2");
            return "请求2";
        }
    
    
    }

     注意有个执行顺序问题:

    @Around是可以同时在所拦截方法的前后执行一段逻辑。

    @Before是在所拦截方法执行之前执行一段逻辑。

    @After 是在所拦截方法执行之后执行一段逻辑。

  • 相关阅读:
    怎么查看京东店铺的品牌ID
    PPT编辑的时候很卡,放映的时候不卡,咋回事?
    codevs 1702素数判定2
    codevs 2530大质数
    codevs 1488GangGang的烦恼
    codevs 2851 菜菜买气球
    hdu 5653 Bomber Man wants to bomb an Array
    poj 3661 Running
    poj 1651 Multiplication Puzzle
    hdu 2476 String Painter
  • 原文地址:https://www.cnblogs.com/lgg20/p/14012223.html
Copyright © 2011-2022 走看看