从 AspectJ 访问私有静态成员(例如记录器)
Accessing private static members (e.g. loggers) from AspectJ
假设我有这个class
public class MyClass {
private Logger log = LogFactory.getLogger(MyClass.class);
public void doSomething() {
// doing something
}
}
假设我要写一个切面来登录和退出:
public aspect TraceAspect {
pointcut method(): execution(* *(..));
before(): method(){
log.info("entering method");
}
after(): method(){
log.info("existing method");
}
}
这里的问题是我想用aspect访问class里面的log对象,但是我不知道怎么办。我不想创建新的记录器,因为我想在记录时保留与 class 记录器关联的所有数据。有没有一种方法或模式可以访问 class 数据?
编辑:想声明这方面应该跟踪所有具有日志字段的 classes。也就是说,我可能有很多classes:MyClass, MyClass1, YourClass2, RepositoryClass,
等等
Nándor 所说的在技术上是正确的,但我的建议是:请尽可能避免访问私有成员或方法,因为它们是私有的是有原因的。例如,即使 class 的 public 界面不变,它们也可能会发生变化。所以你永远不能依赖它们的存在或它们的命名。此外,横切关注点也应尽可能遵循封装等设计原则。
这个具体案例是关于 Slf4J 记录器的,更准确地说是关于您希望避免创建冗余记录器对象的。好吧,关于对象创建,Slf4J 并不像您想象的那样愚蠢或粗心。所有 classes 实现 ILoggerFactory
使用内部映射来缓存给定 (class) 名称的现有记录器,参见例如
那么,为什么不放松一下,使用目标 class 名称从您的方面访问相应的记录器呢?如果目标 class 没有自己的静态记录器,这甚至可以工作:
申请classes:
package de.scrum_master.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClassWithLogger {
private Logger log = LoggerFactory.getLogger(MyClassWithLogger.class);
public void doSomething() {}
}
package de.scrum_master.app;
public class MyClassWithoutLogger {
public void doSomething() {}
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new MyClassWithLogger().doSomething();
new MyClassWithoutLogger().doSomething();
}
}
看点:
package de.scrum_master.aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public aspect TraceAspect {
pointcut executedMethods(Object targetObject) :
execution(!static * *(..)) && target(targetObject);
before(Object targetObject) : executedMethods(targetObject) {
Logger log = LoggerFactory.getLogger(targetObject.getClass());
log.info("Entering " + thisJoinPoint);
}
after(Object targetObject) : executedMethods(targetObject) {
Logger log = LoggerFactory.getLogger(targetObject.getClass());
log.info("Exiting " + thisJoinPoint);
}
}
配置 Slf4J 以使用简单记录器的控制台日志:
[main] INFO de.scrum_master.app.MyClassWithLogger - Entering execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithLogger - Exiting execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Entering execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Exiting execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())
假设我有这个class
public class MyClass {
private Logger log = LogFactory.getLogger(MyClass.class);
public void doSomething() {
// doing something
}
}
假设我要写一个切面来登录和退出:
public aspect TraceAspect {
pointcut method(): execution(* *(..));
before(): method(){
log.info("entering method");
}
after(): method(){
log.info("existing method");
}
}
这里的问题是我想用aspect访问class里面的log对象,但是我不知道怎么办。我不想创建新的记录器,因为我想在记录时保留与 class 记录器关联的所有数据。有没有一种方法或模式可以访问 class 数据?
编辑:想声明这方面应该跟踪所有具有日志字段的 classes。也就是说,我可能有很多classes:MyClass, MyClass1, YourClass2, RepositoryClass,
等等
Nándor 所说的在技术上是正确的,但我的建议是:请尽可能避免访问私有成员或方法,因为它们是私有的是有原因的。例如,即使 class 的 public 界面不变,它们也可能会发生变化。所以你永远不能依赖它们的存在或它们的命名。此外,横切关注点也应尽可能遵循封装等设计原则。
这个具体案例是关于 Slf4J 记录器的,更准确地说是关于您希望避免创建冗余记录器对象的。好吧,关于对象创建,Slf4J 并不像您想象的那样愚蠢或粗心。所有 classes 实现 ILoggerFactory
使用内部映射来缓存给定 (class) 名称的现有记录器,参见例如
那么,为什么不放松一下,使用目标 class 名称从您的方面访问相应的记录器呢?如果目标 class 没有自己的静态记录器,这甚至可以工作:
申请classes:
package de.scrum_master.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClassWithLogger {
private Logger log = LoggerFactory.getLogger(MyClassWithLogger.class);
public void doSomething() {}
}
package de.scrum_master.app;
public class MyClassWithoutLogger {
public void doSomething() {}
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new MyClassWithLogger().doSomething();
new MyClassWithoutLogger().doSomething();
}
}
看点:
package de.scrum_master.aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public aspect TraceAspect {
pointcut executedMethods(Object targetObject) :
execution(!static * *(..)) && target(targetObject);
before(Object targetObject) : executedMethods(targetObject) {
Logger log = LoggerFactory.getLogger(targetObject.getClass());
log.info("Entering " + thisJoinPoint);
}
after(Object targetObject) : executedMethods(targetObject) {
Logger log = LoggerFactory.getLogger(targetObject.getClass());
log.info("Exiting " + thisJoinPoint);
}
}
配置 Slf4J 以使用简单记录器的控制台日志:
[main] INFO de.scrum_master.app.MyClassWithLogger - Entering execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithLogger - Exiting execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Entering execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Exiting execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())