在@Aspect 类型 class 中使用 java 反射访问用户定义的对象状态

Access user-defined object state using java reflection in @Aspect type class

我有一个 class A,它声明了一个静态记录器实例,然后在 class 的方法中使用。

class A {
  static Log log = LogFactory.getLog(A.class);
   person p = new Person();
   public void methodA(){
     // log.info("logging using apache commons logger");
      }
  }

我还有一个class B,它是@Aspect 类型的。它的方法可能会根据 A 的方法的执行而触发。

@Aspect
 class B{

  @Before(--execution of methodA() pointcut expression--)
   public void methodB(JoinPoint jp){
   // How to get the class A's logger instance to continue logging from same logger instance. As it will print class name   A in logs
        }

  }

我想使用 class A 中使用的记录器实例来记录一些消息。

如何通过反射从 joinPoint 获取 Aspect class 中对象的状态。

I am not using spring framework, trying with aspectjrt apectweaver jars

您可以使用 jp.getTarget() 获取非静态方法的目标实例,或者简单地将 target(targetObject) 绑定到建议方法参数。我给你看的是后者。这是我的 MCVE:

Log4J配置:

log4j.rootLogger=DEBUG, consoleAppender
log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern=[%t] %-5p %c %x - %m%n

帮手class:

package de.scrum_master.app;

public class Person {}

驱动程序申请class:

package de.scrum_master.app;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Application {
  private static Log log = LogFactory.getLog(Application.class);
  private Person p = new Person();

  public void methodA() {}

  public static void main(String[] args) {
    Application application = new Application();
    application.methodA();
  }
}

看点:

package de.scrum_master.aspect;

import java.lang.reflect.Modifier;
import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {
  @Before("execution(* methodA()) && target(targetObject)")
  public void logMethodExecution(JoinPoint jp, Object targetObject) {
    // Filter for static logger, make it accessible and use it for logging 
    Arrays.stream(targetObject.getClass().getDeclaredFields())
      .filter(field -> field.getType().equals(Log.class) && Modifier.isStatic(field.getModifiers()))
      .forEach(field -> {
        try {
          field.setAccessible(true);
          ((Log) field.get(null)).info(jp + " -> logging using apache commons logger");
        } catch (IllegalArgumentException | IllegalAccessException e) {
          e.printStackTrace();
        }
      });
  }
}

控制台日志:

[main] INFO  de.scrum_master.app.Application  - execution(void de.scrum_master.app.Application.methodA()) -> logging using apache commons logger

如果方面和目标 class 不在同一个模块中,这种反射的东西非常丑陋,如果没有配置预防措施,在 JMS 样式的模块化应用程序中可能无法按照您希望的方式工作。至少,你可以让你的记录器 public 以避免使用 field.setAccessible(true).