0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В Java аннотации встречаются часто, но особенно много их в Spring Boot. Чтобы понять, как работает фреймворк, нужно разобраться в устройстве аннотаций. В этом уроке мы познакомимся с ними и узнаем, как они работают.</p>
1
<p>В Java аннотации встречаются часто, но особенно много их в Spring Boot. Чтобы понять, как работает фреймворк, нужно разобраться в устройстве аннотаций. В этом уроке мы познакомимся с ними и узнаем, как они работают.</p>
2
<p><strong>Аннотации</strong>- это механизм со своим синтаксисом, который позволяет добавлять метаданные в код. Например, так мы можем добавить какую-то дополнительную информацию, которую затем можно прочитать из исходного кода class-файлов или получить<strong>в рантайме</strong>- то есть во время работы программы. Сами по себе аннотации на код никак не влияют, в этом смысле они похожи на комментарии. Все действия происходят в коде, который ищет аннотации и на их основе меняет поведение.</p>
2
<p><strong>Аннотации</strong>- это механизм со своим синтаксисом, который позволяет добавлять метаданные в код. Например, так мы можем добавить какую-то дополнительную информацию, которую затем можно прочитать из исходного кода class-файлов или получить<strong>в рантайме</strong>- то есть во время работы программы. Сами по себе аннотации на код никак не влияют, в этом смысле они похожи на комментарии. Все действия происходят в коде, который ищет аннотации и на их основе меняет поведение.</p>
3
<p>Аннотации можно указывать на разных уровнях кода. Сюда входят классы, методы и параметры:</p>
3
<p>Аннотации можно указывать на разных уровнях кода. Сюда входят классы, методы и параметры:</p>
4
<p>Некоторые аннотации выглядят как метка - @RestController, другие похожи на вызов метода с параметрами - @RequestMapping("/api"). Принцип работы от этого не меняется: аннотация не превращается в вызов метода, она остается меткой с дополнительными данными.</p>
4
<p>Некоторые аннотации выглядят как метка - @RestController, другие похожи на вызов метода с параметрами - @RequestMapping("/api"). Принцип работы от этого не меняется: аннотация не превращается в вызов метода, она остается меткой с дополнительными данными.</p>
5
<p>Зачем аннотации вообще нужны? Во-первых, они значительно сокращают объем<strong>шаблонного кода</strong>- это повторяющийся одинаковый код, который нужен для конфигурации приложения, соединения его частей друг с другом или других задач. Раньше ту же задачу решали с помощью конфигурационных XML-файлов, которые иногда были просто огромными. Из-за этого Java-программистов часто называли XML-программистами. Активное использование аннотаций существенно упростило этот процесс.</p>
5
<p>Зачем аннотации вообще нужны? Во-первых, они значительно сокращают объем<strong>шаблонного кода</strong>- это повторяющийся одинаковый код, который нужен для конфигурации приложения, соединения его частей друг с другом или других задач. Раньше ту же задачу решали с помощью конфигурационных XML-файлов, которые иногда были просто огромными. Из-за этого Java-программистов часто называли XML-программистами. Активное использование аннотаций существенно упростило этот процесс.</p>
6
<h2>Встроенные аннотации</h2>
6
<h2>Встроенные аннотации</h2>
7
<p>Подавляющее большинство аннотаций в реальных проектах написаны разработчиками библиотек, а еще буквально несколько аннотаций встроено прямо в Java. Например, аннотация @Deprecated позволяет отметить класс или метод как устаревший. Эту информацию затем можно увидеть в подсказках редактора. Такая аннотация помогает другим программистам при выборе классов и методов для реализации их задач:</p>
7
<p>Подавляющее большинство аннотаций в реальных проектах написаны разработчиками библиотек, а еще буквально несколько аннотаций встроено прямо в Java. Например, аннотация @Deprecated позволяет отметить класс или метод как устаревший. Эту информацию затем можно увидеть в подсказках редактора. Такая аннотация помогает другим программистам при выборе классов и методов для реализации их задач:</p>
8
<p>Самая часто используемая аннотация - это @Override. Она указывает, что помеченный метод должен переопределять метод наследуемого класса или реализовывать метод интерфейса. Сама аннотация не обязательна при переопределении, но она помогает избежать ошибок и сделать код проще для чтения:</p>
8
<p>Самая часто используемая аннотация - это @Override. Она указывает, что помеченный метод должен переопределять метод наследуемого класса или реализовывать метод интерфейса. Сама аннотация не обязательна при переопределении, но она помогает избежать ошибок и сделать код проще для чтения:</p>
9
<h2>Кастомные аннотации</h2>
9
<h2>Кастомные аннотации</h2>
10
<p>С такими аннотациями мы будем встречаться чаще всего. Изучить их работу заранее невозможно - каждая конкретная аннотация обрабатывается своим образом и приводит к своим последствиям. Причем в большинстве случаев программист до конца не знает, что на самом деле происходит внутри.</p>
10
<p>С такими аннотациями мы будем встречаться чаще всего. Изучить их работу заранее невозможно - каждая конкретная аннотация обрабатывается своим образом и приводит к своим последствиям. Причем в большинстве случаев программист до конца не знает, что на самом деле происходит внутри.</p>
11
<p>С одной стороны, это хорошо - можно сфокусироваться на важном. С другой стороны, из-за этого код начинает работать как магия, и это может стать проблемой.</p>
11
<p>С одной стороны, это хорошо - можно сфокусироваться на важном. С другой стороны, из-за этого код начинает работать как магия, и это может стать проблемой.</p>
12
<p>Изучим пример типичного контроллера на Spring Boot. Здесь можно насчитать около десятка аннотаций, причем из разных пакетов:</p>
12
<p>Изучим пример типичного контроллера на Spring Boot. Здесь можно насчитать около десятка аннотаций, причем из разных пакетов:</p>
13
<p>Как классы или интерфейсы, аннотации тоже имеют свое определение, поэтому их необходимо импортировать. Редактор делает это самостоятельно, поэтому тут проблем возникнуть не должно.</p>
13
<p>Как классы или интерфейсы, аннотации тоже имеют свое определение, поэтому их необходимо импортировать. Редактор делает это самостоятельно, поэтому тут проблем возникнуть не должно.</p>
14
<h3>Устройство кастомных аннотаций</h3>
14
<h3>Устройство кастомных аннотаций</h3>
15
<p>Посмотрим, как определять и обрабатывать аннотации. Эти знания помогут разобраться в принципе работы аннотаций, а еще вопросы на эту тему часто задают на собеседованиях. Напишем аннотацию @LogExecutionTime, которая замеряет время выполнения помеченного ей метода:</p>
15
<p>Посмотрим, как определять и обрабатывать аннотации. Эти знания помогут разобраться в принципе работы аннотаций, а еще вопросы на эту тему часто задают на собеседованиях. Напишем аннотацию @LogExecutionTime, которая замеряет время выполнения помеченного ей метода:</p>
16
<p>Иронично, что определение аннотации само помечено ими. В коде выше мы видим три обязательные аннотации:</p>
16
<p>Иронично, что определение аннотации само помечено ими. В коде выше мы видим три обязательные аннотации:</p>
17
<ul><li>@interface определяет саму аннотацию</li>
17
<ul><li>@interface определяет саму аннотацию</li>
18
<li>@Retention определяет жизненный цикл аннотации, то есть указывает, как долго аннотация должна оставаться с кодом. В этом случае аннотация должна быть доступна в рантайме, потому что именно так мы будем ее обрабатывать</li>
18
<li>@Retention определяет жизненный цикл аннотации, то есть указывает, как долго аннотация должна оставаться с кодом. В этом случае аннотация должна быть доступна в рантайме, потому что именно так мы будем ее обрабатывать</li>
19
<li>@Target определяет, где мы будем применять аннотацию (например, в методах)</li>
19
<li>@Target определяет, где мы будем применять аннотацию (например, в методах)</li>
20
</ul><p>Аннотация готова, можно начинать применять ее. При этом в работе кода ничего не поменяется, потому что обработчик еще не написан:</p>
20
</ul><p>Аннотация готова, можно начинать применять ее. При этом в работе кода ничего не поменяется, потому что обработчик еще не написан:</p>
21
<p>Дальше мы напишем обработчик аннотации. Это обычный Java-код, поэтому нужно убедиться, что он выполняется до того, как исполнение дойдет до кода с аннотациями. В нашем случае обработчик выполняется в методе main():</p>
21
<p>Дальше мы напишем обработчик аннотации. Это обычный Java-код, поэтому нужно убедиться, что он выполняется до того, как исполнение дойдет до кода с аннотациями. В нашем случае обработчик выполняется в методе main():</p>
22
<p>Здесь мы видим<strong>рефлексию</strong>- технику, которая отображает информацию о программе во время ее работы. Чтобы использовать ее, мы берем все методы класса SomeService, находим методы с аннотацией LogExecutionTime и вызываем их методы, проверяя время выполнения.</p>
22
<p>Здесь мы видим<strong>рефлексию</strong>- технику, которая отображает информацию о программе во время ее работы. Чтобы использовать ее, мы берем все методы класса SomeService, находим методы с аннотацией LogExecutionTime и вызываем их методы, проверяя время выполнения.</p>
23
<h3>Параметры кастомных аннотаций</h3>
23
<h3>Параметры кастомных аннотаций</h3>
24
<p>Добавим в @LogExecutionTime два параметра. Первый временно выключит логирование, а второй задаст минимальное время выполнения, ниже которого логировать не нужно:</p>
24
<p>Добавим в @LogExecutionTime два параметра. Первый временно выключит логирование, а второй задаст минимальное время выполнения, ниже которого логировать не нужно:</p>
25
<p>Параметры описываются внутри тела аннотации определенным способом. Он похож на определение методов с отсутствующим телом и возможностью указать значение по умолчанию. Кстати, значение по умолчанию можно и не прописывать. В таком случае компилятор потребует указать его при добавлении аннотации:</p>
25
<p>Параметры описываются внутри тела аннотации определенным способом. Он похож на определение методов с отсутствующим телом и возможностью указать значение по умолчанию. Кстати, значение по умолчанию можно и не прописывать. В таком случае компилятор потребует указать его при добавлении аннотации:</p>
26
26