Статьи

Создание пользовательских аннотаций с помощью Spring

Java Аннотации были введены с Java 5 еще в 2004 году как способ добавления метаданных в исходный код Java. Сегодня многие основные фреймворки, такие как Spring или Hibernate, сильно зависят от аннотаций.

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

Составление пользовательской аннотации

Предположим, у нас есть набор аннотаций Spring, которые мы часто используем вместе. Типичным примером является комбинация @Service и @Transactional:

1
2
3
4
5
@Service
@Transactional(rollbackFor = Exception.class, timeout = 5)
public class UserService {
    ...
}

Вместо того, чтобы повторять обе аннотации снова и снова, мы можем создать нашу собственную аннотацию, содержащую эти две аннотации Spring. Создать нашу собственную аннотацию очень просто и выглядит так:

1
2
3
4
@Service
@Transactional(rollbackFor = Exception.class, timeout = 5)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {}

Аннотация определяется с помощью ключевого слова @interface (вместо класса или интерфейса). Стандартная Java-аннотация @Retention используется для указания того, что аннотация должна обрабатываться во время выполнения. Мы также добавили обе аннотации Spring в нашу аннотацию.

Теперь мы можем использовать наши собственные аннотации @MyService для аннотации наших сервисов:

1
2
3
4
@MyService
public class UserService {
    ...
}

Spring теперь обнаруживает, что @MyService аннотирован @Service и @Transactional и обеспечивает то же поведение, что и в предыдущем примере, причем обе аннотации присутствуют в классе UserService.

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

Примеры использования

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

Может быть, нам нужно значение свойства в разных местах нашего кода. Свойства часто вводятся с использованием аннотации Spring @Value:

1
2
3
// injects configuration properties my.api.key
@Value("${my.api.key}"
private String apiKey;

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

1
2
3
@Value("${my.api.key}")
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiKey {}

В нашем коде теперь мы можем использовать @ApiKey вместо повтора выражения свойства везде:

1
2
@ApiKey
private String apiKey;

Другим примером являются интеграционные тесты. В тестах часто используются различные аннотации Spring для определения настроек теста. Эти аннотации могут быть сгруппированы с помощью пользовательской аннотации. Например, мы можем создать аннотацию @MockMvcTest, которая определяет настройку Spring для пробных тестов mvc:

1
2
3
4
5
6
@SpringBootTest
@AutoConfigureMockMvc(secure = false)
@TestPropertySource(locations = "classpath:test.properties")
@ExtendWith(SpringExtension.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MockMvcTest {}

Определение наших тестов теперь выглядит намного чище. Нам просто нужно добавить @MockMvcTest, чтобы получить полную настройку теста:

1
2
3
4
@MockMvcTest
public class MyTest {
    ...
}

Обратите внимание, что наша аннотация @MockMvcTest также содержит аннотацию @ExtendWith JUnit 5. Как и Spring, JUnit 5 также может обнаруживать эту аннотацию, если она добавлена ​​в вашу собственную пользовательскую аннотацию. Имейте в виду, что это не будет работать, если вы все еще используете JUnit 4. С JUnit 4 вы должны использовать @RunWith вместо @ExtendWith. К сожалению, @RunWith работает только тогда, когда размещается непосредственно в тестовом классе.

Примеры весной

Spring использует эту функцию в различных ситуациях для определения ярлыков для общих аннотаций.

Вот несколько примеров:

  • @GetMapping — это короткая версия для @RequestMapping (method = {RequestMethod.GET}).
  • @RestController — это сочетание @Controller и @ResponseBody.
  • @SpringBootApplication — это ярлык для @SpringBootConfiguration, @EnableAutoConfiguration и @ComponentScan.

Вы можете убедиться в этом сами, посмотрев на определение этих аннотаций в исходном коде Spring.

Опубликовано на Java Code Geeks с разрешения Михаэля Шаргага, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Составление пользовательских аннотаций с помощью Spring.

Мнения, высказанные участниками Java Code Geeks, являются их собственными.