Spring Cloud step-by-step (part 2)

By Marcin Piczkowski Comment
Subscribe

In the previous post we created basic Spring Web REST API for rental pricing.

In this post, we will transform it into Spring Cloud project and add the centralized configuration.

It means we will keep configuration for all our services in single place, easy for modification and all the changes will be discovered by services without the necessity of changing their code.

The project for this post is available at GitHub branch spring-cloud-2

Configuring Config Service

We need another application which will be our Config Service and Pricing Service will connect to it.

We can generate Config Service app with Spring Initializr at http://start.spring.io.

All we need is to choose “Config Server” and “Web” from dependencies.

image

This would generate app with maven dependencies in pom.xml:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

Then we need to tell Spring Boot that this is a Config Service app with annotation on main class:

@EnableConfigServer

It will add some new REST mappings to the application which we can see in logs when the application starts.

image

Then add these properties in application.properties

server.port=8888
spring.cloud.config.server.git.uri=${HOME}/cloudconfigs

The last property tells Config Service where to look for services configurations, e.g. we can use local git repo, GitHub or bitbucket.

We will use local git repo. Let’s create it. Execute commands in bash:

mkdir -p ${HOME}/cloudconfigs
cd ${HOME}/cloudconfigs
git init

Then create a new file pricing-service.yaml in ${HOME}/cloudconfigs and add these properties:

pricing:
  plan:
    basic: 5
    standard: 200
    vip: 500

Commit the file.

git add pricing-service.yaml
git commit -m 'added config'

Here we use different values than in the initial Pricing Service configuration to spot the difference.

These values will overwrite any local configuration in Pricing Service.

If we wanted, we could also add application.properties or application.yaml to the repo which would keep common properties for all services.

E.g. we could put

pricing:
  plan:
    basic: 1

but in this case, if we start Config Service and query for configuration for pricing-service the value will be overridden with setting from pricing-service.yaml We can check this at http://localhost:8888/pricing-service/default It would respond with JSON like:

{
   "name":"pricing-service",
   "profiles":[
      "default"
   ],
   "label":null,
   "version":"8ab2211dd33751b797afa3d0a0eea8fccc10e676",
   "state":null,
   "propertySources":[
      {
         "name":"/home/marcin/tmp/cloudconfig/application.yaml",
         "source":{
            "pricing.plan.basic":5,
            "pricing.plan.standard":200,
            "pricing.plan.vip":500
         }
      }
   ]
}

Configuring config client

In Pricing Service we need to add a dependency

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

and dependencyManagement section:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

and version configuration in properties:

<properties>
    ...
    <spring-cloud.version>Finchley.RC2</spring-cloud.version>
</properties>

Then add a file resources/bootstrap.yaml

This is a property file which will be read as first when the application starts.

It is how Spring Cloud works. It first reads bootstrap.yaml to determine additional configuration to be used.

In our cases, it will use the configuration from Config Service.

The file will look as follows:

spring:
  application:
    name: pricing-service
  cloud:
    config:
      uri: http://localhost:8888

where spring.application.name will be the name of the service telling Config Service which file to grab from config git repo and spring.cloud.config.uri is a URL of Config Service.

By default Config Service starts on localhost:8888.

Now if we start Pricing Service the order in which properties are resolved is the following:

  • pricing-service.properties in config git repo
  • application.yaml in config git repo (if property not present in pricing-service.properties)
  • application.yaml in pricing service (if property not present in application.yaml in config git repo)

What would happen if the Config Service was down? The local properties from Pricing Service will be used.

Config Service has many nice features like properties per spring profile or label and properties encryption. You can check a nice explanation here or of course in Spring Cloud docs

The final code for this part is available at GitHub spring-cloud-2 branch.

We have now centralized configuration for our services delivered by Config Service, but all services would need to have URL to the Config Service given at runtime (either in local application.yaml or through environment variable).

This is a bit cumbersome if there are different URLs for integration, QA, PROD environments.

In the next post we will add service discovery mechanism so that services can use only a friendly name and the URL will be provided from the service registry.

comments powered by Disqus