Spring Integration: повторно использовать определение MessageProducer - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть исходящий шлюз для мыльных вызовов (MarshallingWebServiceOutboundGateway) со сложной настройкой.Мне нужно использовать это определение шлюза из нескольких потоков.Вопрос пружинная интеграция: на MessageProducer можно ссылаться только после того, как чем-то похож, но этот вопрос касается правильного использования прототипа области действия bean-компонента Spring для соавторов интеграции.

У меня естьотдельный файл конфигурации, который устанавливает шлюз и его зависимости:

@Bean
public MarshallingWebServiceOutboundGateway myServiceGateway() {
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setPackagesToScan("blah.*");

    MarshallingWebServiceOutboundGateway gateway = new MarshallingWebServiceOutboundGateway(
            serviceEndpoint, marshaller, messageFactory);
    gateway.setMessageSender(messageSender);
    gateway.setRequestCallback(messageCallback);

    return gateway;
}

Вот как я изначально пытался подключить исходящий шлюз из двух разных потоков в двух разных файлах конфигурации.

Водин файл конфигурации:

@Bean
public IntegrationFlow flow1() {
    MarshallingWebServiceOutboundGateway myServiceGateway = context.getBean("myServiceGateway", MarshallingWebServiceOutboundGateway.class);

    return IntegrationFlows
            .from(Http.inboundGateway("/res1")
                    .requestMapping(r -> r.methods(HttpMethod.GET))
            .transform(soapRequestTransformer)
            .handle(myServiceGateway) // wrong: cannot be same bean
            .transform(widgetTransformer)
            .get();
}

В отдельном файле конфигурации:

@Bean
public IntegrationFlow flow2() {
    MarshallingWebServiceOutboundGateway myServiceGateway = context.getBean("myServiceGateway", MarshallingWebServiceOutboundGateway.class);

    return IntegrationFlows
            .from(Http.inboundGateway("/res2")
                    .requestMapping(r -> r.methods(HttpMethod.GET))
            .transform(soapRequestTransformer)
            .handle(myServiceGateway) // wrong: cannot be same bean
            .transform(widgetTransformer)
            .handle(servicePojo)
            .get();
}

Это проблема, потому что - насколько я понимаю - myServiceGateway не может быть одним и тем же экземпляром, посколькуЭкземпляр имеет только один исходящий канал и не может принадлежать двум разным потокам.

В связанном вопросе весенняя интеграция: на MessageProducer можно ссылаться только один раз , @ artem-bilan рекомендуется не создаватьисходящий шлюз в методе @Bean, а не простой метод, который создает новые экземпляры для каждого вызова.

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

Поскольку сообщение об ошибке, выходящее из IntegrationFlowDefinition.checkReuse(), говорит A reply MessageProducer may only be referenced once (myServiceGateway) - use @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) on @Bean definition., я хотел еще раз попробовать прототип области видимости.

Итак, я пытаюсь заставить Spring интеграции искать прототип шлюза из контекста по имени, надеясь получить другой экземпляр шлюза в flow1 и flow2:

.handle(context.getBean("myServiceGateway", 
    MarshallingWebServiceOutboundGateway.class))

И я аннотировал исходящийшлюз @ Определение бина с

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Но я вижу, что метод myServiceGateway() вызывается только один раз, несмотря на область действия прототипа, и при запуске приложения все еще происходит сбой с сообщением об ошибке, в котором рекомендуется использовать область действия прототипа- довольно запутанно, на самом деле; -)

Основано на Тайна вокруг Spring Integration и прототип * Я также попробовал:

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)

Приложение запускается, но ответы никогда недоберитесь до шага после ворот, widgetTransformer.(Еще более странно, что именно widgetTransformer пропускается: в flow1 результатом является нетрансформированный ответ шлюза, а в flow2 нетрансформированные сообщения попадают на шаг после элемента widgetTransformer, то есть servicePojo).Создание прокси-сервера из производителя сообщений, похоже, не очень хорошая идея.

Я действительно хочу докопаться до сути.Неправильное сообщение об исключении, которое просит использовать область прототипа, или я просто получаю это неправильно?Как можно избежать повторения определения bean-компонента для производителей сообщений, если мне нужно несколько таких производителей, которые настроены одинаково?

Использование Spring-интеграции 5.0.9.

1 Ответ

0 голосов
/ 22 сентября 2018

Я не совсем уверен, почему @Scope не работает, но вот обходной путь ...

@SpringBootApplication
public class So52453934Application {

    public static void main(String[] args) {
        SpringApplication.run(So52453934Application.class, args);
    }

    @Autowired
    private HandlerConfig config;

    @Bean
    public IntegrationFlow flow1() {
        return f -> f.handle(this.config.myHandler())
                .handle(System.out::println);
    }

    @Bean
    public IntegrationFlow flow2() {
        return f -> f.handle(this.config.myHandler())
                .handle(System.out::println);
    }

    @Bean
    public ApplicationRunner runner() {
        return args -> {
            context.getBean("flow1.input", MessageChannel.class).send(new GenericMessage<>("foo"));
            context.getBean("flow2.input", MessageChannel.class).send(new GenericMessage<>("bar"));
        };
    }

}

@Configuration
class HandlerConfig {

    public AbstractReplyProducingMessageHandler myHandler() {
        return new AbstractReplyProducingMessageHandler() {

            @Override
            protected Object handleRequestMessage(Message<?> requestMessage) {
                return ((String) requestMessage.getPayload()).toUpperCase();
            }

        };
    }

}

то есть делайте, как предложил @artem, но вводите компонент с фабрикойспособ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...