DEV Community

Marcin Piczkowski
Marcin Piczkowski

Posted on

Spring Cloud step-by-step (part 2)

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.

Generate project

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>
Enter fullscreen mode Exit fullscreen mode

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

@EnableConfigServer
Enter fullscreen mode Exit fullscreen mode

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

console log

Then add these properties in application.properties

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

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
Enter fullscreen mode Exit fullscreen mode

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

pricing:
  plan:
    basic: 5
    standard: 200
    vip: 500
Enter fullscreen mode Exit fullscreen mode

Commit the file.

git add pricing-service.yaml
git commit -m 'added config'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

and version configuration in properties:

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
kudzaitsapo profile image
Kudzai Tsapo

Thanks for the tutorial. It's worth noting that the ${HOME} setting works for Unix machines only. On windows, I had to use ${USERPROFILE} which worked.

Again, thanks for the tutorial.