I just setup a Spring Cloud Config server and have an application.yml file that should contain:
hostname: ${MY_ENV_VARIABLE}
When I pull that config file, the placeholder gets expanded before being sent instead of being sent to the application so that the application can expand it.
How do I either make Spring Cloud Config server stop expanding environment placeholders in the configuration files being served or escape the placeholders?
This question is due to ignorance on my part. When you request the configuration as Spring Boot does, e.g., https://config-server:8888/myapp/myprofile/master, then you get the JSON that describes the configuration and NO PROPERTY EXPANSION OCCURS. But, when you test the configuration by requesting it as a YAML file, e.g., https://config-server:888/myapp-myprofile.yaml, then property expansion occurs before the YAML file is displayed.
So, for my purposes, this works fine. I just need to be aware of it when checking that configurations are valid.
Related
I have to change my custom defined spring properties (defined via #ConfigurationProperties beans) during runtime of my Spring Boot application.
Is there any elegant way of doing this using Spring Cloud Config?
I don't want to use an external application.properties in a git repository (as the spring boot application gets shipped to customers and I dont' want to create a git repository for everyone of them).
I just want to access and change the local application.properties (the one in the classpath, located in src/main/resources) file in my Spring container or (if thats not possible) in the Spring Cloud Config Server, which I could embed into my Spring Boot app. Is that possible somehow?
BTW: The goal is to create a visual editor for the customers, so that they can change the application.properties during runtime in their spring boot app.
Spring Boot supports profile based application configuration. Just add application-<profile>.properties file. Then just when running the application select a profile depending on the environment making use of spring.profiles.active.
-Dspring.profiles.active=dev
This will run the application with application-dev.properties file (overriding the default application.properties, i.e you can just leave the common stuff in the default file and change the rest depending on the env)
On a side note, having a repo for configuration is not a must. You could just place them in the class path and give a search-location.
spring:
application:
name: config-server
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:configs/
It actually is possible and in the end quite easy to achieve. It just took me a whole day to get all the information together. Maybe this helps someone:
You basically just need Spring Actuator, but for a certain endpoint, you also need the spring cloud dependency. (to make Post requests to the /env endpoint of Spring Actuator)
To alter your config at runtime, just add the following to your application.properties:
management.endpoints.web.exposure.include: env,refresh
management.endpoint.env.post.enabled: true //this property is only available when spring cloud is added as dependency to your project
If you (like me) don't need the feature of an externalized config, then you also have to add the following (otherwise, your Spring app will not start and throw an error that some config is missing)
spring.cloud.config.enabled: false
Now, if you send a POST request to /actuator/env endpoint with an object in the HTTP body in the form of {"name":"...", "value":"..."} (name is the name of a config property), then your config gets changed. To check that, you can do a GET request to /actuator/env/[name_of_config_property] and see that your config property has changed. No need to restart your app.
Don't forget to secure the /actuator endpoint in your SecurityConfig if you use a custom one.
It seems to me that you neither need the #RefreshScope annotation at your config classes nor the /actuator/refresh endpoint to "apply" the config changes.
Maybe what your looking for could be achieved with Spring cloud config and spring cloud bus. It's explained here: https://cloud.spring.io/spring-cloud-config/reference/html/#_push_notifications_and_spring_cloud_bus
In summary, any change on configuration sent an event to the spring cloud bus and you can then reload app context or configuration with new properties.
I am looking for a way to purely externalize some configuration settings in Spring boot application. For example: when double clicked on the fat-JAR file then it loads configuration from that, say myConfig.config, file which is in the same folder in which the fat-JAR file is. Then read the configuration from there and deploy the web-app. One use case is reading the port number from the config file and start the web-app on port number specified in the config file. If port number needs to be changed then only config file needs to be updated and restart the web-app.
I know that it is possible in .NET. I tried this link[1], but it is specifying config file in command line. Also, the #PropertySource can be used but again it winds up being in fat-JAR. There is Spring Cloud Config as well but I think that it would be overkill for small application. There are lots of tutorials available but they use one of the above mentioned method.
So, Is there any way to achieve that?
If yes, then what are the steps/link for that?
[1] Springboot externalizing log4j configuration
All you need to do is place an application.properties file at the same level as your jar. Spring Boot will find and use the application.properties w/o anything extra.
I am trying to build a sample app on Spring boot and spring cloud.
I have written my database and hibernate configuration in config.properties property file which is located in my desktop and I want my spring boot to make use of this configuration.
My project have 3 modules
API
DataLayer
ServiceLayer
This is the code that I have mentioned in the application.property file of API
spring.profiles.active=native
spring.cloud.config.server.native.searchLocation=C:/Users/DEV/Desktop/configuration/config.properties
and the property file of DataLayer and ServiceLayer is empty
But when I run the API I am getting the following error
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
Process finished with exit code 1
Could any one help me with this error.
Thanks in advance.
This is can not be done from your API module. You added configuration server properties to your 'client' (from configuration point of view) application.
If you want to use Spring Cloud Config to configure your project you should have separate application that will manage your configuration. Let's call it config-server. (You should properly configure maven or gradle dependencies, see documentation) To configure usage of native profile in the config-server in application.properties you have to add properties that you mentioned in the question (example for native profile).
spring.profiles.active=native
spring.cloud.config.server.native.searchLocation=file:<path-to-the-directory-with-conf-files> or classpath:/<path-to-the-directory-with-conf-files>
Note: config-server can handle configuration for lot of services.
More can be found in the documentation Spring Cloud Config Server section.
Then in your API (or any other module) which is a spring boot app you should add spring-cloud-config-client dependency and add bootstrap.properties (or .yml) configuration file. There your should add properties that will describe communication with config-server. By default config-server listens on port 8888.
spring.application.name=<your app name>
spring.cloud.config.uri=http://localhost:8888 # this is also default value for this property
At start-up it will go by http to config-server and fetch your configuration properties based on service name (spring.application.name).
More can be found in Spring Cloud Config client section
Important: make sure your properly organize files in your configuration directory (which is used by native profile by config-server), find some samples. Property files naming are important. For start you can try to use your-application-name.properties
You have to have file: prefixed to the property file location.
Documentation from https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html
There is also a “native” profile in the Config Server that does not use Git but loads the config files from the local classpath or file system (any static URL you want to point to with spring.cloud.config.server.native.searchLocations). To use the native profile, launch the Config Server with spring.profiles.active=native.
[Note]
Remember to use the file: prefix for file resources (the default without a prefix is usually the classpath). As with any Spring Boot
configuration, you can embed ${}-style environment placeholders, but
remember that absolute paths in Windows require an extra / (for
example, file:///${user.home}/config-repo).
[Warning]
The default value of the searchLocations is identical to a local Spring Boot application (that is, [classpath:/, classpath:/config,
file:./, file:./config]). This does not expose the
application.properties from the server to all clients, because any
property sources present in the server are removed before being sent
to the client.
[Tip] A filesystem backend is great for getting started quickly and for testing. To use it in production, you need to be sure that the
file system is reliable and shared across all instances of the Config
Server.
Currently i am working on a REST based project in Spring Boot.
I have added the api url in 'application.properties' file.
i.e.
application.properties
api-base-url=http://localhost:8080/RestServices/v1
And also this 'api-base-url' value access from java.
In some situations i need to change the 'api-base-url' dynamically.
I have change 'api-base-url' value dynamically & working fine.
But my problem is that
when wildfly restart then the configuration will be reset to default.
i.e
This is my default value
api-base-url=http://localhost:8080/RestServices/v1
dynamically change to
api-base-url=http://10.34.2.3:8080/RestServices/v1
when wildfly restart then the configuration will be reset to default.
i.e.
api-base-url=http://localhost:8080/RestServices/v1
Have any solution for this?
You might want to consider using a cloud config server to host your config. Two examples are Spring Cloud Config and Consul.
These servers will host your application's configuration and your spring boot application will make a call out to the config server on start up to get it's config.
spring-boot-actuator exposes the endpoint /refresh which forces the application to refresh it's configuration. In this case, it will call out to the config server to get the latest version.
This way you can change the config hosted in the config server then hit the /refresh endpoint and the changes will be picked up by your application.
As #moilejter suggests, one possible way is to persist in database table and at start time you simply read from that table instead of application.properties file. Your application.properties files can hold information necessary for database connection.
You would also need a JMX method or a REST API to trigger in your application that the url has changed and which inturn, would simply read from same table. This way you would be safe even if app restarts and you won't lose the override.
You can use BeanFactoryPostProcessor coupled with Environment bean to leverage spring placeholder concept.
#user2214646
Use spring expression language
In Spring Cloud Zuul server we can define all routes which need be redirected via "application.properties".
For example:
zuul.routes.resource.path=/api/**
zuul.routes.resource.url=http://api.com:9025
Once the fat jar is created the "application.properties" is encapsulated into jar, and it's not possible to edit and reload the rules inside the file.
Is there any to inform Zuul about the routes in an external file, and at the same time reload them without stopping the server?
You can use spring cloud config for that.
Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments
http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_spring_cloud_config_client
...a bit late to the party, but...
You can do all that you want with the ConfigServer!
Create an application.yml for config that is common across ALL applications
Create profile specific application-mycommonprofile.yml. As 1. but for the 'mycommonprofile' profile.
Create an appX.yml for each application that is specific to that application.
Create profile specific appX-myprofile.yml. As 3. but for the 'myprofile' profile.
All of these files are optional and are not dependent on any others. You can have an application-mycommonprofile.yml without an application.yml for example.
Hope that helps!
Another late-to-the-party answer, but another way is to use a profile config file, which lives in the filesystem, outside the fatjar.
If the configuration name of your Zuul proxy is 'zuul' and your normal config file is 'zuul.properties' or 'zuul.yaml', then it looks for a profile-specific config file in 'zuul-.properties' or 'zuul-.yaml'.
If you do not specify a profile, then the profile named 'default' is active.
So you can load properties from an external file name 'zuul-default.properties' or 'zuul-default.yaml' (or 'zuul-default.yml', if you use a 3-letter filename extension).
This will then be loaded when no other profile is specified.