SpringBoot AOP学习(二):Spring AOP实现日志功能

SpringBoot AOP学习(二):Spring AOP实现日志功能SpringAOP实现日志功能代码示例

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

感谢阅读菜菜的文章,本篇文章是继上一篇 SpringBoot AOP学习(一):AOP的诞生及AOP注解介绍后对AOP注解的使用作一个具体的应用,由于本身我也是才接触不久,借此机会把自己的学习心得记录下来,也希望各位大佬不吝赐教~
在这里插入图片描述
为了学起来更加得心应手,这里简单复习了下IOC:

IOC理论,用来实现对象之间的“解耦”,解决对象之间的耦合度过高的问题。IOC(控制反转)的具体实现是通过借助于“第三方”实现具有依赖关系的对象之间的解耦,这个“第三方”就是IOC容器;同时,IOC也叫依赖注入(DI),那么这两种叫法的区别是什么,且看:
控制反转:获得依赖对象的过程被反转了,从前主动,现在被动
依赖注入:就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中
他们两兄弟是同一个东西从不同的角度来进行描述的,IOC中最基本的技术就是“反射(Reflection)”编程

AOP日志功能实战

菜菜接触一个项目要实现日志功能,需求如下:

1、记录操作人、操作时间
2、记录request请求参数
3、记录response回调数据
4、记录具体的业务描述供系统使用者查看(这里需要自定义注解)
在这里插入图片描述

案例代码结构

为了方便,菜菜将所有代码放在了同一包内
在这里插入图片描述

重点就是这个Aspect切面类
开始实现
首先,
在这里插入图片描述
先定义实体类和controller类

ReqDTO.java

package com.caicai.aop.csdn;


import lombok.Data;

@Data
public class ReqDTO { 
   

    private String user_id;

    private String user_name;
}

TestController.java

package com.caicai.aop.csdn;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/aop")
public class TestController { 
   

        @RequestMapping(path = "/test", method = RequestMethod.POST)
        @MyLog(operateType = "Log测试", operateExplain = "模拟日志记录")  //这里使用的自定义注解
        public String test(@RequestBody ReqDTO reqDTO) { 
   
//            int i = 1 / 0;   //模拟异常
            System.out.println("调用 Log测试 方法");
            return "调用 Log测试 方法 end" ;
        }
    }

然后是定义自定义注解

MyLog .java

package com.caicai.aop.csdn;

import java.lang.annotation.*;

@Target({ 
   ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public  @interface MyLog { 
   
    /** 操作类型 **/
    String operateType();
    /** 操作解释 **/
    String operateExplain();
}

最后,定义我们的切面
在这里插入图片描述

要想把一个类变成切面类,需要两步,

第一步,在类上使用 @Component 注解 把切面类加入到IOC容器中
第二步,在类上使用 @Aspect 注解 使之成为切面类

TestAspect .java

package com.caicai.aop.csdn;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @Aspect 切面类注解实例
 * @author 菜菜bu菜
 */


//声明这是一个组件
@Component
//声明这是一个切面Bean
@Aspect
public class TestAspect { 
   


    //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
    //@annotation表示标注了某个注解的所有方法
    @Pointcut("@annotation(com.caicai.aop.csdn.MyLog)")
    public void aspect(){ 
      }


    //配置前置通知,使用在方法aspect()上注册的切入点
    //同时接受JoinPoint切入点对象,可以没有该参数
  
    @Before("aspect()")
    public void Before(){ 
   
        System.out.println("---------Before方法开始执行");
    }

    //配置后置通知,使用在方法aspect()上注册的切入点
    @After("aspect()")
    public void After(JoinPoint joinPoint){ 
   
        System.out.println("---------After方法开始执行");
    }

    //最终通知
    //returning能够将目标方法的返回值传到切面增强方法里
    //声明rvt时指定的类型会限制目标方法必须返回指定类型(String)的值或没有返回值
    //此处将rvt的类型声明为Object,意味着对目标方法的返回值不加限制
    @AfterReturning(pointcut ="aspect()",returning = "rvt")
    public void AfterReturning(String rvt){ 
   
        System.out.println("--------AfterReturning方法开始执行:---"+rvt);
    }

    //异常通知
    //声明e时指定的类型会限制目标方法必须抛出指定类型的异常
    //此处将e的类型声明为Throwable,意味着对目标方法抛出的异常不加限制
    @AfterThrowing(pointcut="aspect()",throwing="e")
    public void AfterThrowing(Throwable e){ 
   
        System.out.println("--------AfterThrowing方法开始执行:"+e);
    }


    //@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务。
    //功能很强大,可以深入了解下
    @Around("aspect()")
    public Object Around(ProceedingJoinPoint joinPoint) throws Throwable { 
   
        System.out.println("--------Around方法开始执行");
        //获取自定义注解里面的值
        Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
        MyLog logAnnotation = (MyLog)method.getAnnotation(MyLog.class);
        System.err.println("operateType:------"+logAnnotation.operateType());
        System.err.println("operateExplain:------"+logAnnotation.operateExplain());

        //获取入参
        Object[] objs = joinPoint.getArgs();
        String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); // 参数名
        Map<String, Object> paramMap = new HashMap<String, Object>();
        for (int i = 0; i < objs.length; i++) { 
   
            paramMap.put(argNames[i], objs[i]);
        }
        System.err.println("入参:"+paramMap.toString());

        //获取出参
        Object result =joinPoint.proceed();
        System.err.println("出参:"+result.toString());
        return result;

    }

}

测试

正常测试

在这里插入图片描述
结果:

--------Around方法开始执行
---------Before方法开始执行
调用 Log测试 方法
--------AfterReturning方法开始执行:---调用 Log测试 方法 end
---------After方法开始执行
operateType:------Log测试
operateExplain:------模拟日志记录
入参:{ 
   reqDTO=ReqDTO(user_id=1234, user_name=3423)}
出参:调用 Log测试 方法 end

异常测试

在TestController.java下test方法里面加上 int i = 1 / 0; //模拟异常

  @RequestMapping(path = "/test", method = RequestMethod.POST)
        @MyLog(operateType = "Log测试:", operateExplain = "模拟日志记录")  //这里使用的自定义注解
        public String test(@RequestBody  ReqDTO reqDTO) { 
   
            int i = 1 / 0;   //模拟异常
            System.out.println("调用 Log测试 方法");
            return "调用 Log测试 方法 end" ;
        }

再次发送请求
在这里插入图片描述
结果:

--------Around方法开始执行
---------Before方法开始执行
--------AfterThrowing方法开始执行:java.lang.ArithmeticException: / by zero
---------After方法开始执行
operateType:------Log测试
operateExplain:------模拟日志记录
入参:{ 
   reqDTO=ReqDTO(user_id=1234, user_name=3423)}

总结

AOP真真真强啊!面向切面编程(aop)是对面向对象编程(oop)的补充,面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。

实现AOP的技术,主要分为两大类

  1. 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
  2. 采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码,属于静态代理。

AOP框架具有的两个特征

  1. 各个步骤之间的良好隔离性
  2. 源代码无关性

AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象。
在这里插入图片描述
最后,对于实际应用中 @Around的应用非常广泛,下一篇来具体学习一下它~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/169625.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java 反编译器_代码反编译到数据库

    java 反编译器_代码反编译到数据库xjad反编译工具下载使用反编译时把class文件直接拖拽至工具内即可,如果反编译结果不对时把class文件重新去拿原始的不要编辑打开,或者放在一个文件夹内在试。反编译后的代码没有注释、注解等,反正能用得细心看看调整。点击下载工具http://a.xzfile.com/down2/XJadfanbinayi_downcc.zip…

    2022年8月20日
    8
  • python海龟绘图画树_python,递归函数画树,海龟作图,turtle

    python海龟绘图画树_python,递归函数画树,海龟作图,turtle原博文2020-04-0710:18−importturtleimporttimedeftree(t,trunk_length,pensize):iftrunk_length>5:t.pensize(pensize)t.forward(trunk_lengt…相关推荐2019-12-2409:01−用turtle函数画空心圆turtle.cir…

    2022年6月28日
    25
  • 转:分享两个饼状图在线生成工具[通俗易懂]

    转:分享两个饼状图在线生成工具[通俗易懂]饼状图最近用的蛮多的,每次用excel略麻烦:https://imgflip.com/chart-makerhttp://www.lizibuluo.com/bing/index.php两个工具

    2022年8月3日
    5
  • js – form表单提交不刷新

    大家已经发现了,当我们点击submit提交form表单的时候,他会刷新一次,如果不想它刷新的话有下面两种方法:利用iframe我们可以利用一个隐藏的iframe来实现,主要是我们把提交目标放到一个隐藏的iframe里,然后让iframe提交数据(ps:这个未实测,仅仅是网上提供的,我记录一下.以后遇到或者会试一下吧)<formaction=”…

    2022年4月18日
    61
  • springcloud和dubbo区别「建议收藏」

    springcloud和dubbo区别「建议收藏」最大区别SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。…

    2022年6月5日
    30
  • app抓包分析sign

    app抓包分析sign介绍:简单的app抓包分析sign一:准备工具jeborjadxorgdaandsoon首先抓包:点击登录抓取包:可以看见,这里直接抓到账户密码。我们可以通过DDMS查看日志信息:通过添加筛选,可以直接看到信息。我们在看看代码逻辑:对比一下,可以看到,是一样的,说明就是将一串密钥+我们的data数据,然后进行MD5加密得到的sign。后面的代码:应该是在做编码,这里得到正确的结果,就不用看他了。如果结果不正确,可以分析下这个代码的是在干什么,你也可以自己分

    2022年5月9日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号