AspectJ - Creating a global Logger field using an

2019-02-15 08:31发布

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?

2条回答
乱世女痞
2楼-- · 2019-02-15 08:54

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.

查看更多
Luminary・发光体
3楼-- · 2019-02-15 09:12

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());
    }
}
查看更多
登录 后发表回答