在@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)
.
我有一个 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)
.