Writing Client Applications

Refer to the sample apps in the “greeting” repository to follow along with the code in this topic.

To use a Spring app with a Service Registry service instance, you must add the dependencies listed in Client Dependencies to your app’s build file. Be sure to include the dependencies for Service Registry as well.

Register a Service

To register with a Service Registry service instance, your app must include the @EnableDiscoveryClient annotation on a configuration class.

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class MessagesApplication {
    //...

The app’s Eureka instance name (the name by which it will be registered in Eureka) will be derived from the value of the spring.application.name property on the app. If you do not provide a value for this property, the app’s Eureka instance name will be derived from its Cloud Foundry application name, as set in manifest.yml:

---
applications:
  - name: greeter-messages
    instances: 1
    memory: 1G
  ...

Set the spring.application.name property in application.yml:

spring:
  application:
    name: greeter-messages

Note: If the application name contains characters which are invalid in a hostname, the app will be registered with the Service Registry service instance using the application name with each invalid character replaced by a hyphen (-) character (for example, given an application name of “greeter_messages”, the Eureka application name used to register the app with the Service Registry service instance will be greeter-messages). See Eureka Application Name Configuration.

Register Using Container-to-Container Networking

To use Cloud Foundry’s container networking (see Understanding Container-to-Container Networking in the Pivotal Cloud Foundry documentation) with the app, your application.yml must specify a spring.cloud.services.registrationMethod of direct.

spring:
  application:
    name: greeter-messages
  cloud:
    services:
      registrationMethod: direct

Before a client app can use the Service Registry to reach this directly-registered app, you must add a network policy that allows traffic from the client app to this app. See the Consume Using Container-to-Container Networking section for more information.

Consume a Service

Follow the below instructions to consume a service that is registered with a Service Registry service instance.

Discover and Consume a Service Using RestTemplate

A consuming app must include the @EnableDiscoveryClient annotation on a configuration class.

@SpringBootApplication
@EnableDiscoveryClient
public class GreeterApplication {

  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
  //...

To call a registered service, a consuming app can use a URI with a hostname matching the name with which the service is registered in the Service Registry. This way, the consuming app does not need to know the service app’s actual URL; the Registry will take care of finding and routing to the service.

Note: If the name of the registered app contains characters which are invalid in a hostname, that app will be registered with the Service Registry service instance using the application name with each invalid character replaced by a hyphen (-) character. For example, given an application name of “greeter_messages”, the Eureka application name used to register the app with the Service Registry service instance will be greeter-messages. See Eureka Application Name Configuration.

By default, Service Registry requires HTTPS for access to registered services. If your client app is consuming a service app which has been registered with the Service Registry instance using route registration (see the Register a Service section above), you can use a schemeless URI (as //greeter-messages) to access the service. Spring Cloud Netflix Ribbon will default to using an HTTPS route if one is available and to an HTTP route otherwise.

The Messages app is registered with the Service Registry as greeter-messages, so the Greeter app uses the base URI /greeter-messages to communicate with Messages.

@Service
public class GreeterService {

  private static final String URI_TEMPLATE = UriComponentsBuilder.fromUriString("//greeter-messages/greeting")
      .queryParam("salutation", "{salutation}")
      .queryParam("name", "{name}")
      .build()
      .toUriString();

The Greeter app uses a Greeting class to contain the response from Messages:

public class Greeting {

  private String message;

  @JsonCreator
  public Greeting(@JsonProperty("message") String message) {
    this.message = message;
  }

  public String getMessage() {
    return this.message;
  }

}

The greet() method of the GreeterService uses a RestTemplate to return a Greeting.

  public Greeting greet(String salutation, String name) {
    //...
    return rest.getForObject(URI_TEMPLATE, Greeting.class, salutation, name);
  }

Finally, the GreeterController maps its hello() method to /hello, and passes received request parameters to the GreeterService to get a greeting message to return to the user.

  @RequestMapping(value = "/hello", method = RequestMethod.GET)
  public String hello(@RequestParam(value = "salutation", defaultValue = "Hello") String salutation, @RequestParam(value = "name", defaultValue = "Bob") String name) {
    Greeting greeting = greeter.greet(salutation, name);
    return greeting.getMessage();
  }

Discover and Consume a Service Using Feign

If you wish to use Feign to consume a service that is registered with a Service Registry instance, your app must declare spring-cloud-starter-openfeign as a dependency.

Using Maven:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Using Gradle:

compile("org.springframework.cloud:spring-cloud-starter-openfeign")

Your consuming app must include the @EnableDiscoveryClient annotation on a configuration class. In order to have Feign client interfaces automatically configured, it must also use the @EnableFeignClients annotation.

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@RestController
public class GreeterApplication {

    @Autowired
    MessagesClient messagesClient;
    //...

The Greeter app uses a Greeting class to contain the response from Messages:

public class Greeting {

  private String message;

  @JsonCreator
  public Greeting(@JsonProperty("message") String message) {
    this.message = message;
  }

  public String getMessage() {
    return this.message;
  }
}

The GreeterApplication class has a method hello() which is mapped to /hello and uses a Feign client to access the Messages app.

    @RequestMapping(value = "/hello", method = GET)
    public String hello(@RequestParam(value="salutation", defaultValue="Hello") String salutation, @RequestParam(value="name", defaultValue="Bob") String name) {
      Greeting greeting =  messagesClient.greeting(name, salutation);
      return greeting.getMessage();
    }

In the Greeter app, the MessagesClient interface is a Feign client for the Messages app:

@FeignClient("greeter-messages")
interface MessagesClient {
  @RequestMapping(value = "/greeting", method = GET)
  Greeting greeting(@RequestParam("name") String name, @RequestParam("salutation") String salutation);
}

The Messages app is registered with the Service Registry instance as greeter-messages, so the @FeignClient annotation on the MessagesClient interface uses that Eureka application name. The interface declares one method, greeting(), which accesses the Messages app’s /greeting endpoint and sends along optional name and salutation parameters if they are provided.

Note: If the name of the registered app contains characters which are invalid in a hostname, that app will be registered with the Service Registry service instance using the application name with each invalid character replaced by a hyphen (-) character. For example, given an application name of “message_generation”, the Eureka application name used to register the app with the Service Registry service instance will be greeter-messages. See Eureka Application Name Configuration.

Consume Using Container-to-Container Networking

To use Cloud Foundry’s container networking (see Understanding Container-to-Container Networking in the Pivotal Cloud Foundry documentation) to reach an app registered with the Service Registry, you must add a network policy. You can do this using the Cloud Foundry Command Line Interface (cf CLI).

Note: Container networking support is included in the cf CLI version 6.30.0 and later.

Run the cf network-policies command to list current network policies:

$ cf network-policies
Listing network policies in org myorg / space dev as user...

source   destination   protocol   ports

Use the cf add-network-policy command to grant access from the Greeter app to the Messages app:

$ cf add-network-policy greeter --destination-app greeter-messages --protocol tcp --port 8080
Adding network policy to app greeter in org myorg / space dev as user...
OK

Use cf network-policies again to view the new access policy:

$ cf network-policies
Listing network policies in org myorg / space dev as user...

source    destination          protocol   ports
greeter   greeter-messages   tcp        8080

The Greeter app can now use container networking to access the Messages app via the Service Registry. For more information about configuring container networking, see Administering Container-to-Container Networking in the Pivotal Cloud Foundry documentation.

Disable HTTP Basic Authentication

The Spring Cloud Services Starter for Service Registry has a dependency on Spring Security. Unless your app has other security configuration, this will cause all app endpoints to be protected by HTTP Basic authentication.

If you do not yet want to address application security, you may turn off Basic authentication using a class that extends Spring Security’s WebSecurityConfigurerAdapter and is annotated with the Spring @Configuration annotation. The sample apps disable all default security for the development profile only, using the @Profile annotation:

@Configuration
@Profile("development")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests().anyRequest().permitAll()
        .and()
        .httpBasic().disable()
        .csrf().disable();
  }

}

For more information, see “Security” in the Spring Boot Reference Guide.

Create a pull request or raise an issue on the source for this page in GitHub