Spring boot 2.0.2, перехват аннотаций Cloud Stream с Aop больше не работает - PullRequest
0 голосов
/ 04 июня 2018

Я пытался сделать заголовок как можно более явным и простым.

По сути, мне нужно перехватить использование аннотаций @Input и @Output в облачном потоке.Это необходимо для автоматического добавления определенного ChannelInterceptor в каждый MessageChannel.(Поведение в методе preSend будет немного отличаться, независимо от того, было ли сообщение создано или использовано).

Например, если я объявлю этот совет

@Around("@annotation(org.springframework.cloud.stream.annotation.Input)")
public Object interceptInput(ProceedingJoinPoint joinPoint) throws Throwable {
    LOG.debug("Intercepted @Input from method : {}", joinPoint.getSignature());

    Object returnValue = null;

    try {
        returnValue = joinPoint.proceed();
ChannelInterceptorManager.addInputInterceptor((AbstractMessageChannel)returnValue);
    } catch (Exception e) {
        LOG.warn("@Input error", e);
    }

    return returnValue;
}

, и я объявлю этот пример класса

@EnableBinding(Sink.class)
@Component
public class MyClass {

    @StreamListener(Sink.INPUT)
   public void handle(Object message) {
      // preSend has been called before this method
   }
}

Это отлично работало с Spring Boot 2.0.1, но не с Spring Boot 2.0.2, и я изо всех сил пытаюсь понять, почему.

Я не пробовал другое Cloudаннотации потока, но базовый Aop работает нормально.

Имейте в виду, что это предназначено для использования в JAR, поэтому я заранее не знаю классов или названий каналов, которые будут использоваться, янужно, чтобы это было автоматически и прозрачно для разработчика.

Спасибо!

Редактировать: Если кто-то, читающий это, не знаком с Cloud stream, интерфейс Sink объявляет метод, аннотированный @Input, так что включение привязки к нему сделает свое дело.

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Итак, BPP не полностью решает проблему, так как мне нужно отличать MessageChannel, созданный с помощью @Input, от тех, что созданы с помощью @Output.Компонент MessageChannel не несет эту информацию.Вот почему я использовал Aop для перехвата этих двух аннотаций отдельно.

Для понимания: я также подумал об использовании @GlobalChannelInterceptor с шаблонами, содержащими либо «вход», либо «выход», но этоозначает применение таких шаблонов к конечному пользователю.Я оставляю это решение в качестве крайней меры, но я хотел бы, чтобы этот процесс был полностью незаметным и без последствий при использовании банки.Вот где AOP пригодился, но это новое поведение из 2.0.2, безусловно, проблематично в моем случае.

Редактировать: Таким образом, проблема с изменением версии - порядок инициализации бина, для любого, имеющего подобную проблемус весенней загрузкой 2.0.2.Если у вас есть контроль над каждым нужным компонентом, я предлагаю вам взглянуть на @ DependsOn.

В конечном счете, я решил свою конкретную проблему, используя BeanPostProcessor вместо AOP для отделения входов от выходов, как это было предложено @OlegZhurakousky.Ниже приведен метод работы:

@Autowired
    private AbstractBeanFactory beanFactory;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof AbstractMessageChannel) {
            try {
                RootBeanDefinition beanDefinition = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
                Method method = beanDefinition.getResolvedFactoryMethod();

                if (method != null) {
                    if (AnnotationUtils.findAnnotation(method, Input.class) != null) {
                        ((AbstractMessageChannel)bean).addInterceptor(/*Your input ChannelInterceptor*/);
                    } else if (AnnotationUtils.findAnnotation(method, Output.class) != null) {
                        ((AbstractMessageChannel)bean).addInterceptor(/*Your output ChannelInterceptor*/);
                    }
                }
            } catch (Exception e) {
                // exception can be thrown by the bean factory
            }
        }

        return bean;
    }
0 голосов
/ 04 июня 2018

Не уверен, что произошло между загрузкой 2.0.1 и 2.0.2, но вышеприведенное звучит как довольно сложный способ сделать что-то простое.Почему бы просто не зарегистрировать BPP, где вы можете добавить перехватчики до / после канала во время инициализации.

...