Set application.properties value from JNDI Environment value - spring

I am building a spring boot application, that has RabbitMQ configuration like below.
spring.rabbitmq.host=host
spring.rabbitmq.port=5672
spring.rabbitmq.username=userName
spring.rabbitmq.password=password
I need to set environment specific configuration. But that configuration needs to be read from tomcat context.xml file.
I would need to pass the values for host, username, and password by reading from tomcat Environment tag set in context.xml.
How can I do this?
Spring docs says: 24.3 Application Property Files
If your application runs in a container, then JNDI properties (in java:comp/env) or servlet context initialization parameters can be used instead of, or as well as, environment variables or system properties.
can they be directly used like this:
spring.rabbitmq.host="${rabbitMQHost}"
spring.rabbitmq.port=5672
spring.rabbitmq.username=${rabbitMQUserName}
spring.rabbitmq.password=${rabbitMQPassword}

Related

How to set logging.file.name through command line arguments in spring boot?

I am setting the logging.file.name in application.properties file which I want to pass as command line argument. Is it possible?
The reason is I am trying to run multiple jar files from a single application and I want to display logs of each application run at a single location.
Spring Boot provides several options to externalize configuration.
Spring Boot uses a very particular PropertySource order that is
designed to allow sensible overriding of values. Properties are
considered in the following order (with values from lower items
overriding earlier ones):
Default properties (specified by setting SpringApplication.setDefaultProperties).
#PropertySource annotations on your #Configuration classes. Please note that such property sources are not added to the
Environment until the application context is being refreshed. This is
too late to configure certain properties such as logging.* and
spring.main.* which are read before refresh begins.
Config data (such as application.properties files).
A RandomValuePropertySource that has properties only in random.*.
OS environment variables.
Java System properties (System.getProperties()).
JNDI attributes from java:comp/env.
ServletContext init parameters.
ServletConfig init parameters.
Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
Command line arguments.
properties attribute on your tests. Available on #SpringBootTest and the test annotations for testing a particular
slice of your application.
#TestPropertySource annotations on your tests.
Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
So you should be possible to override the values defined in your application.properties by setting environment variables, Java system properties, or command line arguments:
Environmant variables: export LOGGING_FILE_NAME=yourfile.txt
Java system property: -Dlogging.file.name=yourfile.txt
Command line argument: --logging.file.name=yourfile.txt

Springboot: Spring JPA - How to get datasource properties from server container

I use WAS Liberty Server container which provides server.xml and server.env file for configuring many things in addition to configuring DataSource properties such as url, username, password etc.
For security reasons, these properties are not known to developers for production Liberty servers. However, developers use same server.xml/server.evn files but with different DataSource properties so they can do their work.
So, I might have two server.env files like:
PRODUCTION server.env: dataSourceUrl="server-A-URL" (this URL is not known to developers)
DEVELOPMENT server.env: dataSourceUrl="server-B-URL" (this URL is known to developers)
, then the dataSourceUrl is used in server.xml files in production and development to set the url accordingly.
So, the structure of server.xml/server.env file is same for developers and production, only the DataSource url, username, password are different. This way developers can work using their own DataSource properties and once ready to deploy they app, it is handed to other team which then just changes the DataSource properties to the production values and deploys the application to production server.
With Springboot JPA, I know we can use application.properties file to set these DataSource values. But, we would like to be able to set these to the values located in server.env file. Basically to have something like this in application.properties file:
spring.datasource.url=dataSourceUrl //dataSourceUrl is set in server.env
, then be able to use this value in Java code using #Value injection like:
public class MyClass {
#Value("${spring.datasource.url}")
String dsUrl;
...
}
I have been reading about externalizing properties but I am not able to figure out how to do this
You can use Liberty's jndiEntry elements to make configured values available in JNDI. You will need the jndi-1.0 feature, after which you can configure,
<jndiEntry jndiName="spring/datasource/url" value="${dataSourceUrl}"/>
and access it in your application as:
String dsUrl = InitialContext.doLookup("spring/datasource/url");
Or, from a web or ejb component as:
#Resource(lookup = "spring/datasource/url")
String dsUrl;

How to set arbitrary system.property from Spring Boot?

If I run my app as java jar -Dsomething=anything thejar.jar then I have set a system property.
Can I do that via Spring Boot Configuration files or is my only option to defined a #Configuration class that reads a property and then sets the system property from that?
Spring configuration is highly flexible and provides a hierarchy for resolving configuration properties. You can set properties using the spring config server, environment variables (my preferred approach), system properties, application.yaml/propteries, etc. Check out the docs on externalized configuration
Say you wanted to set a property: app.some.property=foo. You can access this property from any bean using the value annotation:
#Value("${app.some.property}")
private String someProperty;
And then you can set it at runtime using one of the approaches defined above:
1. System Property
java -jar -Dapp.some.property=foo thejar.jar
2. Environment Variable
export APP_SOME_PROPERTY="foo"
java -jar thejar.jar

spring boot YAML default and environment variable override like HOCON files

Is there a way in spring-boot YAML file to do the same as in HOCON files where you can have a default and be able to override it with an environment variable like this:
basedir = "/whatever/whatever"
basedir = ${?FORCED_BASEDIR}
In this case in HOCON if you don't define a environment variable named FORCED_BASEDIR then basedir will be "/whatever/whatever" but if you do then the value of basedir will be whatever is defined in the environment variable.
Thanks
So based on webdizz answer below I looked up a little bit and I found a pretty good description in book "Spring Boot in Action". Here is the hierarchy:
There are, in fact, several ways to set properties for a Spring Boot application. Spring
Boot will draw properties from several property sources, including the following:
Command-line arguments
JNDI attributes from java:comp/env
JVM system properties
Operating system environment variables
Randomly generated values for properties prefixed with random.* (referenced
when setting other properties, such as `${random.long})
An application.properties or application.yml file outside of the application
Licensed to Thomas Snead 58 CHAPTER 3 Customizing configuration
An application.properties or application.yml file packaged inside of the
application
Property sources specified by #PropertySource
Default properties
Spring Boot provides means to define variables at many levels and your case is supported, you just need to define variable in following way:
in application.yml:
basedir: "/whatever/whatever"
and in environment:
export BASEDIR = "/another/whatever"
Then in runtime application will use value from environment.
For more details check this out enter link description here.

Spring #Scheduled job - Get base application path

I have a Spring MVC application and in it I am running a periodic job using a class with method annotated as #Scheduled
In this method, I want to get the base application path i.e. http://localhost:8080/ or http://www.mywebsite.com/ based on whether this is my local system or production system.
How can I do this? I do not have access to HttpServletRequest because this is not a Controller class.
Any hints would be appreciated
In my opinion it is a good idea to use profiles and store properties like base application path in properties file - where each environment has its own property file: config_dev.properties, config_production.properties
Once they are there you can load them in job-like classes using Environment (described on SpringSource blog).
How to configure Tomcat and Spring to use profiles: Spring 3.1 profiles and Tomcat configuration
Put a myconfiguration.properties out of your application, to let the application know that whether its running locally or in production. And then in your method annotated as #Scheduled just read the Property file.
String configPath = System.getProperty("config.file.path");
File file = new File(configPath);
FileInputStream fileInput = new FileInputStream(file);
Properties properties = new Properties();
properties.load(fileInput);
And provide the agrument,
-Dconfig.file.path=/path/to/myconfiguration.properties
when running your application server (or container). This can be done by putting,
JAVA_OPTS="$JAVA_OPTS -Dconfig.file.path=/path/to/myconfiguration.properties"
at the beginning (roughly) of the script, which is used while running your application server.
For tomcat its catalina.sh
For Jboss AS its run.sh
For weblogic its setDomainEnv.sh
And After doing that start your server and deploy your application. Finally, your #Scheduled method should know the information it needs. As the property file is outside of the application, you can change the value of the property when you want without rebuilding the application or without even disturbing it!
just add this code in your web.xml
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>my.root.path</param-value>
</context-param>
and use it your code as a system properties

Resources