Расширьте функциональность класса с помощью процессора аннотаций во время компиляции - PullRequest
0 голосов
/ 25 декабря 2018

У меня есть следующий класс 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();
    }
}

Я смог сделать это с отражением во время выполнения, но это значительно увеличивает время запуска.Есть ли способ сделать это с помощью только аннотаций и собственного процессора аннотаций?Проще говоря, я хочу создать аннотацию, которая добавляет аннотированный метод к классу и добавляет произвольный вызов метода к уже существующему методу.

Я знаю, что обработка аннотаций на самом деле не поддерживает изменение источника,Мне было бы интересно узнать какой-либо другой способ, позволяющий мне выполнить вышеизложенное, не помещая реестр и связанный с ним код непосредственно в мой исходный код.

1 Ответ

0 голосов
/ 25 декабря 2018

Вы можете создать свой собственный перехватчик или создать свой собственный PostProcessor.Тем не менее, Spring имеет хорошую встроенную функцию (которая фактически используется во всей среде), называемую Application Events .Это хорошая штука, которая использует 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));
    }
}

ИМХО, это не слишком много кода для большого удобства использования такой функции.

Кроме того, если вы предпочитаете использовать value из @Counted вместо имени метода, вы можете сделать аннотацию аналогично , выполнив это .

...