问题
I'd like to create an Inter-Type declaration that declares a (static final) Logger instance inside each class.
The constructor should be passed the enclosing class Klazz.class
value:
@Aspect
public class LoggerAspect {
public interface Logger {
}
public static class LoggerImpl implements Logger {
private static final Logger logger =
new Logger(thisJoinPoint.getTarget().getClass()/*.getName()*/);
}
@DeclareParents(value="com.my.api..*",defaultImpl=LoggerImpl.class)
private Logger implementedInterface;
}
I wrote the above solution, however I'm unable to use thisJoinPoint
outside of an AspectJ advice
.
If the Logger default implementation is applied to some class Klazz, how can I modify the above code to successfully pass Klazz.class to the Logger constructor?
回答1:
You can declare a static member on any single class via inter-type declaration:
public aspect LoggingAspect {
static Logger MyClass.someField = Logger.getLogger(MyClass.class.getName());
}
But this is not very flexible because you need to do it for each single class. I just wanted to mention it.
In order to add something which is not technically but effectively a static member to a class, just use per-type association for your logging aspect:
public aspect LoggingAspect
pertypewithin(org.foo..*) // per-type association
{
Logger logger;
after() : staticinitialization(*) { // run 1x after class-loading
logger = Logger.getLogger(
getWithinTypeName() // type associated with aspect instance
);
}
pointcut logged() : // what to log, e.g. public methods
execution(public * *(..)); // (pointcut could also be abstract
// and refined in sub-aspects)
before() : logged() {
logger.log(...); // logging action
}
}
An example similar to this one - it is a common pattern - can be found in Ramnivas Laddad's excellent book AspectJ in action (2nd edition), chapter 6.2.4. It is also mentioned in the AspectJ documentation.
回答2:
This answer gives the correct solution, posted below for convenience. Additionally it uses AspectJ annotations which is the preferred notation nowadays.
The developers recently added the annotation API, I presume with the intention of standardising the markup as many other popular libraries like Spring are also doing.
@Aspect("pertypewithin(com.something.*))")
public abstract class TraceAspect {
Logger logger;
@Pointcut
public abstract void traced();
@Pointcut("staticinitialization(*)")
public void staticInit() {
}
@After(value = "staticInit()")
public void initLogger(JoinPoint.StaticPart jps) {
logger = Logger.getLogger(jps.getSignature().getDeclaringTypeName());
}
@Before(value = "traced()")
public void traceThatOne(JoinPoint.StaticPart jps) {
logger.log(jps.getSignature().getName());
}
}
来源:https://stackoverflow.com/questions/12126436/aspectj-creating-a-global-logger-field-using-an-inter-type-declaration