We are leveraging Spring Cloud Config and Spring Cloud Config Vault. We would like to know if there is a way to "bootstrap the bootstrap", ie we want spring cloud config server to be hit and then pull properties from that to leverage in our vault configuration. We looked at order, but it didn't appear to work, and I assume it is because of the post processing order, but I was hoping I might be missing something.
TL;DR
It doesn't work.
Explanation
What Spring Cloud does with its bootstrap context, is setting up an application context that contains a set of PropertySources initialized from Spring beans. The bootstrap context is used then as parent context for the actual context created by Spring Boot. A property lookup looks for properties in its own context and within the parent context.
Configuration properties are initialized very early in the startup process and they use properties from the current Environment. At the time ConfigurationProperties beans are initialized, the Environment does not yet contain any remote PropertySources.
The only option I see here (except creating a bootstrap-bootstrap-context) is using the Spring Cloud Config client within your main class and contribute Vault properties before any Spring context is built.
Probably you can, but it requires PropertySourceBootstrapConfiguration#initialize() method overriding. You can't disable bean PropertySourceBootstrapConfiguration, but you can disable it's initialize method by using applicationContext.getBeanFactory().getBean(PropertySourceBootstrapConfiguration.class).setPropertySourceLocators(new ArrayList<>()) in CustomPropertySourceBootstrapConfiguration (to avoid obsolete external property sources calls).
In your CustomPropertySourceBootstrapConfiguration#initialize method you can retrieve properties from config-server and then customize your vaultPropertySourceLocator by inserting generated in config-server secretId of token.
Don't forget to add your CustomPropertySourceBootstrapConfiguration to spring.factories.
So, it's not easy but it is possible.
We created the custom datasource using EnvironmentPostProcessor which will get called before autoconfigure beans
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.application.customize-the-environment-or-application-context
Related
I have a spring boot based spring application that is deployed into an external tomcat instance.
The application creates few datasources. These datasources are added to entitymanager and transaction manager is setup accordingly.
However, recently we have integrated programmatically an ETL tool that works with JNDI datasources. The ask here is to bind the current spring datasources into the JNDI tree at startup.
I have tried to create an initial context post datasource bean creation and bind the datasources there, however, i do see a NoInitialContext exception being thrown.
How can i bind these spring datasources into the JNDI tree of the external tomcat? Appreciate the help!
Note: I cannot/am not allowed to edit the tomcat configuration as it is initialized from a PaaS template. So need to work on the approach of being able to bind to the JNDI tree from within the application.
AFAIK this is not possible. Take a look at the JEE spec:
The container must ensure that the application component instances have only read access to their naming context. The container must throw the javax.naming.OperationNotSupportedException from all the methods of the javax.naming.Context interface that modify the environment naming context and its subcontexts.
Jakarta EE Spec - Resources, Naming, and Injection
See this SO post has some interesting code examples if you want to play around.
IMHO you can achieve what you want by creating JNDI resources and passing these to the EntityManger/Spring. But that means that the configuration would exist outside of Spring completely. So this may not do what you want to do.
I have a Camel Spring Boot application where I am printing the value of a property which is set using Spring Cloud Config Server (via Git commit id plugin). The issue is that the value of the property in Camel application is not updated once the value is committed to Git. I have to restart the Camel application which fails the purpose of Spring Cloud Config server. Please note that we are using Git file system in our local machine.
The name of the properties file is CamelSpringBootSample-dev.properties.
As soon as I commit, the config server publishes the updated value at the endpoint on refresh:
http://localhost:8888/CamelSpringBootSample/dev
I have also made the Camel application end point available at:
http://localhost:8181/actuator/env
Here the value of the property is not updated on refresh. However, if I restart the Camel application, the value is reflecting.
The source code for all the three projects are uploaded in github.com.
The config server: https://github.com/sreejeshraj/config-server
The Camel client project (which uses the config server to configure itself): https://github.com/sreejeshraj/camel-config-server
Please do not get misled by the repository name camel-config-server. This is the client of config server, but I accidentally named it incorrectly, apologies.
The local git repository where the configuration properties are stored: https://github.com/sreejeshraj/Git-Config
Please note that I have used the annotation #RefreshScope in my Spring bean component class.
Can you please help me with this? Thanks in advance.
You have to set:
management.endpoints.web.exposure.include=refresh
in bootstrap.properties or bootstrap.yml.
and trigger the /actuator/refresh endpoint.
See #RefreshScope and /refresh not working
Note that as said in the comments, Camel does not update its values when a Spring beans is refreshed and there is no plan to implement this feature. (https://issues.apache.org/jira/browse/CAMEL-13892). You probably could find a solution through Spring Cloud Bus.
As #ortomala-lokni already pointed out, you need to refresh your configuration consumers after an update happened.
If you want a centralized solution for this task (for refreshing many components automatically), take a look at Spring Cloud Bus.
This page gives a quite good overview about the subject.
I had a situation where I had both application.properties and bootstrap.properties file in my client. I that case you should specify spring.application.name and spring.cloud.config.server.git.uri inside bootstrap.yml. I didn't refresh properties having spring.application.name inside applicaiton.properties.
We have a application which is running on amazon EC2. we are planning to migrate it to elastic beanstalk environment. our application has two configuration files which stores some endpoints and few other control parameters. currently those are loaded as spring properties and injected to respective beans. we are thinking of putting them in to a S3 bucket and read them while loading the spring context. tries different approaches but still not luck.
1) what would be best advisable way to read the properties file with aws elastic beanstalk. we do not like to put them all as environment variables?
2) I tried creating a class extending
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
and tried by overriding processProperties method. but it seems annotation based property injection happens before calling this method. instance was created but the processPRoperties method was not called? any idea how this could be handled will be appreciated
EDIT
I have used a custom ApplicationContextInitializer registered in web.xml
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.xxx.PropertyInitializer</param-value>
</context-param>
in the initializer class injected the properties. seems it is working fine but then I'm facing another issue stated here.
Spring application context is converted to proxy after custom property injection
I'm using Spring Boot 1.3.6 and Spring Session and Redis as the Session store. I need to be able to set the redisNamespace for the application a runtime, and not hard-code it in the code. That means I cannot use #EnableRedisHttpSession since that is not something I can set via the applaction.yml file.
I've updated Spring Session to 1.2.1.RELEASE to get the support I need, but I cannot seem to get the system to configure the namespace via configuration. I tried using a SPEL in the #EnableRedisHttpSession(redisNamespace) call, but that doesn't work. I tried to have the RedisHttpSessionConfiguration injected via Autowired to set it as well, and that seemed to have been ignored. There was also another reference in another SO post about using spring.session.redis.namespace as a property in application.yml but that doesn't work.
Any suggestions/tips would be greatly appreciated!
Declaring spring.redis.namespace per the documentation is not enough.
After setting #EnableRedisHttpSession() to #EnableRedisHttpSession(redisNamespace = "${spring.redis.namespace}") it worked.
Per the normal functionality to externalise configuration you can use system environment variables as well, instead of spring.redis.namespace.
Note: In this case spring.redis.namespace corresponds to the application.yaml file that looks like:
spring:
redis:
namespace: ${REDIS_NAMESPACE:foobar}
I simply put a -Dspring.session.redis.namespace=myKeyName to VM arguments.
and it is working fine.
and I'm using spring boot v1.3.5.RELEASE and spring session 1.2.0.RELEASE.
I'm using Spring 2.5.6. I have a bean whose properties are being assign from a property file via a PropertyPlaceholderConfigurer. I'm wondering whether its possible to have the property of the bean updated when the property file is modified. There would be for example some periodic process which checks the last modified date of the property file, and if it has changed, reload the bean.
I'm wondering if there is already something that satisfies my requirements. If not, what would be the best approach to solving this problem?
Thanks for your help.
Might also look into useing Spring's PropertyOverrideConfigurer. Could re-read the properties and re-apply it in some polling/schedular bean.
It does depend on how the actual configured beans use these properties. They might, for example, indirectly cache them somewhere themself.
If you want dynamic properties at runtime, perhaps another way to do it is JMX.
One way to do this is to embed a groovy console in your application. Here's some instructions. They were very simple to do, btw - took me very little time even though I'm not that familiar with groovy.
Once you do that you can simply go into the console and change values inside the live application on the fly.
You might try to use a custom scope for the bean that recreates beans on changes of the properties file. See my more extensive answer here.
Spring Cloud Config has facilities to change configuration properties at runtime via the Spring Cloud Bus and using a Cloud Config Server. The configuration or .properties or .yml files are "externalized" from the Spring app and instead retrieved from a Spring Cloud Config Server that the app connects to on startup. That Cloud Config Server retrieves the appropriate configuration .properties or .yml files from a GIT repo (there are other storage solutions, but GIT is the most common). You can then change configuration at runtime by changing the contents of the GIT repo's configuration files--The Cloud Config Server broadcasts the changes to any Client Spring applications via the Spring Cloud Bus, and those applications' configuration is updated without needing a restart of the app. You can find a working simple example here: https://github.com/ldojo/spring-cloud-config-examples