AspectJ - Создание глобального поля Logger с использованием объявления между типами

Я хотел бы создать объявление Inter-Type, которое объявляет (статический финал) экземпляр Logger внутри каждого класса.

Конструктор должен быть передан вмещающий класс Klazz.class значение:

@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;
}

Я написал вышеупомянутое решение, однако я не могу использовать thisJoinPoint вне AspectJ advice,

Если реализация Logger по умолчанию применяется к некоторому классу Klazz, как я могу изменить приведенный выше код для успешной передачи Klazz.class в конструктор Logger?

2 ответа

Вы можете объявить статический член для любого отдельного класса через объявление между типами:

public aspect LoggingAspect {
    static Logger MyClass.someField = Logger.getLogger(MyClass.class.getName());
}

Но это не очень гибко, потому что вы должны сделать это для каждого отдельного класса. Я просто хотел упомянуть об этом.

Чтобы добавить что-то, что не является технически, но эффективно статическим членом класса, просто используйте ассоциацию для каждого типа для вашего аспекта регистрации:

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
    }
}

Пример, похожий на этот, - это обычный шаблон - можно найти в превосходной книге Рамниваса Ладдада "Аспект J в действии" (2-е издание), глава 6.2.4. Это также упоминается в документации AspectJ.

Этот ответ дает правильное решение, размещенное ниже для удобства. Кроме того, он использует аннотации AspectJ, которые в настоящее время являются предпочтительными.

Недавно разработчики добавили API-интерфейс для аннотаций, я полагаю, с целью стандартизации разметки, как это делают многие другие популярные библиотеки, такие как Spring.

@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());
    }
}
Другие вопросы по тегам