2
votes

We configure two separate RestTemplateBuilder beans in a java @Configuration annotated class like so:

@Bean("internal_api")
public RestTemplateBuilder internalRestTemplateBuilder(@Autowired 
OAuthConsumerOperations oAuthConsumerOperations) {
...    
}

@Bean("external_api")
public RestTemplateBuilder externalRestTemplateBuilder(){
...
}

When we deploy the app to Pivotal Cloud Foundry Apps Manager, we get the error below. It is complaining that more than one RestTemplateBuilder bean was found when it is expecting only one.

2018-08-28T11:59:17.67-0400 [APP/PROC/WEB/0] OUT {"timeMillis":1535471957677,"thread":"main","level":"WARN","loggerName":"org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext","message":"Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'documentationPluginsBootstrapper' defined in URL [jar:file:/home/vcap/app/BOOT-INF/lib/springfox-spring-web-2.7.0.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL [jar:file:/home/vcap/app/BOOT-INF/lib/springfox-spring-web-2.7.0.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cloudFoundryEndpointHandlerMapping' defined in class path resource [org/springframework/boot/actuate/cloudfoundry/CloudFoundryActuatorAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cloudFoundryEndpointHandlerMapping' parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.web.client.RestTemplateBuilder' available: expected single matching bean but found 2: internal_api,external_api","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.impl.SLF4JLocationAwareLog","contextMap":{},"threadId":1,"threadPriority":5}

Is this a bug? Are you not all allowed to configure multiple RestTemplateBuilder beans when using spring actuator on Cloud Foundry? Is there a way around this error? If not, would creating RestTemplate beans instead of RestTemplateBuilders work? If that is the case, then does the CloudFoundryActuatorAutoConfiguration class require at least one RestTemplateBuilder bean to be defined when deployed on Cloud Foundry?

1

1 Answers

2
votes

My $0.02, but I don't think you should be creating RestTemplateBuilder instances. The docs for RestTemplateBuilder say:

In a typical auto-configured Spring Boot application this builder is available as a bean and can be injected whenever a RestTemplate is needed.

https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/client/RestTemplateBuilder.html

It's best if your app can be "typical", and I wouldn't stray from that unless there's a good reason. So I think you'd want to do something like this:

// this is created & injected by Spring Boot
@Autowired
private RestTemplateBuilder restTemplateBuilder;

@Bean("internal_api")
public RestTemplate internalRestTemplate(@Autowired OAuthConsumerOperations oAuthConsumerOperations) {
    return restTemplateBuilder.build();  // add additional config
}

@Bean("external_api")
public RestTemplate externalRestTemplate(){
    return restTemplateBuilder.build();  // add additional config
}

To address your questions specifically:

Is this a bug? Are you not all allowed to configure multiple RestTemplateBuilder beans when using spring actuator on Cloud Foundry? Is there a way around this error?

I can't say unequivocally but it seems that Actuator has a precondition which expects only one to exist. Should/could it support cases with more than one? Maybe, but it doesn't seem to do that at the moment.

If not, would creating RestTemplate beans instead of RestTemplateBuilders work?

I believe this is the way to go, see above.

If that is the case, then does the CloudFoundryActuatorAutoConfiguration class require at least one RestTemplateBuilder bean to be defined when deployed on Cloud Foundry?

No, it looks like Spring Boot will define one for you. Although, if you needed, you could override and create your own.