I have the following SpringBoot project structure ..
dependencyProject is packaged as a .jar and contains property configuration files:
.
└── dependencyProject
└── src
└── main
└── resources
├── application-dev.yml
└── application.yml
application-dev.yml contains
app-configuration.org.app.shell: true
Then mainProject consumes dependencyProject i.e dependencyProject is on the classpath.
.
├── config
│ └── application.yml
└── src
└── main
└── java
└── Main.java
application.yml contains
app-configuration.org.app.shell: false
By default my app runs in dev profile.
When I run the app, the value for app-configuration.org.app.shell is true.
Why is it not using the value obtained from application.yml, inside the main/root project?
Is there a way I can override the property value from inside my main project, without having to edit the version inside the jar project?
Why is it not using the value obtained from application.yml, inside the main/root project?
Spring loads configuration properties in the following order:
1. Application properties packaged inside your jar (application.properties and YAML variants).
2. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
3. Application properties outside of your packaged jar (application.properties and YAML variants).
4. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
Source: Spring-boot. Externalized Configuration
Your properties in dev profile are loaded later and override the value.
Is there a way I can override the property value from inside my main project, without having to edit the version inside the jar project?
You probably can do some workaround but be aware that this could result in reverse confusion for others (e.g. why my profile-specific properties do not override those defined in application properties as Spring claims to be)
Well if I understood your question correctly, you can override the value using an environment variable. Like this,
-Dapp-configuration.org.app.shell=false
Related
I have a multi-module Spring Boot Gradle project (Kotlin) with the following directory structure.
root
|- domain (Module containing entities and interfaces)
|- application (Spring boot Kotlin application)
|- src/main
|- kotlin (app sources)
|- resources
|- application.properties (default config)
|- src/test/kotlin/long/package/name/ApplicationTests.kt
|- build.gradle.kts (and also gradle folder)
|- config
|- application.properties (config to override classpath properties)
|- build.gradle.kts (and settings.gradle.kts and other gradle folder)
When I run the Application.kt file, it is able to pick up this file (both with IDE and gradle), and it runs successfully.
Since my config folder is outside my application folder, running my ApplicationTests.kt results in the error below. The output is same when running through IDE (IntelliJ) run button and ./gradlew clean test.
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection
I am expecting the tests to find the application.properties file inside the config folder. How can I register my config/application.properties so that I can keep it separate from my classpath:application.properties?
UPDATE:
I tried adding the following copy task to gradle.
tasks.create("copy", Copy::class.java) {
from("../config")
into("$buildDir/resources/main")
}
tasks.named("test").configure {
dependsOn("copy")
}
This enables me to overwrite the application.properties from config folder (meaning any property not added in config/app.prop is no longer present). Test runs successfully now (if I add all entries from classpath properties to config/app.props). How can I merge the contents of these two properties files inside application/build.gradle.kts?
If you want to override your application.properties with an external application.properties, you can copy the external file to build/classes directory using Gradle and append a profile name, like application-ext.properties. Then, activate default and ext profiles using spring.profiles.active.
Another option would be to use Spring Config server, but that may be overkill for this simple task.
By default, Spring will look in your current working directory for the directory named, config. As you've noted, you're not executing the application in the directory containing the config directory. You can override where Spring looks for this config folder with the -Dspring.config.location option or via the environment variable, SPRING_CONFIG_LOCATION
If your config directory is located at /opt/myconfigs/config, you would start your service with -Dspring.config.location=/opt/myconfigs/config. Another option is to export SPRING_CONFIG_LOCATION=/opt/myconfigs/config and start your app without any additional JVM options.
If you're running tests in the application directory, then the config folder would be one level up from the current working directory. Annotating your tests with
#TestPropertySource(properties = "spring.config.location=../config/,classpath:/application.properties") would load the application.properties from both the config folder and the src/main/resources folder, properties in the config props would override properties in the local application properties.
The same thing can be achieved with the VM argument of -Dspring.config.location=classpath:/application.yml,file:../config/, here order is important.
[root#xx ~]# tree /data/portal/
/data/portal/
├── portal.jar
└── config
└── application.properties // I wish it read this
java -jar portal.jar does not read properties in config folder, it stubbornly reads the same file in jar package. However, based on 24.3 Application Property Files jar should read the configuration in config folder. Maven project too. Now I have to manually configure the file location by --spring.config.location.
EDIT:
I have just found that, by using --spring.config.location=file:/absolutepath/config/application.yml does not actually load any included property files. like this:
spring.profiles.include: 'routes'
does not load application-routes.yml, even though log says The following profiles are active: routes
my application is using Spring Boot, with 2 main modules main and test. In another directory on same level I have folder which contains script with database triggers which I need create in database before tests.
Here is my project structure:
src/
├── main
├── scripts (this is not module, only default folder)
│ └── custom_script.sql
└── test
└── persistent
└── TestConfiguration.java
Test configuration is only interface where I set some configuration for tests, currently contains following code:
#Sql("../../scripts/custom_script.sql")
public interface TestConfiguration {
}
This code didn't work, and custom_script.sql isn't executed. Can you tell me why, or what is the better to execute it?
I have a maven project that is generating a .war file.
I want to configure maven to generate an executable jar, that embeds a servlet container (jetty, tomcat, or others) plus my war application, and generate an executable jar that can run my web application with a command like:
java -jar mywebapp.war
Is there a maven plugin to obtain such artifact?
At the moment I'm using jetty-runner to run a test version of my app, it's quite satisfying for test, but not as as handy for redistribution as it would be an executable war (like in jenkins).
Update
#jesse-mcconnell: I don't want to change a single line in my web application (except in the pom.xml) to achieve the result. It's just a matter to package my war differently, and keep it deployable under an appserver of choice, plus having the ability to run it as an executable war.
A perfect solution should also give me the ability to choose which appserver to embed, also specifying all needed configuration files contained in the executable war itself.
#khmarbaise: I know about jenkins, I already checked the code long time back, it uses winstone servlet container, and it puts a Main.class in the war which is accessible from http (and I think it's wrong)
A perfect solution could generate a war containing stuff like this:
├── META-INF
│ └── MANIFEST.MF (Main-Class: WEB-INF.container.classes.Main)
└── WEB-INF
├── web.xml
├── classes
├── lib
└── container
├── lib (jetty.jar/tomcat.jar/whatever.jar)
├── etc (configuration files for the container)
└── classes
└── Main.class
Main.class should use etc configuration as default, but being able to override common parameters at the command line (port, context,etc) or specifying a new configuration.
Main.class should be able to load the container jar and configuration from inside the container (or extract into tmp.dir) and start up the appserver.
This is how I would make it.
At the end, you have a normal war, that can be deployed in any appserver, with the ability to run in a self-contained way.
Tomcat Maven plugin do that have a look here http://tomcat.apache.org/maven-plugin-2.0/executable-war-jar.html
HTH
Use the maven jar plugin to set the Main-Class in the manifest, and then write a main method with something akin to this (or that calls into code like this):
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java?h=jetty-8
You can register your servlets and wire up the webapp accordingly.
The issue with bundling a war file proper inside of a jar file is that you would need a specialized deployer that understands deploying a war file from within a jar, not a common thing. So creating an uber type jar is probably the better way to go. Besides, one of the big reasons of the actual WebAppContext is the classloader isolation which is kinda moot in these cases.
You can use the maven-dependency-plugin to unpack the various dependencies you need. There are other plugins you can use like the maven-uberjar-plugin (I think that was the name) but you can do it simply with the maven-dependency-plugin + a custom main class akin to something like the above.
I like this approach as you end up with a main method that you can run in eclipse that starts up the whole application and lets you debug the whole thing as well, often quite a win.
Edit: for posterity, jetty also releases with an artifact called jetty-runner that allows for running war files directly off of the command line
No that i know but check the jenkins source code which supports starting directly from command like you expected to work.
I want to create /java, /resources, and /webapp/WEB-INF/web.xml folder structure under src.
I have used the -DarchetypeArtifactId=maven-archetype-webapp but it creates /resources /webapp/WEB-INF/web.xml but doesn't create /java folder.
So in spite of creating the folder /java in eclipse manually is there any other way to create with some -DarchetypeArtifactId= so that it creates the above folder structure.
I'll be thankful if someone can tell me how can I customize and design my folder structure and create it with maven without using existing template.
When you use -DarchetypeArtifactId=maven-archetype-webapp, java folder wont be created. It needs to be created manually.
It created the following structure
src
└── main
└── resources
└── webapp
└── WEB-INF
Best choice is to follow Maven standard directory layout:
http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
Archetypes are minimized due different programming languages can be used for web development:
http://cvs.peopleware.be/training/maven/maven2/standardDirLayout.html (link goes to web.archive since the main link is dead)
It will minimize configuration of plugins and also will simplify understanding and maintenance of Maven projects
you can create a Maven Webapp using following archetype
-DarchetypeArtifactId=maven-archetype-webapp
which will automatically creates the desired folder structure
in your case its apart from src\main\java
src\main\resources
src\main\webapp