I have a java Spring boot project which uses a MySQL database. I have the following application.properties file to specify the MySQL url, user and password:
spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
spring.datasource.username=${MYSQL_USER}
spring.datasource.password=${MYSQL_PASSWORD}
Using this property file, I can run the application from Eclipse if I edit the run configurations and set the values of DB_HOST, DB_PORT, DB_NAME, MYSQL_USER and MYSQL_PASSWORD in the Environment tab and run it.. everything works fine.
But now I want to run it on the server, by generating a JAR and passing these values from command line to the Jar during run time. So, I created a Jar file like this:
/gradlew clean build bootJar -DDB_HOST=mock -DDB_PORT=mock -DDB_NAME=mock \
-Dmysql_user=mock \
-Dmysql_password=mock
this successfully generates the executable Jar file.. then I try to run the generated jar file like this:
java -jar build/libs/MyApplication.jar -Ddb_host=localhost \
-Ddb_port=3306 \
-Ddb_name=my_db \
-Dmysql_user=root \
-Dmysql_password=root
but it gives the following error:
...
Failed to parse the host:port pair '${DB_HOST}:${DB_PORT}'
...
java.lang.NumberFormatException: For input string: "${DB_PORT}"
...
Which means that it is not actually replacing the values during runtime.
How do I fix this?
Edit: I also tried to open up the jar using archive utility and saw the application.properties file.. it contains the following line:
spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
which means that these values should have been updated during runtime. but it isn't
I was eventually able to get this to work by adding a DatasourceConfig class and setting the values programatically.
I removed all the spring.datasource.* values from my application.property file and then created a new class:
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class DatasourceConfig {
#Bean
#Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(System.getProperty("MYSQL_URL"));
dataSource.setUsername(System.getProperty("MYSQL_USER"));
dataSource.setPassword(System.getProperty("MYSQL_PASSWORD"));
return dataSource;
}
}
This allows you to configure the datasource, username and password externally as VM arguments at runtime.
The values MYSQL_URL,MYSQL_USER,MYSQL_PASSWORD are passed onto the gradle command while building like this:
./gradlew clean build bootJar -DMYSQL_URL=mock -DMYSQL_USER=mock -DMYSQL_PASSWORD=mock
, and similarly to the java command while running the jar like this:
java -jar build/libs/MyApplication.jar -DMYSQL_URL=jdbc:mysql://localhost:3306/my_db -DMYSQL_USER=root -DMYSQL_PASSWORD=root
You just need to expose those Fields as Environment Variables before running the jar.
For Linux:
$ export DB_HOST=localhost
$ export DB_PORT=3306
$ export DB_NAME=my_db
$ export MYSQL_USER=root
$ export MYSQL_PASSWORD=root
$ java -jar build/libs/MyApplication.jar
Related
I am starting spring boot project as follows
java -classpath "/home/madhur/github/fantasy_fury/target/fantasy_fury.jar:/home/madhur/github/fantasy_fury/target/dependency/*:/home/madhur/github/fantasy_fury/conf" com.games24x7.fantasy.fury.FantasyFuryInit
The conf folder has an application.properties with following contnents
zkHost=${ZK_CLUSTER_URLS}
Now, I am trying to read this variable as follows:
#Value("${zkHost:localhost}")
String zkHost;
However, it does not contain the actual value, but the default value localhost value every time.
Tried to set it as follows:
export ZK_CLUSTER_URLS=madhur1;java -classpath "/home/madhur/github/fantasy_fury/target/fantasy_fury.jar:/home/madhur/github/fantasy_fury/target/dependency/*:/home/madhur/github/fantasy_fury/conf" com.games24x7.fantasy.fury.FantasyFuryInit
Then also, the output is localhost. What I am missing?
Spring boot version is 1.4
Currently my tech stack is Java, Spring Boot.
I am using application-dev.properties to keep the AWS access key and secret key.
In application-dev.properties to inject the keys I have:
#This property provide access key details
com.abc.sqs.accesskey = AWS_ACCESS_KEY
#This property provide secret key details
com.abc.sqs.secretkey = AWS_SECRET_KEY
Now from GitLab CICD .gitlab-ci.yml file while I am trying to smoke test of the application .jar I have something like this (stage is smoke test) -
smoke test:
stage: smoke-test
image: openjdk:12-alpine
before_script:
- apk add --update curl && rm -rf /var/cache/apk/*
script:
- ls -la ./app-service/target/
- sed -i "s/AWS_ACCESS_KEY/$AWS_ACCESS_KEY_ID/" ./app-service/src/main/resources/application-dev.properties
- sed -i "s/AWS_SECRET_KEY/$AWS_SECRET_ACCESS_KEY/" ./app-service/src/main/resources/application-dev.properties
- java -jar -Dspring.profiles.active=dev ./app-service/target/app-service.jar &
- sleep 30
- curl http://localhost:5000/actuator/health | grep "UP"
- curl -i -X POST http://localhost:5000/actuator/shutdown
Here I am bringing $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY from GitLab CICD environment variables and trying to replace AWS_ACCESS_KEY and AWS_SECRET_KEY of properties file. But this way I am not able to inject during start of the server.
While trying to test the jar getting following exception:
Caused by: com.amazonaws.services.sqs.model.AmazonSQSException: The
security token included in the request is invalid. (Service:
AmazonSQS; Status Code: 403; Error Code: InvalidClientTokenId;
Please need your suggestion.
Advance thanks.
If you want to override properties in a properties file, instead of using sed, you can simply declare an environment variable or a JVM variable with a similar name. It will have the priority over properties declare in file.
For instance:
com.abc.sqs.accesskey = AWS_ACCESS_KEY
Can become with a JVM variable:
java -jar -Dspring.profiles.active=dev -Dcom.abc.sqs.accesskey=$AWS_ACCESS_KEY_ID ./app-service/target/app-service.jar
This will override the value of the properties file, and this will be available on application startup.
I have a simple Spring application with reading configuration values from a properties file. The file is configured to be on classpath by default (#PropertySource("classpath:thefile.properties") annotation on a configuration class). I want to be able to optionally use some another properties file that I can (but don't have to) specify in command line on the program startup. I.e., I eventually want to run something like this:
java -jar application.jar --path "some/location/thefile.properties"
Now values from the specified file should be used.
I have already tried using SpringBoot and the spring.config.location option both before and after the jar:
java -jar "-Dspring.config.location=file:some/location/thefile.properties" application.jar
keeps using values from the file on classpath
java -jar application.jar "--spring.config.location=file:some/location/thefile.properties"
complains about unrecognized option
My main class looks like this:
#SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(MainClass.class, args);
// Application code triggered here...
}
}
I don't need to use SpringBoot, I just want to set the properties file location somehow. Any idea? And is this possible at all?
Do something like this on your property class :
#Configuration
#PropertySource(value = "file:${myapp.external.config}")
**Command** java -jar -Dmyapp.external.config="C:\yourPath\abc.properties" xyz.jar
If you have multiple external properties files, example below
#Configuration
#PropertySource(value = {"file:${app1.config}", "file:${app2.config}"})
**Command** java -jar -Dapp1.config="C:\yourPath\abc1.properties"
-Dapp2.config="C:\yourPath\abc2.properties" xyz.jar
This worked for me on Windows : "C:\Program Files\Java\jdk-15.0.1\bin\java" -jar C:\Users\your.name\YourApp.jar --spring.config.location="C:/Users/your.name/yourAppProps.properties".
I have a simple spring boot application that returns value of a system env variable
application.properties
my-var=${SYSTEM_ENV_VAR}
where SYSTEM_ENV_VAR is a system variable defined in /etc/environment
DemoApp.java
#SpringBootApplication
#RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Value("${my-var}")
String env;
#GetMapping(path = "/")
public String get() {
return "This: " + env;
}
}
I follow the process of creating an executable jar with mvn clean package
Now, when I execute the jar as /home/ubuntu/sample-app/target/demo-0.0.1-SNAPSHOT.jar, I get the correct value of my system environment variable
I created a service
/etc/systemd/system/demoapp.service
[Unit]
Description=desc
After=syslog.target
[Service]
EnvironmentFile=-/etc/environment
User=root
ExecStart=/home/ubuntu/sample-app/target/demo-0.0.1-SNAPSHOT.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
I execute the service as sudo systemctl start demoapp.service.
When I check the status sudo systemctl status demoapp.service, I see an error trace
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder
'SYSTEM_ENV_VAR' in value "${SYSTEM_ENV_VAR}"
But I know that /etc/environment is loading since I can see other entries in the log which show the loading of all my system envs
Can anyone help me with this? Thanks.
Value that you are using for ${my-var} should not be ${SYSTEM_ENV_VAR} instead should be the actual path to the system variable.
So your application.properties should have
my-var=path/to/system/variable
and not
my-var=${SYSTEM_ENV_VAR}
Ok. So this is what I ended up doing.
I noticed that removing the export keyword in my /etc/environment resulted in the value of SYSTEM_ENV_VAR being interpreted and displayed.
But now apache started complaining since it could not find the value for SYSTEM_ENV_VAR. Therefore, I split the declaration into 2 parts. So the file looks like:
/etc/environment
export SYSTEM_ENV_VAR
SYSTEM_ENV_VAR=the-value
This way, apache and spring boot both are happy.
i'm working on spring boot project and all works fine , now i want to build and run the app.
in the application.properties file i set the property server.port = 8090
after building the project using maven i run the following command
java -jar jarfilename.jar but it says the port 8080 is already in use.
i try these commands:
java -jar -Dport=8090 jarfilename.jar
and
java -jar jarfilename.jar --port=8090
but also i got the same message the port 8080 is already in use.
I'm wondering why it takes the port number 8080 and ignore the port number 8090 that i set in the application.properties file.
Note : (I'm using tomcat embedded server) and when i check the folder target/classes.. application.properties i didn't find the property server.port=8090.
can anyone explain to me what' happen exacly?
thanks in advance.
Is the application.properties located at the right location?
Description from Spring.io:
SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).
Use java -jar -Dserver.port=8090 jarfilename.jar to set the port from command line.
Hint, from Spring.io: If you want to use the short term -Dport=8090, you can use server.port=${port:8080} in your application property file.
I encountered the same problem, in my case, I didn't pass the args to SpringApplication.
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class);
}
should be
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
when you create spring boot application using 'spring initializer' select jar file
I know its an old post, but I might know the answer(maybe it will help others): There is a hierarchy with the configuration settings.
The applicaton.properties file is at the bottom(OS env. variables, Java System properties etc. are all above), on the other hand, terminal parameters are at the top.
So when the server initialized, it used the port from a property setting, that is higher in the hierarchy ladder.