当前位置: 首页 > 知识库问答 >
问题:

如何使用spring aop实现方法链接的日志记录

东郭海阳
2023-03-14
package com.sample;
public class Test implements T{

@Override
 public void show() {
   System.out.println("Test.show()");
   test();
  }
  void Test(){
   //Want to log entry and exit point of this method whenever this method called by any other method
   //The method may belongs to same class or different package's different class
  }
<bean id="exceptionAspect" class="com.sample.ExceptionAspect"/>
<bean id="test" class="com.sample.Test"/>
@Aspect
public class LoggingAspect {
@Around(value="execution (* com.sample.*.*(..))||"+
              "execution(* some other package.*.*(..))")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
      final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
      logger.info("Execution of : " + joinPoint.getSignature() + " Started");
      joinPoint.proceed();
      logger.info("Execution of : " + joinPoint.getSignature() + " completed");
  }

}

客户端类

package com.test;
public class App {
   public static void main(String[] args) throws Exception {

    ApplicationContext appContext = new ClassPathXmlApplicationContext(
                "classpath:/META-INF/spring.xml");

        T test=(T) appContext.getBean("test");
        test.show();
    }

如有任何帮助,不胜感激。

共有1个答案

经伟
2023-03-14

您试图做的事情在Spring AOP中是不可能的(至少在没有对建议的方法进行一些重构的情况下是不可能的)。原因是Spring AOP是基于代理的,这意味着它为每个bean创建一个代理类并注入它而不是您的实现。代理具有bean的所有方法以及添加的方面功能。因此,当您调用bean的方法(实际上是bean的代理)时,将执行方面代码,然后通过委托调用您的方法。因此,当您的方法调用其他方法时,调用是使用真正的bean执行的,而不是这些bean的代理--如果存在的话--因此您不会得到预期的输出。

您可以想出一个代理,它看起来像这样:

class MyBeanProxy implements MyBean {

    MyBeanImpl theBean;

    public void foo() {
        // aspect code
        theBean.foo();
    }
    public void bar() {
        // aspect code
        theBean.bar();
    }
}

你的豆子就像

interface MyBean {
    foo();
    bar();
}

@Component("my_bean")
class MyBeanImpl implements MyBean {
    public void foo() {
        System.out.println("foo");
        bar();
    }
    public void bar() {
        System.out.println("bar");
    }
}
public void foo() {
    System.out.println("foo");
    MyBean myBeanProxy = (MyBean) AopContext.currentProxy();
    myBeanProxy.bar();
}

2-重构代码,使bar()位于另一个bean中,您可以使用AppContext检索该bean。

3-使用AspectJ:方面代码被注入到目标类本身(真的!)

下面是使用AspectJ的一个小示例

package com.aj;

import java.util.Arrays;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {

    @Around("execution( * com.app.services.*.* (..) )")
    public Object callDurationAdvice(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        String argList = Arrays.toString(args);
        System.out.println(signature.getDeclaringTypeName() +
                "." + signature.getName() + "(" + argList + ") started");
        long s = System.nanoTime();
        Object proceed = pjp.proceed(args);
        long e = System.nanoTime();
        System.out.println(signature.getDeclaringTypeName() +
                "." + signature.getName() + "(" + argList + ") ended after " +
                ((double)(e-s)/1000000) + " ms");
        return proceed;
    }
}
package com.app.services;

public class ServicesVersionInfo {

    public static String getVersion() {
        return getVersionNumber() + " " + getVersionStage();
    }

    public static String getVersionNumber() {
        return "1.0.0";
    }

    public static String getVersionStage() {
        return "ALPHA";
    }
}
package com.app;

import com.app.services.ServicesVersionInfo;


public class App {

    public static void main(String[] args) {
        System.out.println("App services version: " + 
            ServicesVersionInfo.getVersion());
    }
}

Ran,这应该输出一些谎言

com.app.services.ServicesVersionInfo.getVersion([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) ended after 0.004862 ms
com.app.services.ServicesVersionInfo.getVersionStage([]) started
com.app.services.ServicesVersionInfo.getVersionStage([]) ended after 0.005673 ms
com.app.services.ServicesVersionInfo.getVersion([]) ended after 0.378877 ms
App services version: 1.0.0 ALPHA

最后,这里有一些类似的问题和进一步的阅读:

Spring AOP不适用于其他方法内的方法调用

 类似资料:
  • 一些日志记录需要在类的静态方法执行前后完成。我试图使用Spring AOP实现这一点,但它不起作用,对于普通方法来说,它是起作用的。请帮助我理解如何实现这一点,如果可以使用注释来完成,那就太好了。

  • 本文向大家介绍PHP写日志的实现方法,包括了PHP写日志的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP写日志的实现方法。分享给大家供大家参考。具体实现方法如下:   这里注意需要给记日志的目录权限: 如果你的apache里配的不是www你要改为对应的 可以用ll命令查看你的权限 希望本文所述对大家的PHP程序设计有所帮助。

  • 问题内容: 我想在Java中实现方法链接。 我该如何实现? 还请告诉我何时使用它。 我想创建可以按如下方式使用的方法链接: 或喜欢 或喜欢 问题答案: 让你的方法返回如下: 这样,每次调用其中一个方法后,你将获得返回的同一对象,以便可以调用另一个方法。 当你要在对象上调用一系列方法时,此技术很有用:它减少了实现该方法所需的代码量,并允许你在方法链之后使用单个返回值。 减少显示对话框所需的代码量的一

  • 主要内容:Logger日志方法的例子,Logger的日志方法Logger 类有多种方法来处理日志记录活动。Logger 类不允许我们实例化一个新的 Logger 实例,但它支持两种获取 Logger 对象的静态方法: 两个方法中的第一个返回应用程序实例的根记录器,它没有名称。 任何其他命名的 Logger 对象实例都是通过传递记录器的名称由第二种方法获得的。记录器的名称可以是您传递的任何字符串,通常是类或包名称,如下所述: Logger日志方法的例子 Lo

  • 本文向大家介绍python实现简单日志记录库glog的使用,包括了python实现简单日志记录库glog的使用的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了python实现简单日志记录库glog的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一、 glog的简介 glog所记录的日志信息总是记录到标准的stderr中,即控制台