Configuration Client and RefreshScope for core Spring and Spring Boot Configuration Server

Content:

Introduction
I am sure everybody will accept that one of the initial steps of building a new application, is developing a configuration system.

I was part of a several green field projects and nearly every one them, one of the initial tasks was always to develop the configuration system. So in total, I guess I developed 7-8 configuration systems, after first 4-5 times, I asked myself isn’t a better way to do this. Later stages of my carrier, I encounter the cloud programming concepts and mainly Spring Boot and to my surprise, they already have an answer to my dilemma, Spring Cloud Config (https://cloud.spring.io/spring-cloud-config/).

Of course, with the initial joy, I start experimenting with it, with the help of the Spring Boot and build some ‘Hello World’s and proof of concepts, the thing was perfect for the Spring Boot applications, integration with Git, Profiles, configuration values automatically bind to ‘@Value’ annotations, ‘@RefreshScope’ so we can change the configuration values of our application on the run. So if we only program Spring Boot applications, we don’t have to spend any second about developing a configuration system.

Then I thought, would not be cool to use the Spring Cloud Config on the applications we already developed, that is the time point I experienced the shock, Spring Cloud Config does not support anything other then Spring Boot tool chain. Yes, you understood correctly, Spring outside of the Spring Boot technology stack can’t use the Spring Cloud Config, no central location for configuration, no refresh on the runtime, nada….

So my first question, how hard it can be to integrate Spring Cloud Config with core Spring, specially the ‘@RefreshScope’, the rest of the blog describes what we have to do to achieve that goal.

Solution
Ok, lets talk about the first good news then the bad news. First, Spring Cloud Config present all the configuration information over REST interfaces, so it will be easy to access any platform that communicate REST to access that information, fortunately this is no problem for core Spring.

Bad news are, core Spring does not know anything about the Environment configuration of the Spring Boot, it does not know anything about ‘@RefreshScope’ those are the things we have to implement.

So lets list our tasks,
– we have to create communication middle for accessing Spring Cloud Config
– we have to inform Spring with Environment and PropertySource about the configuration values we got from Spring Cloud Config
– a JMX facade to be able to access configuration values from the all over the Java Virtual Machine
– a @RefreshScope implementation
– a JMX Facade to be able to refresh @RefreshScope’d beans
– a Refresh REST Endpoint to refresh the configuration values externally for the application
– a bootstrap for Configuration Client

These to do’s will also form our project structure, instead of having one single project, I preferred little bit the plug and play approach, if people are not interested with the @RefreshScope or refreshing the application from outside, they can leave these dependencies out in their project so they will have no effect.

Project Structure
-‘configuration-api’ – this project is there mainly to be able to externalize the API of the configuration server to be used from several projects in the same JVM(via JMX) this way not all projects has to initialize the service. This pattern is quite useful in Micro Service design to save resource, so not every micro service investing resource to initialize the configuration services.
-‘configuration-core’ – is where the main functionality lies, it is responsible to store the configuration information and distribute to the interested parties. It is also responsible for the bootstrap configuration of the configuration system.
-‘configuration-client’ – is responsible for contacting the Spring Cloud Config and downloading the configuration information.
-‘configuration-refresher’ – is there provide the refresh endpoint to trigger the system to get the latest configuration information from Spring Cloud Config.
-‘configuration-scope’ – is there to introduce the ‘@RefreshScope’ annotation and for the implementation of the Refresh Scope outside of the Spring Boot.
-‘configuration-yaml’ – is there to be able to bootstrap the ‘configuration-core’ via YAML.
-‘configuration-driver’ – is there to test the concepts in this blog.
-‘configuration-tomcat’ – is to there start the Tomcat container for driver project.

Operation Principles
To be able to use our configuration service, first of all we would be able to make bootstrap configuration, for this purpose the configuration service will try to read from the property ‘org.salgar.configurationserver.propertyfile’ the location of the bootstrap configuration file(this functionality is realized in ‘YamlInitializer.java’ class in ‘configuration-yaml’ project). ‘YamlFileConfiguration’ is class based on ‘Apache Commons Configuration’ s ‘org.apache.commons.configuration.AbstractFileConfiguration’ so it bring the functionality to read the property files on the run and reflect the changes from bootstrap configuration to the configuration service.

Which looks like the following initially.

application:
 name: test
configuration:
 initial: HalliHallo
 server:
  url: http://localhost:8888

snippet 1

Really relevant part of it, our application is called ‘test’, which is really important while Spring Cloud Config can hold the configuration information about several applications and only way that application gets relevant information about itself is to have the application name.

Second one is naturally the URL of the Spring Cloud Config so our application can get is configuration information.

Now with this information, with the start of the Spring Application Context, our configuration service will load all the configuration information from the Spring Cloud Config. We need the ‘configuration-client’ communicate with Spring Cloud Config and deliver the results, unfortunately Spring Boot Configuration Server delivers the results in Spring Boot propriety format, namely as ‘org.springframework.cloud.config.environment.Environment’, to be able to process this information we have to port this class to core Spring world, which is realized in ‘configuration-api’ projects ‘org.salgar.configuration.api.environment.Environment’ class. This way we can interpret the information from Spring Cloud Config and feed to normal Spring’s configuration system.

Spring Cloud Config contains for test purposes following configuration information in Yaml format.


stageall:
 environment01:
  serviceUrl:
   'instance01': https://192.168.107.16/api/v0/orderApplication
   'instance02': https://192.168.107.17/api/v0/orderApplication
   'instance03': https://192.168.107.18/api/v0/orderApplication
   'instance04': https://192.168.107.19/api/v0/orderApplication
   'instance05': https://192.168.107.20/api/v0/orderApplication

stage01:
 environment01:
  serviceUrl:
   'instance01': https://140.18.159.16/api/v0/orderApplication
   'instance02': https://140.18.159.17/api/v0/orderApplication
   'instance03': https://140.18.159.18/api/v0/orderApplication
   'instance04': https://140.18.159.19/api/v0/orderApplication
   'instance05': https://140.18.159.20/api/v0/orderApplication
   
 environment02:
  serviceUrl:
   'instance01': https://environment02.server.xxx/api/v0/orderApplication
   'instance02': https://environment02.server.xxx/api/v0/orderApplication
   'instance03': https://environment02.server.xxx/api/v0/orderApplication
   'instance04': https://environment02.server.xxx/api/v0/orderApplication
   'instance05': https://environment02.server.xxx/api/v0/orderApplication

stage02:
 environment01:
  serviceUrl:
   'instance01': https://119.108.55.16/api/v0/orderApplication
   'instance02': https://119.108.55.17/api/v0/orderApplication
   'instance03': https://119.108.55.18/api/v0/orderApplication
   'instance04': https://119.108.55.20/api/v0/orderApplication
   'instance05': https://119.108.55.21/api/v0/orderApplication

snippet 2

We should naturally say to Spring Cloud Config where to find this file which happens in “bootstrap.yml” file of the Spring Cloud Config.

spring:
  cloud:
    config:
      server:
        native:
          searchLocations: file:///C:/config
  profiles:
    active: native

server:
  port: 8888

snippet 3

the configuration values are ‘searchLocations’ where the configuration file lies and the spring profile ‘native’ while we don’t want to use ‘git’ to keep our configuration values but a plain text file(for feasibility study purposes, otherwise it is totally fine to use Git). Our configuration file is also called ‘test.yml’ because as you might remember we configured our applications name in bootstrap as ‘test’.

Now that we know how to get the configuration information from Spring Cloud Config, how do we feed to the normal Spring configuration system. Two classes are responsible for this ‘org.salgar.configuration.initialisation.BootstapPropertySourceConfiguration’, which is responsible for feeding the bootstrap information and ‘org.salgar.configuration.initialisation.ConfigurationServerPropertySourceInitializer’, which is responsible for feeding the Spring Cloud Config information. They both implement the ‘org.springframework.core.Ordered’ interface and uses the highest precedence to initialize before every other component in Spring.

   @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 30;
    }

snippet 4

and these information will be placed into the ‘org.springframework.core.env.ConfigurableEnvironment’ of the Spring when ‘org.springframework.context.ApplicationListener’s ‘onApplicationEvent’ method with ‘org.springframework.context.event.ContextRefreshedEvent’ triggered.

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
            propertySources.addLast(getPropertySource());
        }
    }

snippet 5

This way our configuration value are added to the PropetySource chain of the Spring Configuration Environment.

Please pay attention that this way, the configuration values will be available after Spring initialization (so your application can use those to fulfill business cases) if you need the configuration values to configure the Spring itself, you need another approach, as you can remember we used ‘Ordered’ interfaces to guarantee that our PropertySource configurer components are one of the first Spring Components that will be initialized, now if these classes will also implement ‘InitializingBean’ interface, they can register the PropertySources during the initialization of the Spring, as following.

    @Override
    public void afterPropertiesSet() throws Exception {
        MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
        propertySources.addLast(getPropertySource());
    }

snippet 5a

the decision is up to you, depending when you need the configuration values.

Now we can access to the these configuration values either via ‘org.salgar.configuration.api.ConfigurationFacade’

String parameter = configurationFacade.getProperty("stage1", "environment1", "instance01", "serviceUrl");

snippet 6

of course this is the classical way of using properties in any application, we are getting over the configuration facade. I used here that our configuration system has the concepts of ‘stage’, ‘environment’, ‘instance’ and ‘property’ but you can just ask one property also, following will also work.

String parameter = configurationFacade.getProperty("stage1.environment1.instance01.serviceUrl");

snippet 7

Now we have to naturally inject the ‘configurationFacade’ to our class

@Autowired
@Named("proxyConfigurationFacade")
ConfigurationFacade configurationFacade;

snippet 8

interesting part here is ‘proxyConfigurationFacade’, why I am injecting this, as said before we can have several application in the JVM that needs the configuration service, so we registered our configuration service to JMX and accessing over it via Spring with the following snippet…

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="proxyConfigurationFacade" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
        <property name="objectName" value="configuration:name=configuration-service,type=org.salgar.ConfigurationService,artifactId=configuration-service"/>
        <property name="proxyInterface" value="org.salgar.configuration.api.ConfigurationFacade"/>
    </bean>
</beans>

snippet 9

and the ‘org.salgar.configuration.api.ConfigurationFacade’ is registered to the JMX with the following class ‘org.salgar.configuration.jmx.ConfigurationFacadeJmx’…

package org.salgar.configuration.jmx;

import org.salgar.configuration.api.ConfigurationFacade;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource(objectName = "configuration:name=configuration-service,type=org.salgar.ConfigurationService,artifactId=configuration-service")
public class ConfigurationFacadeJmx implements ConfigurationFacade {
    private ConfigurationFacade configurationFacade;

    public ConfigurationFacadeJmx(ConfigurationFacade configurationFacade) {
        this.configurationFacade = configurationFacade;
    }

    @Override
    @ManagedOperation(description = "delivers the configuration parameters")
    @ManagedOperationParameters({
            @ManagedOperationParameter(name = "name", description = "Name of the configuration parameter")
    })
    public String getProperty(String name) {
        return this.configurationFacade.getProperty(name);
    }

    @Override
    @ManagedOperation(description = "delivers the configuration parameters")
    public void refresh() {
        this.configurationFacade.refresh();
    }

    @Override
    @ManagedOperation(description = "delivers the configuration parameters")
    @ManagedOperationParameters({
            @ManagedOperationParameter(name = "channel", description = "stage for configuration values, like, stage01, stage02, etc"),
            @ManagedOperationParameter(name = "stage", description = "environment of the configuration values, like, environment01, environment02, etc"),
            @ManagedOperationParameter(name = "instance", description = "instance for the configuration values"),
            @ManagedOperationParameter(name = "name", description = "Name of the configuration parameter")
    })
    public String getProperty(String channel, String stage, String instance, String name) {
        return this.configurationFacade.getProperty(channel, stage, instance, name);
    }
}

snippet 10

and initialize via ‘org.salgar.configuration.jmx.JmxInitializer’ in ‘configuration-core’ project…

@Configuration
public class JmxInitializer {
    @Bean(name = "coreRegisterer")
    public MBeanExporter getMBeanExporter() {
        MBeanExporter mBeanExporter = new MBeanExporter();
        Map<String, Object> beans = new HashMap<>();
        beans.put("configuration:name=configuration-service,type=org.salgar.ConfigurationService,artifactId=configuration-service", new ConfigurationFacadeJmx(ConfigurationContainer.getInstance()));
        mBeanExporter.setBeans(beans);
        MetadataMBeanInfoAssembler metadataMBeanInfoAssembler = new MetadataMBeanInfoAssembler();
        metadataMBeanInfoAssembler.setAttributeSource(new AnnotationJmxAttributeSource());
        mBeanExporter.setAssembler(metadataMBeanInfoAssembler);
        mBeanExporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING);
        return mBeanExporter;
    }
}

snippet 11

until now this is the classical of way of using configuration parameter, lets go now for little bit for more modern approach and use Spring annotation for configuration value, namely with the annotation ‘org.springframework.beans.factory.annotation.Value’…

@Value("${stage1.environment01.serviceUrl.instance01}")
private String serviceUrl;

snippet 12

with this annotation while we configured our property source in the Spring’s ‘ConfigurableEnvironment’ now Spring can access our configuration values directly.

At this point, we have to discuss my biggest motivation to develop this solution. ‘@RefreshScope’, in my several previous projects, I developed configuration systems that are able to refresh their configuration values during the runtime, but they were simplistic systems, instead assigning concrete values to configuration properties, we just placed the configuration values to a map and they were read from there, so every time they were refreshed, the system saw the actual values. When I first discover the ‘@RefreshScope’ I found it much more elegant then our own solutions, so naturally I really like to adapt it to our project but I experienced the disappointment that is only available in the context of Spring Boot.

It was little bit a challenge but I managed to port the Spring Boot implementation to normal Spring.

To be able to use ‘@RefreshScope’, we have to annotated a class with it, for ex…

@Configuration
@RefreshScope
public class DriverFacadeImpl implements DriverFacade {
    @Value("${stage1.environment01.serviceUrl.instance01}")
    private String oneOtherProperty;

    ....
}

snippet 13

This way, Spring will place every instance of this class in a scope and if any client requires serve this class from this scope, until a refresh signal arrives. When the signal arrives, Spring will invalidate the scope container and if any client require the class again, it will recreate it and serve them (in the process it will re-read the configuration properties). Simple but it is elegant.

There is some interested details about how the ‘@RefreshScope’ is defined (you can see the whole code here, it is little bit too much to copy\paste here).

Basic details of the ResreshScope are as following, when Spring discovers a bean with ‘@RefreshScope’ annotated, it will call this Scope’s get method…

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        BeanWrapper value =  this.cache.get(name);
        if(value == null) {
            value = new BeanWrapper(name, objectFactory);
            this.cache.put(name, value);
        }

        return value.getBean();
    }

snippet 14

the first check will be ‘is the Spring Bean in cache of the refresh scope’, if yes it is delivered from there, otherwise it will be wrapped with ‘BeanWrapper’ then placed in to cache and delivered back.

So when the configuration must be refreshed from the outside and the signal is received, ‘destroy’ method called and cache is cleared, this way when Bean is demanded again, it will be re-created via ObjectFactory(this way all the configuration parameter will be re-read) and delivered back to Spring.

public void destroy() {
        this.cache.clear();
    }

snippet 15

Also one interesting point here, with the following snippet ‘RefreshScope’ will register itself to Spring.

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope(this.name, this);
        setSerializationId(beanFactory);
    }

snippet 16

To be able to deliver the refresh signal, the bean that realize the implementation of the ‘@RefreshScope’ will be registered to the JMX Bean, so when the Refresh Endpoint receives the signal, it will be transferred via JMX.

And some interesting points from the ‘@RefreshScope’ annotation,

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

snippet 17

%90 of it standard Java Annotation stuff but what interesting there is ‘@Scope(“refresh”)’ which tell Spring that this is a Scope annotation and Spring should search for a scope called ‘refresh’ in this which is already defined in

public class RefreshScope implements Scope, BeanFactoryPostProcessor {
    ....
    private String name = "refresh";
    
    ....

    @Override
    public String getConversationId() {
        return this.name;
    }

    ....
}

snippet 18

Finally, lets look to the Refresh Endpoint implementation, it is a straight forward REST interface,

@RestController
public class RefreshController {
    @Autowired(required = false)
    @Named("proxyRefreshScopeFacade")
    private RefreshScopeFacade refreshScopeFacade;

    @Autowired(required = false)
    @Named("proxyConfigurationFacade")
    private ConfigurationFacade configurationFacade;


    @RequestMapping("/refresh")
    public void refresh() {
        if(refreshScopeFacade != null) {
            refreshScopeFacade.refresh();
        }
        if(configurationFacade != null) {
            configurationFacade.refresh();
        }
    }
}

snippet 19

which here use GET Method for demonstration purposes but actually should use POST for more security, when the ‘localhost:7777/refresher/refresh’ called it just triggers JMX methods to refresh the Scope and Configuration Facade so they will get the actual values,

Tests
Now that we discuss the theory and show the implementation details, lets show case that it is exactly doing what we are expecting or not.

To be able to execute our tests, we first need a Spring Cloud Config instance, luckily that is really easy, first we need a Maven project with an one single class.

@EnableConfigServer
@SpringBootApplication
public class ConfigServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServiceApplication.class, args);
    }
}

snippet 20

the class has nothing other then one single main method and couple annotations to configure the Spring Cloud Config , ‘@SpringBootApplication’ and ‘@EnableConfigServer’.

And two configuration files, ‘bootstrap.yml’,

spring:
  cloud:
    config:
      server:
        native:
          searchLocations: file:///C:/config
  profiles:
    active: native

server:
  port: 8888

snippet 21

which defines where is the configuration files lies, native active profile (normally Spring Cloud Config read its configuration information from Git for this example we don’t want to deal with that) and port number where Spring Cloud Config listens the http traffic.

First, lets start the Spring Boot Configuration with the following command..

Configuration Server Start
picture 1

after the maven build, with the help of the ‘spring-boot-maven-plugin’, the jar that is created will contain all the dependencies so we can start the configuration server with such a simple command.

After successful start, shell for SBCS will look like the following…

Configuration Server Successful Start
picture 2

@Configuration
@RefreshScope
public class DriverFacadeImpl implements DriverFacade {
    @Autowired
    @Named("proxyConfigurationFacade")
    ConfigurationFacade configurationFacade;

    @Value("${stage01.environment01.serviceUrl.instance02}")
    private String oneOtherProperty;

    public String driver() {
        String parameter = configurationFacade.getProperty("stage01", "environment01", "instance01", "serviceUrl");

        return parameter;
    }

    public String driver1() {
        return this.oneOtherProperty;
    }
}

snippet 21a

Now that SBCS is running, let look how we are going test this, in the snippet 21a you saw a piece of code accessing properties in a two different way, one was reading it from ‘ConfigurationFacade’ and the other one via Spring’s ‘@Value’ annotation, to create a realistic test, I will deploy Maven Artifact that is containing the test code to the Tomcat Servlet Container. Personally I don’t want to install the Tomcat myself, I want it that Maven does it for me, so I created another project called ‘configuration-tomcat’ with the following ‘pom.xml’ configuration.

......
           <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/${project.build.finalName}</path>
                    <port>7777</port>
                    <ajpPort>7019</ajpPort>
                    <useSeperateTomcatClassLoader>false</useSeperateTomcatClassLoader>
                    <systemProperties>
                        <configuration.server.url>http://localhost:8888</configuration.server.url>
                        <org.salgar.configurationserver.propertyfile>C:\config\test.yml</org.salgar.configurationserver.propertyfile>
                    </systemProperties>
                    <webapps>
                        <webapp>
                            <groupId>org.salgar.configuration</groupId>
                            <artifactId>configuration-refresher</artifactId>
                            <version>1.0-SNAPSHOT</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                            <contextPath>refresher</contextPath>
                        </webapp>
                        <webapp>
                            <groupId>org.salgar.configuration</groupId>
                            <artifactId>configuration-driver</artifactId>
                            <version>1.0-SNAPSHOT</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                            <contextPath>driver</contextPath>
                        </webapp>
                    </webapps>
                </configuration>
            </plugin>
........

snippet 22

which lets the maven uses ‘tomcat7-maven-plugin’ and configure to use to maven artifact ‘configuration-refresher’ under web context ‘refresher’ and ‘configuration-driver’ under ‘driver’.

Now when we execute the ‘mvn tomcat7:run’ this will start the Tomcat container and deploy the artifacts.

So when I want to test ‘driver’ end point which will read the configuration value from ‘ConfigurationFacade’…

Driver ConfigurationFacade
picture 3

As you might see, it reads the value…

String parameter = configurationFacade.getProperty("stage01", "environment01", "instance01", "serviceUrl");

snippet 23

and delivers it as ‘https://140.18.159.16/api/v0/orderApplication&#8217;.

Now lets try the ‘driver1’ endpoint,

Driver1 over @Value
picture 4

it reads the parameter with ‘@Value’,

    @Value("${stage01.environment01.serviceUrl.instance02}")
    private String oneOtherProperty;

snippet 24

and delivers it as ‘https://140.18.159.17/api/v0/orderApplication&#8217;.

Now lets see, what happens when we refresh the values, first lets edit the configuration file and change the following values,

stage01:
 environment01:
  serviceUrl:
   'instance01': https://140.18.159.160/api/v0/orderApplication
   'instance02': https://140.18.159.170/api/v0/orderApplication
   'instance03': https://140.18.159.18/api/v0/orderApplication
   'instance04': https://140.18.159.19/api/v0/orderApplication
   'instance05': https://140.18.159.20/api/v0/orderApplication

snippet 25

to refresh the Spring Cloud Config, we have to make POST request to ‘http://localhost:8080/refresh&#8217;, easiest ways to this is with the following curl command ‘curl –noproxy localhost -d{] http://localhost:8080/refresh&#8217;.

SBCS is refreshed and re-read the configuration values, now we must refresh the client application so it can refresh itself also (I previously mentioned, actually this should be also POST request for simplicity reasons I am using it as GET).

Client Refresh
picture 5

Now if we repeat the calls,

Refreshed driver
picture 6

Now we are getting ‘https://140.18.159.160&#8217; as response instead of ‘https://140.18.159.16&#8217; for ‘driver’ response,


picture 7

and ‘https://140.18.159.170&#8217; instead of ‘ https://140.18.159.17&#8217; as ‘driver1’ response, this proves that our concept is working.

Conclusion
I think in this blog, I managed to show why it is a good idea to use a Configuration Server, instead of developing your own for the 10th time, and the concepts behind the ‘@RefreshScope’ and how to use it in core Spring.

I hope this will be useful for somebody.

If you decide the use the Spring Cloud Config and the ideas in this blog, I strongly recommend to watch this video Extending Spring Cloud Config it is a really nice video what to extend in Spring Cloud Config to get a better millage for it. Somethings in this blog must be modified to be able to use all ideas there, if you need help for it let me know, I will see what I can do about it.

Appendix
How to get the source code

You can get the source of the blog from github with the following command

git clone https://github.com/mehmetsalgar/configuration-service.git

and build it with ‘mvn clean install’

Advertisements

About Mehmet Salgar

Mehmet Salgar
This entry was posted in Micro Services, Software Development, Spring, Spring Boot, Spring Boot Configuration Server, Spring Cloud Config. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s