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 是在所拦截方法执行之后执行一段逻辑。

  • 相关阅读:
    数据库的视图概念作用
    常见的反爬虫和应对方法
    referrer policy
    JSON
    异步消息处理机制
    Acitivity(活动)
    springboot @Autowired 空指针异常问题处理
    CentOS7 宝塔 ThinkPHP SQLServer 2000 安装FreeTDS
    PHP THINKPHP 函数 dump var_dump var_export
    ThinkPHP5 WHERE AND OR 实现多条件查询
  • 原文地址:https://www.cnblogs.com/lgg20/p/14012223.html
Copyright © 2011-2022 走看看