Java Аннотации и apt (основы) - PullRequest
5 голосов
/ 28 января 2011

Я действительно засучил рукава и впервые пытаюсь понять аннотации Java, и прочитал статьи Sun, Oracle и Wikipedia на эту тему.Их легко понять концептуально, но мне трудно собрать все кусочки головоломки вместе.

Следующий пример, вероятно, ужасная инженерия, но просто позабавьте меня (это пример !).

Допустим, у меня есть следующий класс:

public Widget
{
    // ...

    public void foo(int cmd)
    {
        switch(cmd)
        {
        case 1:
            function1();
            break;
        case 2:
            function2();
            break;
        case 3:
        default:
            function3();
            break;
        }
    }
}

Теперь, где-то еще в моем проекте, у меня есть другой класс, SpaceShuttle , который имеетметод с именем blastOff () :

public class SpaceShuttle
{
    // ...

    public void blastOff()
    {
        // ...
    }
}

Теперь я хочу настроить аннотацию с именем Widgetize , чтобы любые методы были помечены @ Widgetize будет вызывать Widget :: foo (int) до их собственного вызова.

@interface Widgetize
{
    int cmd() default 2;
}

Так что теперь давайте вернемся к SpaceShuttle:

public class SpaceShuttle
{
    // ...

    @Widgetize(3)
    public void blastOff()
    {
        // Since we pass a cmd of "3" to @Widgetize,
        // Widget::function3() should be invoked, per
        // Widget::foo()'s definition.
    }
}

Увы, мои вопросы!

  1. Я предполагаю, что где-то мне нужно определить процессор аннотаций;класс Java, который будет указывать, что делать, когда встречаются аннотации @Widgetize (int), да?Или это происходит, скажем, в XML-файлах конфигурации, которые передаются в apt (подобно тому, как ant читает файлы build.xml)?

  2. Редактировать: Если я был прав насчет этих процессоров аннотаций в вопросе № 1 выше, то как мне "отобразить" / "зарегистрировать" / сделать эти процессоры доступными для apt?

  3. В buildscripts, обычно ли apt запускается до javac, так что изменения на основе аннотаций или генерация кода происходят до компиляции?(Это вопрос типа передового опыта).

Спасибо, и я прошу прощения за мои примеры кода, они оказались намного громоздче, чем я намеревался (!)

Ответы [ 5 ]

4 голосов
/ 28 января 2011

Это больше похоже на AOP (Аспектно-ориентированное программирование), чем на аннотации. Темы часто путаются, так как АОП использует аннотации для достижения своих целей. Вместо того, чтобы заново изобретать AOP, я бы порекомендовал поискать и существующую библиотеку AOP, например AspectJ .

Однако, чтобы ответить на ваш конкретный вопрос, есть два возможных подхода к достижению вашей цели.

Подход во время выполнения

Это подход, обычно используемый в контейнерах (например, Spring). Это работает так, что вместо того, чтобы создавать экземпляры своих классов самостоятельно, вы запрашиваете у контейнера экземпляр вашего класса.

Контейнер имеет логику для проверки класса на предмет любых RuntimeAnnotations (например, @Widgetize). Затем контейнер будет динамически создавать прокси вашего класса, который сначала вызывает правильный метод Widgetize, а затем вызывает целевой метод.

Затем контейнер вернет этот прокси исходному запрашивающему. Запрашивающий по-прежнему обнаружит, что он получил класс (или интерфейс), который он запрашивал, и не будет знать о поведении прокси, добавленном контейнером.

Это также поведение, используемое AspectJ.

Подход к усовершенствованию

Это подход, принятый AspectJ. Если честно, я не знаю много деталей о том, как это работает. Каким-то образом AspectJ будет сканировать ваши файлы классов (байт-код), выяснить, где находятся аннотации, а затем изменить сам байт-код, чтобы вызывать прокси-класс вместо фактического класса.

Преимущество этого подхода в том, что вам не нужно использовать контейнер. Недостатком является то, что теперь вы должны выполнить этот шаг улучшения после компиляции кода.

2 голосов
/ 28 января 2011

Я предполагаю, что где-то мне нужно определить процессор аннотаций; Java класс, который укажет, что делать когда аннотации @Widgetize (int) столкнулся, да? Или это случилось скажем, в XML-файлах конфигурации, которые получают в подходящее место (как читает муравей файлы build.xml)?

В Java 1.6 стандартный способ определения процессоров аннотаций - ServiceLoader SPI.

В buildscripts, обычно запускается apt до Javac, так что на основе аннотации изменения или генерация кода происходит до компиляции? (Это лучший вопрос типа практики).

APT должен иметь место перед компиляцией, так как он работает с исходными файлами (фактически с синтаксическими деревьями).

1 голос
/ 28 января 2011

Я часто использую метод перехватчиков с Hibernate.Hibernate требует, чтобы транзакция запускалась и фиксировалась вокруг каждого запроса.Вместо того, чтобы иметь много повторяющегося кода, я перехватываю каждый метод Hibernate и запускаю транзакцию в перехватчике.

Для этого я использую перехватчики метода AOP Alliance вместе с Google Guice.Используя их, вы используете аннотацию Widgetise, а затем с помощью Guice, чтобы сказать, где вы видите эту аннотацию, используйте перехватчик этого метода.Это делает следующий фрагмент Guice.

        bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), new TransactionalInterceptor);

Перехватчик перехватывает метод, затем вы можете вызвать foo, а затем сообщить перехватчику метода, чтобы он продолжил вызов исходного метода.Например (в упрощенном виде):

public class Interceptor implements MethodInterceptor {

    //PUT ANY DEPENDENCIES HERE IN A CONSTRUCTOR

    public Object invoke(MethodInvocation invocation) throws Throwable {

            //DO FOO HERE

            result = invocation.proceed();
        return result;
    }

}

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

0 голосов
/ 22 октября 2016

Аннотации могут обрабатываться как во время компиляции, так и во время выполнения.Для их обработки во время выполнения требуется использовать API-интерфейс отражения, который будет влиять на производительность, если это не будет сделано разумно.

Также возможно обрабатывать аннотации во время компиляции.Цель состоит в том, чтобы создать класс, который затем может быть использован вашим кодом.Существует определенный интерфейс, который должны удовлетворять обработчики аннотаций, и они должны быть объявлены для выполнения.

Посмотрите на следующую статью для примера, который структурно прост для вашего случая использования:

Обработка аннотации 101

0 голосов
/ 28 января 2011

Кажется, что в основе вашей путаницы лежит неверное убеждение, что аннотации - это нечто большее, чем просто метаданные. Прочтите эту страницу в руководстве по языку JSE 1.5. Вот соответствующий фрагмент:

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

В вашем коде

    @Widgetize(3)
    public void blastOff()

не приводит к выполнению Widget::function3() (например: в java мы ссылаемся на элемент как Widget.function3()) Аннотация - это просто эквивалент машиночитаемого комментария ( т.е. метаданные).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...