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注解面向切面记录日志就写完了!

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

相关文章

  • Java程序执行过程及内存机制详解

    Java程序执行过程及内存机制详解

    本讲将介绍Java代码是如何一步步运行起来的,还会介绍Java程序所占用的内存是被如何管理的:堆、栈和方法区都各自负责存储哪些内容,感兴趣的朋友跟随小编一起看看吧
    2020-12-12
  • Java由浅入深通关抽象类与接口上

    Java由浅入深通关抽象类与接口上

    在类中没有包含足够的信息来描绘一个具体的对象,这样的类称为抽象类,接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成,本文给大家介绍Java抽象类和接口,感兴趣的朋友一起看看吧
    2022-04-04
  • mybatis中映射文件(mapper)中的使用规则

    mybatis中映射文件(mapper)中的使用规则

    这篇文章主要介绍了mybatis中映射文件(mapper)中的使用规则,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java中的CompletableFuture异步编程详解

    Java中的CompletableFuture异步编程详解

    这篇文章主要介绍了Java中的CompletableFuture异步编程详解,只要提到多线程来优化性能,那么必定离不开异步化,异步化的出现才是多线程优化性能这个核心方案的基础,需要的朋友可以参考下
    2023-12-12
  • springboot多项目结构实现

    springboot多项目结构实现

    本文主要介绍了springboot多项目结构实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • springboot中nacos-client获取配置的实现方法

    springboot中nacos-client获取配置的实现方法

    本文主要介绍了springboot中nacos-client获取配置的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • HashMap vs TreeMap vs Hashtable vs LinkedHashMap

    HashMap vs TreeMap vs Hashtable vs LinkedHashMap

    这篇文章主要介绍了HashMap vs TreeMap vs Hashtable vs LinkedHashMap的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • 关于break和continue以及label的区别和作用(详解)

    关于break和continue以及label的区别和作用(详解)

    下面小编就为大家带来一篇关于break和continue以及label的区别和作用(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Nebula Graph介绍和SpringBoot环境连接和查询操作

    Nebula Graph介绍和SpringBoot环境连接和查询操作

    Nebula Graph 是一款开源的、分布式的、易扩展的原生图数据库,能够承载包含数千亿个点和数万亿条边的超大规模数据集,并且提供毫秒级查询,这篇文章主要介绍了Nebula Graph介绍和SpringBoot环境连接和查询,需要的朋友可以参考下
    2022-10-10
  • Mybatis与Hibernate的区别

    Mybatis与Hibernate的区别

    以前没怎么用过mybatis,只知道与hibernate一样是个orm数据库框架。随着使用熟练度的增加,发现它与hibernate区别是非常大的感兴趣的朋友通过本文一起学习吧
    2016-01-01

最新评论