1
votes

I'm using a standard Spring @RestController inside a Spring Boot app that calls into Spring Integration to initiate a messaging flow. As I understand it, the hook into Spring Integration in this instance is to use a Gateway - there seems to be a few different ways that this can be done using the Java DSL.

I currently have this working in 2 different ways:

  1. by defining an interface marked with the @MessagingGateway annotation.
  2. by instantiating a new GatewayProxyFactoryBean(Consumer.class) and setting the channel.

Both of these feel a bit clunky - there appears to be a third, cleaner way, that allows you to not have to annotate or manually construct a GatewayProxyFactoryBean, and simply use a built-in Functional interface with a bean name. From the docs:

@Bean
public IntegrationFlow errorRecovererFlow() {
    return IntegrationFlows.from(Function.class, "errorRecovererFunction")
            .handle((GenericHandler<?>) (p, h) -> {
                throw new RuntimeException("intentional");
            }, e -> e.advice(null))
            .get();
}


@Autowired
@Qualifier("errorRecovererFunction")
private Function<String, String> errorRecovererFlowGateway;

However, the bean errorRecovererFunction does not appear to get registered and the application fails to start.

Field errorRecovererFlowGateway in MyController required a bean of type 'java.util.function.Function' that could not be found.

Am I missing something here?

Thanks in advance.

1
Any chances that you can share with us simple project on GitHub to let us to play and reproduce? - Artem Bilan
So far everything is good and I hope you have an @EnableIntegration somewhere or this is a Spring Boot application. Also be sure that controller and Integration flow are in the same context. - Artem Bilan

1 Answers

0
votes

I did this application:

@SpringBootApplication
@RestController
public class So52778707Application {

    @Autowired
    @Qualifier("errorRecovererFunction")
    @Lazy
    private Function<String, String> errorRecovererFlowGateway;

    @GetMapping("/errorRecoverer")
    public String getFromIntegrationGateway(@RequestParam("param") String param) {
        return this.errorRecovererFlowGateway.apply(param);
    }

    @Bean
    public IntegrationFlow errorRecovererFlow() {
        return IntegrationFlows.from(Function.class, "errorRecovererFunction")
                .handle((p, h) -> {
                    throw new RuntimeException("intentional");
                })
                .get();
    }

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

}

Pay attention to the @Lazy annotation on the errorRecovererFlowGateway autowiring property. The Docs about this annotation says:

If you want to influence the startup creation order of certain beans, consider declaring some of them as @Lazy (for creation on first access instead of on startup) or as @DependsOn certain other beans (making sure that specific other beans are created before the current bean, beyond what the latter’s direct dependencies imply).

I think we need to clarify in Spring Integration Reference Manual that beans created during IntegrationFlow parsing cannot be inject as is, but @Lazy annotation should be considered for deferred bean resolution.