Spring AOP使用@Aspect注解 面向切面实现日志横切的操作

 更新时间:2021年06月22日 08:40:28   作者:zsq_fengchen  
这篇文章主要介绍了Spring AOP使用@Aspect注解 面向切面实现日志横切的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

引言:

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

在Spring AOP中业务逻辑仅仅只关注业务本身,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

相关注解介绍如下:

@Aspect:作用是把当前类标识为一个切面供容器读取

@Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。

@Around:环绕增强,相当于MethodInterceptor

@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行

@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有

@AfterThrowing:异常抛出增强,相当于ThrowsAdvice

一:引入相关依赖

二:Spring的配置文件

applicationContext.xml 中引入context、aop对应的命名空间;配置自动扫描的包,同时使切面类中相关方法中的注解生效,需自动地为匹配到的方法所在的类生成代理对象。

创建简单计算器的接口ArithmeticCalculator.java及实现类ArithmeticCalculatorImpl.java

package com.svse.aop;
public interface ArithmeticCalculator {
    //定义四个简单的借口 加减乘除算法
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}
package com.svse.aop;
import org.springframework.stereotype.Component;
//将实现类加入Spring的IOC容器进行管理
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
         int result = i + j;
            return result;
    }
    @Override
    public int sub(int i, int j) {
          int result = i - j;
            return result;
    }
    @Override
    public int mul(int i, int j) {
          int result = i * j;
            return result;
    }
    @Override
    public int div(int i, int j) {
          int result = i / j;
            return result;
    }
}

现在想在实现类中的每个方法执行前、后、以及是否发生异常等信息打印出来,需要把日志信息抽取出来,写到对应的切面的类中 LoggingAspect.java 中 要想把一个类变成切面类,需要两步,

① 在类上使用 @Component 注解 把切面类加入到IOC容器中

② 在类上使用 @Aspect 注解 使之成为切面类

package com.svse.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import com.tencentcloudapi.vod.v20180717.VodClient;
/**
 * 日志切面
 * 
 * @author zhaoshuiqing<br>
 * @date 2019年6月14日 下午3:03:29
 */
@Component
@Aspect
public class LoggingAspect {
    //现在想在实现类中的每个方法执行前、后、以及是否发生异常等信息打印出来,需要把日志信息抽取出来,写到对应的切面的类中 LoggingAspect.java 中 
    //要想把一个类变成切面类,需要两步, 
    //① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
    //② 在类上使用 @Aspect 注解 使之成为切面类    
    
    /**
     * 前置通知:目标方法执行之前执行以下方法体的内容 
     * @param jp
     */
    @Before("execution(* com.svse.aop.*.*(..))")
    public void beforeMethod(JoinPoint jp){
         String methodName =jp.getSignature().getName();
         System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
    }
    
     /**
     * 返回通知:目标方法正常执行完毕时执行以下代码
     * @param jp
     * @param result
     */
    @AfterReturning(value="execution(* com.svse.aop.*.*(..))",returning="result")
    public void afterReturningMethod(JoinPoint jp, Object result){
         String methodName =jp.getSignature().getName();
         System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
    }    
      /**
     * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。
     * @param jp
     */
    @After("execution(* com.svse.aop.*.*(..))")
    public void afterMethod(JoinPoint jp){
        System.out.println("【后置通知】this is a afterMethod advice...");
    }    
    
    /**
     * 异常通知:目标方法发生异常的时候执行以下代码
     */
    @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e")
    public void afterThorwingMethod(JoinPoint jp, NullPointerException e){
         String methodName = jp.getSignature().getName();
         System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e);
    }    
    
  /**
  * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
  * @return 
  */
 /*@Around(value="execution(* com.svse.aop.*.*(..))")
 public Object aroundMethod(ProceedingJoinPoint jp){
     String methodName = jp.getSignature().getName();
     Object result = null;
     try {
         System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
         //执行目标方法
         result = jp.proceed();
         System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
     } catch (Throwable e) {
         System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
     }
     
     System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
     return result;
 }*/
}

编写MainTest方法进行测试

package com.svse.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
    public static void main(String[] args) {
        
        //ClassPathXmlApplicationContext默认是加载src目录下的xml文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 
        ArithmeticCalculator arithmeticCalculator =(ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
        
        System.out.println(arithmeticCalculator.getClass());
        int result = arithmeticCalculator.add(3, 5);
        System.out.println("result: " + result);
        
        result = arithmeticCalculator.div(5, 0);
        System.out.println("result: " + result);
    }
}

运行结果:

把其它代码都注释掉,把环绕通知的方法释放出来,测试结果如下:

至此AOP注解面向切面记录日志就写完了!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Mybatis中的延迟加载详细解读

    Mybatis中的延迟加载详细解读

    这篇文章主要介绍了Mybatis中的延迟加载详细解读,Mybatis中延迟加载又称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询,延迟加载可以有效的减少数据库的压力,需要的朋友可以参考下
    2023-10-10
  • SpringBoot是如何使用SQL数据库的?

    SpringBoot是如何使用SQL数据库的?

    今天给大家带来的是关于Springboot的相关知识,文章围绕着SpringBoot是如何使用SQL数据库的展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java序列化的原理分析及解决

    Java序列化的原理分析及解决

    文章介绍了Java中的序列化机制,包括Serializable和Externalizable接口的区别,以及serialVersionUID的作用,Serializable接口可以序列化的所有子类型本身都是可序列化的,如果要序列化的类有父类,父类也应该实现Serializable接口
    2024-11-11
  • java开发微信分享接口的步骤

    java开发微信分享接口的步骤

    这篇文章主要为大家详细介绍了java开发微信分享接口的步骤,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Mybatis-plus如何通过反射实现动态排序不同字段功能

    Mybatis-plus如何通过反射实现动态排序不同字段功能

    这篇文章主要介绍了Mybatis-plus如何通过反射实现动态排序不同字段功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • SpringBoot如何使用MyBatisPlus逆向工程自动生成代码

    SpringBoot如何使用MyBatisPlus逆向工程自动生成代码

    本文介绍如何使用SpringBoot、MyBatis-Plus进行逆向工程自动生成代码,并结合Swagger3.0实现API文档的自动生成和访问,通过详细步骤和配置,确保Swagger与SpringBoot版本兼容,并通过配置文件和测试类实现代码生成和Swagger文档的访问
    2024-12-12
  • AJAX中Get请求报错404的原因以及解决办法

    AJAX中Get请求报错404的原因以及解决办法

    刚学习一门技术时总会踩一些坑,下面这篇文章主要给大家介绍了关于AJAX中Get请求报错404的原因及解决办法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-03-03
  • Java操作数据库(行级锁,for update)

    Java操作数据库(行级锁,for update)

    这篇文章主要介绍了Java操作数据库(行级锁,for update),文章围绕Java操作数据库的相关资料展开详细内容,需要的小伙伴可以参考一下,希望对你有所帮助
    2021-12-12
  • SpringBatch结合SpringBoot简单使用实现工资发放批处理操作方式

    SpringBatch结合SpringBoot简单使用实现工资发放批处理操作方式

    这篇文章主要介绍了SpringBatch结合SpringBoot简单使用实现工资发放批处理操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 三道java新手入门面试题,通往自由的道路--JVM

    三道java新手入门面试题,通往自由的道路--JVM

    这篇文章主要为大家分享了最有价值的3道JVM面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,对hashCode方法的设计、垃圾收集的堆和代进行剖析,感兴趣的小伙伴们可以参考一下
    2021-07-07

最新评论