У меня есть следующий класс Spring Boot с пользовательской аннотацией Counted:
@RestController
@RequestMapping("/identity")
public class IdentityController {
@Autowired
private IdentityService identityService;
@PostMapping
@Counted(value = "post_requests_identity")
public Integer createIdentity() {
return identityService.createIdentity();
}
}
Обозначение Counted определяется следующим образом:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Counted {
String value();
}
Я хочу написать обработчик аннотаций, который эффективно заставляет мой Контроллер вести себя как в приведенном ниже коде.
@RestController
@RequestMapping("/identity")
public class IdentityController {
@Autowired
private IdentityService identityService;
@Autowired
private PrometheusMeterRegistry registry;
@PostConstruct
public void init() {
registry.counter("post_requests_identity");
}
@PostMapping
public Integer createIdentity() {
registry.counter("post_requests_identity").increment();
return identityService.createIdentity();
}
}
Мне удалось сделать это с помощью отражения во время выполнения, но это значительно увеличивает время запуска. Есть ли способ сделать это с помощью аннотаций и специального обработчика аннотаций? Проще говоря, я хочу создать аннотацию, которая добавляет аннотированный метод к классу и добавляет произвольный вызов метода к уже существующему методу.
Я знаю, что обработка аннотаций на самом деле не поддерживает изменение источника. Мне было бы интересно узнать какой-либо другой способ сделать это, не помещая реестр и связанный с ним код непосредственно в мой исходный код.
@DeanXu прав. в Java EE можно использовать Перехватчики. Если вы действительно настаиваете на изменении существующих источников во время компиляции, взгляните на Проект Ломбок. Они используют обработчик аннотаций в качестве точки входа и изменяют AST с помощью некоторого недокументированного API компилятора.
Я пробовал этот подход, но не нашел хорошего способа инициализировать свои счетчики с помощью Spring AOP API. В этом случае я использовал отражение, что мне не понравилось. На что мне обратить внимание в этом конкретном случае? Как бы то ни было, я не настаиваю на использовании обработки аннотаций для достижения этой функциональности.




Вы можете сделать свой собственный перехватчик или создать свой собственный PostProcessor. Однако в Spring есть хорошая встроенная функция (которая фактически используется повсюду во фреймворке) под названием События приложения. Это приятная мелочь, которая использует DI и Spring в качестве шины через небольшую симпатичную абстракцию именно для таких нужд, как ваши. (также см. статью этот блог для получения дополнительной информации).
Со стороны, принимающей ApplicationEvent, у вас может быть такая простая установка, как:
// Create an ApplicationEvent type for your "count" event like so...
public class CountEvent extends ApplicationEvent {
private String counterName;
...
}
// Create a class that accepts the count events and meters them...
@Component
public class MeterEventService {
@Autowired
private PrometheusMeterRegistry registry;
@EventListener
public void createIdentity(CountEvent countEvent) {
String countedMethod = countEvent.getCounterName();
registry.counter(countedMethod).increment();
}
}
Со стороны отправителя вы можете использовать свою собственную аннотацию, чтобы легко продолжить с того места, где вы остановились в своем вопросе:
@Component
@Aspect
public class Mail {
// Autowire in ApplicationContext
private ApplicationContext applicationContext;
@After("execution (@<package to annotation>.Counted * *(..))")
public void countMetric(JoinPoint jp){
MethodSignature signature = (MethodSignature) jp.getSignature();
String method = signature.getMethod().getName();
applicationContext.publishEvent(new CountEvent(method));
}
}
IMHO это не слишком много кода для большого удобства наличия такой функции.
Кроме того, если вы предпочитаете использовать value из @Counted вместо имени метода, вы можете аналогичным образом снять аннотацию делая это.
Я нашел решение, используя АОП и библиотеку отражений. Спасибо, что направили меня на правильный путь.
Что вам нужно, это АОП, а не обработка аннотаций