In this tutorial, you'll see how to externalize configurations of the Spring boot microservices using Spring cloud config server.
Spring cloud config server
With the Config Server, you have a central place to manage external properties for applications across all environments. This centralized configuration makes it easy to manage configuration when you have multiple microservices.
As your microservice move through various deployment stages from dev to qa to production, you can manage the configuration between those environments easily with externalized configuration and be certain that applications have everything they need to run when they are deployed.
How does Spring cloud config server work
You can create a config server application with the necessary information about the repository where configuration files are kept. You can also use discovery server to register the config server application.
In the microservices you can provide the location of the config server using spring.config.import
property.
This is now the default way to bind to Config Server.
Spring Cloud config example
In this microservice externalized configuration using cloud config example, we'll use the example shown in this post- Spring Boot Microservice - Service Registration and Discovery With Eureka as our base example and make changes in it to externalize the configuration.
In the example we'll have two services CustomerService and AccountService to cater to customer and account related functionalities respectively. When customer information is retrieved it should also get the accounts associated with the specific customer. For getting the associated accounts for a customer we'll have to make a call from CustomerService to AccountService.
1. Config server application
We'll create config server as a separate application which also get registered with Eureka.
If you are using Spring Tool Suite, create a new Spring starter project and give the name as config-server. Give other details like Group and Artifact Id. In the dependencies select Config Server and Eureka Discovery Client as dependencies. Created pom.xml should be something like this.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.netjstech</groupId> <artifactId>configserver</artifactId> <version>0.0.1-SNAPSHOT</version> <name>config-server</name> <description>Configuration Server</description> <properties> <java.version>17</java.version> <spring-cloud.version>2022.0.4</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2. Using @EnableConfigServer annotation
In the generated ConfigServerApplication class add the @EnableConfigServer
annotation to mark this application
as a config server.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @EnableDiscoveryClient @EnableConfigServer @SpringBootApplication public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
@EnableDiscoveryClient is used to mark that this application is a discovery client and should be registered by the discovery server.
Note that @EnableDiscoveryClient is no longer required. You can put a DiscoveryClient implementation on the classpath to cause the Spring Boot application to register with the service discovery server.
3. Configuration for the config server
Config server needs to know the location of the repository where the configuration properties are saved. You can use GIT, BitBucket, DB, AWS S3 and many other options as your repository. In this example GIT is used as the repository of configuration files.
Give the location of the repository with this property- spring.cloud.config.server.git.uri
For example, if I have created a new repository named config-server-repository in github then I need to give location of this repository.
In your config-server application under src/main/resources create a file named application.yml and give the configuration similar to as given below.
server: port: 8084 spring: application: name: configserver cloud: config: server: git: uri: https://github.com/netjs/config-server-repository default-label: main username: GITHUB_USER password: GITHUB_PASSWORD clone-on-start: true eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka
server.port specifies the port config server listens on.
spring.application.name specifies the name of the application. The application gets registered with the discovery server with this name.
default-label: main means config server will try to get configuration stored in the main branch in the repository.
clone-on-start: true means repository should be cloned on startup
With this step done, config-server application is ready.
Changes in customer-service configuration to use config server
1. Adding dependencies
Your microservices should get configuration data through config-server now, so first thing is to set micro-services as config-client. For that add spring-cloud-starter-config dependency in the pom.xml of customer-service
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
2. Changes in application.yml
In the application.yml file comment the existing configuration and add the following.
spring: application: name: customer-service profiles: active: dev config: import: configserver:http://localhost:8084
In the config clients you can provide the location of the config server using spring.config.import property.
3. Adding configuration to repository
One important thing in the configuration is active profile which is dev. By default config-server looks for the file with the name in the format APPLICATION_NAME-PROFILE.yml (or .properties). For example, as per the configuration given above config-server will try to load customer-service-dev.yml file from the configured GIT repository. That way based on the current profile (dev, qa, prod), config server can load the correct file (APPLICATION_NAME-dev.yml, APPLICATION_NAME-qa.yml, APPLICATION_NAME-prod.yml).
You can create a directory where you want to store these configuration files and then do git init to initialize it as GIT repository. Connect it with your remote repository created in GitHub.
In the directory, create a file customer-service-dev.yml and add the previous configuration of the customer-service (which should be commented right now, if you are following this tutorial).
server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/customer username: DB_USERNAME password: DB_PASSWORD application: name: customer-service jpa: properties: hibernate: sqldialect: org.hibernate.dialect.MySQLDialect showsql: true
commit the changes to the repository.
4. Verifying the configuration
Start the config-server, eureka-discovery-service and customer-service applications.
The Config Service serves property sources from /{application}/{profile}/{label}. Since we don't have any label so configuration should be accessible from http://localhost:8084/customer-service/dev. If everything is set right then you should be able to see configuration you saved in customer-service-dev.yml by using this URL.
You can also check the logs to verify that your application is fetching configuration from config-server.
[2m2023-10-06T11:03:57.520+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mc.n.c.CustomerServiceApplication [0;39m [2m:[0;39m The following 1 profile is active: "dev" [2m2023-10-06T11:03:57.570+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.c.c.c.ConfigServerConfigDataLoader [0;39m [2m:[0;39m Fetching config from server at : http://localhost:8084 [2m2023-10-06T11:03:57.570+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.c.c.c.ConfigServerConfigDataLoader [0;39m [2m:[0;39m Located environment: name=customer-service, profiles=[default], label=null, version=153081cc68dff557826cbdc3498db09bf9aee448, state=null [2m2023-10-06T11:03:57.570+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.c.c.c.ConfigServerConfigDataLoader [0;39m [2m:[0;39m Fetching config from server at : http://localhost:8084 [2m2023-10-06T11:03:57.570+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.c.c.c.ConfigServerConfigDataLoader [0;39m [2m:[0;39m Located environment: name=customer-service, profiles=[dev], label=null, version=153081cc68dff557826cbdc3498db09bf9aee448, state=null [2m2023-10-06T11:03:57.570+05:30[0;39m [32m INFO[0;39m [35m26224[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mo.s.c.c.c.ConfigServerConfigDataLoader [0;39m [2m:[0;39m Fetching config from server at : http://localhost:8084
Spring Boot Config Data resolves configuration in a two step process. First it loads all configuration using the default profile. This allows Spring Boot to gather all configuration which may activate any additional profiles. After it has gathered all activated profiles it will load any additional configuration for the active profiles. Due to this you may see multiple requests being made to the Spring Cloud Config Server to fetch configuration.
Changes in account-service configuration to use config server
1. Add dependency
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
2. Changes in application.yml
server: port: 8082 spring: application: name: account-service profiles: active: dev config: import: optional:configserver:http://localhost:8084
If you use optional: prefix, config client won't fail if it is unable to connect to Config Server.
3. Adding configuration to repository
Create account-service-dev.yml file in the local directory and add the previous configuration of account-service there.
spring: datasource: url: jdbc:mysql://localhost:3306/account username: DB_USERNAME password: DB_PASSWORD jpa: properties: hibernate: sqldialect: org.hibernate.dialect.MySQLDialect showsql: true eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka
commit the changes to the repository.
4. Verifying the configuration
Start account-service and try to access http://localhost:8084/account-service/dev.
Once all the service are started you can access http://localhost:8081/customer/1 if everything is fine then you should get customer information along with the accounts.
That's all for this topic Spring Boot Microservice - Externalized Configuration With Spring Cloud Config. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
No comments:
Post a Comment