Аннотации
Аннотация — метка на коде, которую читают компилятор, фреймворк или инструменты. Не меняет логику напрямую, но говорит «обращайся с этим особым образом».
Вы уже использовали их каждый день в Spring:
@RestController // Spring: сделай этот класс HTTP-контроллером
@GetMapping("/users") // Spring: этот метод обрабатывает GET /users
@Override // компилятор: проверь что я правда переопределяю
@Deprecated // инструменты: предупреди что метод устарел
@SuppressWarnings("all") // компилятор: не показывай предупреждения
Своя аннотация:
@Retention(RetentionPolicy.RUNTIME) // доступна в рантайме (нужно для рефлексии)
@Target(ElementType.METHOD) // можно ставить только на методы
public @interface LogExecutionTime {
String value() default ""; // параметр с дефолтом
}
@Retention — когда аннотация живёт:
SOURCE— только в исходниках, компилятор удаляет (например@Override)CLASS— в байт-коде, но недоступна в рантаймеRUNTIME— доступна через рефлексию в рантайме (все Spring-аннотации)
Копнуть глубже
Как фреймворки читают аннотации через рефлексию:
// Spring внутри делает что-то похожее
for (Method method : bean.getClass().getMethods()) {
if (method.isAnnotationPresent(LogExecutionTime.class)) {
LogExecutionTime ann = method.getAnnotation(LogExecutionTime.class);
// оборачивает вызов метода в прокси с таймером
}
}
Это именно то, как работает AOP в Spring (см. тему «AOP: Aspect, Advice, Pointcut»): Spring сканирует классы, находит аннотации, создаёт прокси.
@Target — куда можно ставить аннотацию:
ElementType.TYPE // класс, интерфейс, enum
ElementType.METHOD // метод
ElementType.FIELD // поле
ElementType.PARAMETER // параметр метода
ElementType.CONSTRUCTOR // конструктор
Мета-аннотации — аннотации на аннотациях. @Retention и @Target сами являются мета-аннотациями. Ещё одна важная — @Inherited: позволяет аннотации на классе наследоваться подклассами.
Annotation Processor — обработка аннотаций на этапе компиляции (не рантайм). Примеры: Lombok генерирует геттеры/сеттеры, MapStruct генерирует маппинг-код. Работает через javax.annotation.processing.Processor — компилятор вызывает процессор до генерации байт-кода.
• разницу @Retention SOURCE/CLASS/RUNTIME и как фреймворки читают аннотации (если дошёл до 2-го слоя).