Skip to content

Latest commit

 

History

History
126 lines (84 loc) · 5.77 KB

File metadata and controls

126 lines (84 loc) · 5.77 KB

Reflection для аннотаций

1. Что такое reflection в контексте аннотаций

Reflection — это механизм Java, позволяющий исследовать и изменять поведение классов, методов и полей во время выполнения. С аннотациями reflection используется для:

  • чтения метаданных (например, какие методы помечены @Transactional);
  • динамического вызова логики в зависимости от аннотаций (например, обработчики событий, DI-фреймворки);
  • генерации кода или конфигурации на основе аннотаций.

2. Ключевые методы для работы с аннотациями

В Java аннотации — это тоже объекты (интерфейсы), доступные через reflection API. Класс Class, Method, Field, Constructor и Package имеют методы:

  • getAnnotation(Class<A> annotationClass) — возвращает аннотацию указанного типа или null;
  • getAnnotations() — возвращает все аннотации (включая унаследованные);
  • getDeclaredAnnotations() — возвращает только аннотации, объявленные явно (без наследования);
  • isAnnotationPresent(Class<? extends Annotation> annotationClass) — проверяет наличие аннотации.

3. Простой пример

Создадим свою аннотацию и используем её на классе:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    String value();
}

Применим:

public class Demo {
    @MyAnnotation("test method")
    public void doSomething() { }
}

Прочитаем через reflection:

Class<?> clazz = Demo.class;
for (Method method : clazz.getDeclaredMethods()) {
    if (method.isAnnotationPresent(MyAnnotation.class)) {
        MyAnnotation ann = method.getAnnotation(MyAnnotation.class);
        System.out.println("Метод " + method.getName() + 
                           " помечен аннотацией со значением: " + ann.value());
    }
}

Вывод:

Метод doSomething помечен аннотацией со значением: test method

4. Ретеншн — когда доступна аннотация

Чтобы работать с аннотацией через reflection, нужно указать:

@Retention(RetentionPolicy.RUNTIME)

Иначе:

  • SOURCE — аннотация видна только компилятору (например, @Override);
  • CLASS — сохраняется в class-файле, но недоступна во время выполнения;
  • RUNTIME — доступна через reflection.

5. Типичные практики использования

A. Фреймворки DI (Spring, CDI, Guice)

  • Читают аннотации (@Component, @Inject, @Autowired).
  • Создают объекты или прокси на основе метаданных.

B. Валидация

  • Аннотации вроде @NotNull, @Size читаются через reflection → валидатор проверяет входные данные.

C. Логирование / AOP

  • @LogExecutionTime → аспект ищет аннотированные методы и добавляет логи.

D. Кастомные процессоры

  • Вы можете динамически вызвать метод или изменить его поведение, если на нём есть определённая аннотация.

6. Ограничения и подводные камни

  • Reflection медленнее, чем прямой вызов, но для большинства задач это некритично (часто используется кеширование).
  • Аннотации не могут иметь поведение — они только хранят данные (метаданные).
  • Работа только с RUNTIME-аннотациями — аннотации с CLASS и SOURCE обрабатываются либо компилятором, либо аннотационными процессорами (APT).
  • SecurityManager (в старых версиях Java) мог запрещать reflection, в современных — через модули (Java 9+).

7. Разница с аннотационными процессорами

  • Reflection — работает во время выполнения (runtime).
  • Annotation processing (javax.annotation.processing) — работает во время компиляции, генерируя код или проверяя правильность использования аннотаций.

📌 Кратко для собеседования

Reflection позволяет во время выполнения получать аннотации у классов, методов и полей (getAnnotation, isAnnotationPresent), а затем использовать эти метаданные для динамической конфигурации, DI, AOP или валидации. Чтобы аннотация была доступна через reflection, нужно указать @Retention(RetentionPolicy.RUNTIME).