【AOP】利用aop,实现方法的环绕日志(包括注解日志)

背景

在工作中,日志是查找BUG的重要手段之一,常规的方式就是代码中通过面向过程的方式,即在代码中将想要显示的变量输出。

        logger.debug("id="+id);

然而,在是调试当中,经常需要查看方法的传入参数,但是如果代码中没有log,那查日志就GG了;但是在每个方法都log一段代码,那就有点累赘了,所以接下来将用Spring中的AOP(切面编程)的方式,实现方法环绕日志。

需求

切面编程的方式,记录代码运行中传入变量的值。

步骤

1.maven依赖
2.编写切面
3.注入bean和配置Pointcut

过程

  1. maven依赖
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${springframework.version}</version>
</dependency>
  1. 编写切面(用于记录方法参数的日志操作)

package com.liushiyao.common;

import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class LogAspect {

    private final Logger logger = Logger.getLogger(this.getClass());

    /**
     * 输出调用的参数
     *
     * @param joinPoint
     */
    public void after(JoinPoint joinPoint) {
        //获取参数列表
        Object[] arguments = joinPoint.getArgs();
        //方法名
        String methodName = joinPoint.getSignature().getName();
        String targetName = joinPoint.getTarget().getClass().getName();
        logger.debug("{refer}" + targetName + "." + methodName + ",{arg}" + Arrays.toString(arguments));
    }

}

  • 类LogAspect即为AOP编程中的Aspect,里面用来声明before(略),after,around(略)
  • after方法即为AOP编程中的Advice,是AOP程序的具体操作。
  • after方法是调用方法之后执行的,通过JoinPoint对象,可以获得方法的参数列表已经对应的名字等等
  1. 注入bean和配置Pointcut
    在dispatcher-servlet.xml增加以下代码
	<!--指定扫描目录-->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!--将日志类注入到bean中。-->
    <bean id="logAspect" class="com.liushiyao.common.LogAspect"></bean>

    <aop:config>
        <!--调用日志类-->
        <aop:aspect id="LogAspect" ref="logAspect">
            <!--配置在service包下所有的类在调用之前都会被拦截-->
            <aop:pointcut id="log" expression="execution(* com.liushiyao.blog.service..*.*(..))"/>
			<!--方法前触发 <aop:before pointcut-ref="log" method="before"/>-->
            <!-- 方法后触发 --><aop:after pointcut-ref="log" method="after"/>
            <!-- 环绕触发  <aop:around pointcut-ref="log" method="around"/>  -->
        </aop:aspect>
    </aop:config>
  • pointcut(切点),匹配service下的所有方法,当service中的方法被调用的时候,就会执行after方法。

运行

写个测试的controller


	@RequestMapping("/aop")
    @CrossOrigin
    private void aop(Integer integer,String string){

        testService.aopLogTest(integer,string);

    }

  • controller使用到了testService中的aopLogTest的方法

而aopLogTest方法只是个空方法,

   public void aopLogTest(int arg,String strArg){
    }

调用接口,输入日志

[DEBUG] 2019-10-11 00:08:58,739 method:com.liushiyao.common.LogAspect.after(LogAspect.java:30)
{refer}com.liushiyao.blog.service.TestService.aopLogTest,{arg}[1, 我是字符串]

从日志可以看出,通过AOP的方式被调用的方法的参数列表自动的以日志的方式记录了下来(即使被调用的方法中没有手动把方法参数打印出来),这就是面向切面编程。

拓展

pointcut是通过配置文件匹配的,那能不能通过注解的方式(当然,匹配的方式也可以实现,只是注解更加的灵活),想要记录哪些方法就记录哪些方法?

当然可以!

  1. 先定义一个注解
import com.liushiyao.common.def.Log;
import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoLog {

    //日志类型
    public int type () default Log.Type.DEBUG;


}
  1. 定义日志类型

public class Log {

    public static final class Type{

        public static final int DEBUG = 1;
        public static final int INFO = 2;
        public static final int ERROR = 3;

    }

}

  1. 对after方法进行改造
/**
     * 输出调用的参数
     *
     * @param joinPoint
     */
    public void after(JoinPoint joinPoint) {

        //获取参数列表
        Object[] arguments = joinPoint.getArgs();
        //方法名
        String methodName = joinPoint.getSignature().getName();
        String targetName = joinPoint.getTarget().getClass().getName();

        Class targetClass = null;
        try {
            targetClass =
                Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method methods [] = targetClass.getMethods();
        for (Method method:methods){
            //找到对应的方法
            if(method.getName().equals(methodName)){
                //是否有注解
                AutoLog autoLog = method.getAnnotation(AutoLog.class);
                if(autoLog != null){
                    if(autoLog.type() == Log.Type.DEBUG){
                        logger.debug("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
                    }else if(autoLog.type() == Log.Type.INFO){
                        logger.info("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
                    }else if(autoLog.type() == Log.Type.ERROR){
                        logger.error("{refer}" + targetName +"." + methodName + ",{arg}" + Arrays.toString(arguments));
                    }
                }
            }

        }

    }
  1. 对需要打日志的方式加注解
  • TestService
	public void aopLogTest(int arg,String strArg) {
    }
	@AutoLog(type = Log.Type.INFO)
    public void aopLogTest2(String strArg){
    }

	@RequestMapping("/aop")
    private void aop(Integer integer,String string){

        testService.aopLogTest(integer,string);
		testService.aopLogTest2(string);

    }

  1. 运行结果
[INFO ] 2019-10-12 22:16:17,020 method:com.liushiyao.common.LogAspect.after(LogAspect.java:52)
{refer}com.liushiyao.blog.service.testService.aopLogTest2,{arg}[555]

可以看出只有加了@AutoLog的方法才会记录日志。

以上就是对环绕日志应用和注解日志的介绍,如有错误,欢迎指正

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP是一个强大的框架,可以帮助我们实现各种切面,其中包括日志记录。下面是实现日志记录的步骤: 1. 添加Spring AOP依赖 在Maven或Gradle中添加Spring AOP依赖。 2. 创建日志切面 创建一个用于记录日志的切面。这个切面可以拦截所有需要记录日志方法。在这个切面中,我们需要使用@Aspect注解来声明这是一个切面,并使用@Pointcut注解来定义哪些方法需要被拦截。 ```java @Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void serviceMethods() {} @Around("serviceMethods()") public Object logServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法名,参数列表等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 记录日志 System.out.println("Method " + methodName + " is called with args " + Arrays.toString(args)); // 执行方法 Object result = joinPoint.proceed(); // 记录返回值 System.out.println("Method " + methodName + " returns " + result); return result; } } ``` 在上面的代码中,我们使用了@Around注解来定义一个环绕通知,它会在拦截的方法执行前后执行。在方法执行前,我们记录了该方法的名称和参数列表,然后在方法执行后记录了该方法的返回值。 3. 配置AOPSpring的配置文件中配置AOP。首先,我们需要启用AOP: ```xml <aop:aspectj-autoproxy/> ``` 然后,我们需要将创建的日志切面添加到AOP中: ```xml <bean id="loggingAspect" class="com.example.demo.aspect.LoggingAspect"/> <aop:config> <aop:aspect ref="loggingAspect"> <aop:pointcut id="serviceMethods" expression="execution(* com.example.demo.service.*.*(..))"/> <aop:around method="logServiceMethods" pointcut-ref="serviceMethods"/> </aop:aspect> </aop:config> ``` 在上面的代码中,我们将创建的日志切面声明为一个bean,并将其添加到AOP中。我们还定义了一个切入点,并将其与日志切面的方法进行关联。 4. 测试 现在,我们可以测试我们的日志记录功能了。在我们的业务逻辑中,所有匹配切入点的方法都会被拦截,并记录它们的输入和输出。我们可以在控制台中看到这些日志信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值