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的应用非常广泛,下一篇来具体学习一下它~

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 后端:414 Request-URI Too Large解决方案

    后端:414 Request-URI Too Large解决方案Web项目接口请求会出现414Request-URITooLarge这个错误下面给大家分享一下相关解决办法:一、get请求改为Pos…

  • 11.08-efi shell

    11.08-efi shell11.08任务目标//进度:将DOS下的SPD读取工具移植到EFIShell环境下,并将读取的SPD内容保存至DIMM_SPD.txt工作结果:学习笔记:fopen()打开文件perror()错误判断处理fread()读取,写入fseek()重定向流ftell()返回当前文件位置fgets()读取fclose()关闭文件流FILE*fopen(constchar*path,constchar*mode);//打开一个文件 参数pa

  • 一分钟制作U盘版BT3 – 有图滴儿 bt3激活成功教程教程

    一分钟制作U盘版BT3 – 有图滴儿 bt3激活成功教程教程一分钟制作BT3U盘版方便,快捷简单无效不退款光盘版BT3,大概694MB,直接刻盘,然后用光盘引导,就可以进入bt3,连接为:http://ftp.heanet.ie/mirrors/back

  • C# SqlTransaction的使用[通俗易懂]

    C# SqlTransaction的使用[通俗易懂]Sqltransaction是用在多sql任务写数据库时的Codeusing(SqlConnectionconn=newSqlConnection(SqlHelper.ConnectionString)){conn.Open();…

  • linux gcc 查看版本号,如何查看Linux或者gcc版本

    linux gcc 查看版本号,如何查看Linux或者gcc版本匿名用户1级2016-12-29回答1.查看Linux版本cat/etc/issueLinaro12.07\n\l2.查看内核版本1)cat/proc/versionLinuxversion2.6.38-13-generic(buildd@rothera)(gccversion4.5.2(Ubuntu/Linaro4.5.2-8ubuntu4))#57-UbuntuS…

  • javacv学习之实现matlab中imfill算法(孔洞填充)

    javacv学习之实现matlab中imfill算法(孔洞填充)因生产需要计算图像的面积,首先第一步就是要先将图像中有洞的地方给它填上,网上找了半天说是matlab中的imfill算法就能直接填上,但我对matlab也不熟也不想用它,结果网上搜资料看看到很多C++的博主写的可以直接用opencv搞定,我一想opencv能搞定那肯定javacv也能搞,所以就有了下面的内容。废话不多说直接上代码publicstaticvoidmain(String[]args){System.loadLibrary(Core.NATIVE_LIBRAR

发表回复

您的电子邮箱地址不会被公开。

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