I can see many posts regarding environment specific properties, but none of them is quite solving my problem.
I'm working on my spring boot app, which will have say two profiles dev/live.
I want my project to have the following structure:
--deployment
--dev
--myapp.properties
--live
--myapp.properties
--src
--main
--java
--resources
--test
--java
I know that if I had two application.properties in my resources folder, say application-live.properties and application-dev.properties I'd be able to tell maven which one to pick at application start time using:
Dspring.profiles.active=profile_name
But I don't like name of this generic properties file. So I found this way to tell the application where to look for profile specific properties in /deployment/<profile>/.
I did it using Maven build task configuration:
<build>
<resources>
<resource>
<directory>deployment/${environment}</directory>
<includes>
<include>*.properties</include>
<include>*.xml</include>
</includes>
</resource>
</resources>
</build>
This is going to search for resources in deployment/<profile> and include them. Good thing is that Maven finds the correct environmental property files, but unfortunately it includes them in target/classes/myapp.properties which seems invisible for Spring Boot? How can I tell Maven to place it in the same directory as application.propertiesor alternately how can I tell Spring Boot to find it where it is at the moment?
Thanks a lot!
How can I tell Maven to place it in the same directory as application.propertiesor alternately how can I tell Spring Boot to find it where it is at the moment?
1) you don't need to modify Maven settings because it places config file to the right place: target/classes is the root of the classpath, because all files from this directory will copied into the WEB-INF/classes directory of you WAR/JAR file.
2) to change name of the properties file from you can use spring.config.name property by explicitly passing it as -Dspring.config.name=myapp or as environment variable SPRING_CONFIG_NAME=myapp. More information you can find in the Change the location of external properties of an application chapter of the official documentation.
Related
I am using Netbeans 8.2 to develop Spring applications. This specific app with which I am having trouble is a Spring Boot 1.5.3 app. I have a spring xml file and an application.properties that I keep in /config under the root project directory.
I am passing the spring xml file to my project via the #ImportResource annotation and a value property like #ImportResource(value="${config.xmlfile}").
When I click the 'Run Project' button in Netbeans my Spring app starts up and it correctly finds the application.properties file in my /config folder. However, any classpath references to other files in that folder are lost. For example, setting the config.xml file to classpath:config/file.xml or classpath:file.xml both fail to find the file but file:config/file.xml works.
Similarly, when running from the command line I have the following as my structure:
app/
|-- bin
| `-- app-run.sh
|-- config
| |-- application.properties
| |-- log4j2.xml
| |-- file.xml
`-- app-exec.jar
I am using the spring-boot-maven-plugin to make the jar as follows:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
and my app-run.sh script executes the following:
exec /bin/java -cp :.:../config/*:../app-exec.jar
-Dlogging.config=../config/log4j2.xml
-Dspring.config.location=../config/application.properties
-jar ../app-exec.jar
where /bin/java represents the location where I have java installed. The classpath set in -cp does not seem to be working here. Similarly to when running through the IDE, setting the config.xml file to classpath:config/file.xml or classpath:file.xml both fail to find the file but file:../config/file.xml works.
I would like to be able to set the classpath in both the IDE and from command line so that I can access files in Spring using classpath reference to make things easier. I do NOT want to put them all in src/main/resources and have them be packaged in the jar, as I need to edit these after packaging and deployment.
Does anybody have any ideas or helpful hints? Thanks in advance!
Updated answer:
You can follow the practice in my original answer, but we recently dropped this for a simpler and cleaner option that is more standard (the "Java" way). We made the change because we needed to dynamically load dependent libraries at runtime that were not available at compile time (in their exact version). In our case we wanted to load dependent jars only from separate folder(s) and not from an executable jar. We ended up having duplicate dependencies in the executable jars and in separate folder(s), so we decided to drop the executable jar Properties Launcher and instead only load dependencies from separate folders. This is often NOT the best option and should be evaluated for your use case. I prefer reading the standard Java classpath.
To run a Spring Boot app without an executable jar, we used Maven Assembly to put the dependent jars in a /libs directory and dropped the spring-boot-maven-plugin. The steps and some code for this are below:
Remove the spring-boot-maven-plugin that creates the executable jar in ZIP format
Add the following to your assembly XML
<dependencySets>
<dependencySet>
<outputDirectory>where you want the libs to go</outputDirectory>
<useProjectArtifact>whether you want to include the project
artifact here</useProjectArtifact>
</dependencySet>
</dependencySets>
Run your code from the main class and include the dependent jar folder(s) on the classpath. Use the standard classpath notation on your OS and not the custom, awkward PropertiesLauncher loader path syntax
java -cp <standard-classpath> <main-class>
An example of an actual call:
java -cp $CLASSPATH:./lib/*:./cfg/*:my-app.jar Application.class
In this way you execute the Spring Boot app via standard java execution call, no custom Spring loading syntax. You just need to ensure that all of your dependencies are available on the classpath at runtime. We found this much easier to maintain and made this the standard for all of our apps.
Original answer:
After some researching, and thanks to #TuyenNguyen's helpful answer I was able to get the following working:
I added the following to my spring-boot-maven-plugin so that when I run from the command line it uses the PropertiesLauncher instead of the JarLauncher:
<configuration>
<mainClass>${mainClass}</mainClass>
<layout>ZIP</layout> //THIS IS THE IMPORTANT PART
</configuration>
See here and here for more about the PropertiesLauncher options. It allows you to set the classpath, among other things.
See here, here, and here for where I found the answer to this problem. Using format ZIP makes the PropertiesLauncher be used.
From there, I was able to use this command to launch the application as I intended:
java -Dloader.path=../config,../ -Dloader.config.location=classpath:application.properties -jar ../app-exec.jar
Another important note: when specifying the -Dloader.path make sure to use comma-separated values and only directories and files, as described here. Also, be sure to put the -D args before you specify -jar jar or they will not be set.
If anyone has any suggestions or edits to further improve this answer or the original question in order to help additional users, please let me know or make the edits yourself!
If you don't put your files in src/main/resources then you can put it inside any folder that you want, BUT you must set your folder as a resources folder. Because classpath is always point to resources folder. Once you make your folder as a resource folder, it will be packaged into the jar. If you want to edit your resource file, just using 7 zip tool to open your jar -> edit files -> save -> it will update your change in the jar.
Another solution is create a folder, put all files you want to edit and not packaged in that, then set classpath manually to that folder every time you run, but the way you set above is not correct, try this solution for set classpath correct way.
I am using maven for my spring boot application(1.5 version). There are some files in src/main/resources like abc.properties, app.json. Below are some pointer what i want to achieve.
Exclude these files getting into the jar.
When i run my application through intellij these files should be available in classpath.
I looked at related answers on SO but none matches my case. Any suggestion?
you can use the resouce tag in maven pom file:
<resources>
<resource>
<directory>[your directory]</directory>
<excludes>
<exclude>[non-resource file #1]</exclude>
<exclude>[non-resource file #2]</exclude>
<exclude>[non-resource file #3]</exclude>
...
<exclude>[non-resource file #n]</exclude>
</excludes>
</resource>
...
</resources>
For more informations see: https://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html
My understanding is
You want some config file, that is available in classpath during runtime
Such config file will be changed based on environment
The way I used to do is:
Create a separate directory for such kind of resources, e.g. src/main/appconfig/
Do NOT include this in POM's resources (i.e. they are not included in resulting JAR)
In IDE, add this directory manually as source folder (I usually put this in testResource in POM. When I use Eclipse + M2E, testResources will be added as source folder. Not sure how IntelliJ though)
For point 2, I used to do it slightly differently. Instead of excluding, I will include in the result JAR but in a separate directory (e.g. appconfig-template), so that people using the application can take this as reference to configure their environment.
An alternative of 3 is: create a separate profile which include appconfig as resource. Use this profile only for your IDE setup but not building your artifact.
So I have the following folder structure:
Project
lib
(running jar from this folder)
properties (property file to load is in this folder)
I am trying to load a property file via X.class.getClassLoader().getResource("properties/fileName"). This method works in eclipse but when I build the jar using maven it fails to find the file, giving a file not found exception.
I suspect the folder is not in the classpath because if I run getClassLoader().getResources("") the property folder never shows up. I tried all the suggestions in previous questions on stackoverflow but none have worked so far.
I also tried running java -cp and -classpath but it still failed.
When using Maven, files like *.properties and any other not-compilable files must lie at src/main/resources folder, by default, to be available.
Additionally, I would recommend you to use Thread.currentThread().getContextClassLoader() to get a proper classloader, in order to load resources.
Anyway, if you want to have your custom folder at classpath, I suggest you to add as a resource, at the pom.xml, like this:
<project>
...
<build>
...
<resources>
<resource>
<!-- The folder you want to be a resource (from project root folder), like: project/properties -->
<directory>properties</directory>
<!-- Filtering if Maven should post-process text files to find and replace ${key} params: in most cases, leave it false -->
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
I want to logging to file and set it in properties file, because default logger.info() output goes to console and in web application there is no console in my case.
As Navi says... it goes in src/main/resources
Just to clarify this subject... the logging.properties must go in WEB-INF/classes directory.
If you are using some kind of framework for organizing your project, you must find out where to place the file in order to stay in WEB-INF/classes
If you are using maven to organize the web app, you must know that everything that lies in src/main/resources goes to WEB-INF/classes.
you should put in src/main/resources
This is the first place I found when I was trying to figure out where my logging.properties file needed to go while testing.
TL;DR: src/test/resources
Deploy to Tomcat
When running as a web application, as this comment suggests, I don't need to deploy a logging.properties file to src/main/resources (although that probably would have fixed my immediate problem). My container already has one. For Tomcat, that location is $CATALINA_HOME/conf/logging.properties. If you are running Tomcat from Eclipse, you can set that in launch configuration, as explained here.
This answer talks about setting up different logging properties per application, which is what putting the file in src/main/resources does.
This section is the answer to the poster's question. The rest of this is the answer to my similar but different problem.
Debugging tests
The actual problem that I was having was that my java.util.logging stopped showing the class name and method name after I added an SLF4J-using jar to my project and was trying to debug my unit tests. I had to add org.slf4j:slf4j-jdk14 to my POM in Provided scope so that my tests would run at all. But then they didn't have class and method names. Configuring the logging.properties file to match the one for Tomcat but with different handlers fixed that after I added some Surefire configuration:
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
<property>
<name>java.util.logging.config.file</name>
<value>src/test/resources/logging.properties</value>
</property>
<property>
<name>java.util.logging.manager</name>
<value>org.apache.juli.ClassLoaderLogManager</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
And my logs once again were showing all the information even when running tests from Maven.
Summary
If you want to set how your regular application is logging, then src/main/resources may be the right place. But I wanted to change how my tests were logging, so I used src/test/resources instead. Since Tomcat's launch configuration doesn't run under typical unit tests, I had to add some configuration to Surefire to serve the same purpose. The logging.properties outside Tomcat does not use any Catalina jars, so I switched it to use different handlers.
If you are using Tomcat, then you should log to $CATALINA_HOME/logs/myapp/myapp.log.
Imagine I have a project I want to build using maven. My project doesn't, unfortunately, respect the maven default layout. So I'm having two source folders A & B containing .properties files with .java sources.
After an mvn install, my .properties files are not packaged in the jar with my .class generated files. Is there a way to do this automatically, you'd probably propose to use <resources> tag to solve this kind of problems; this obviously works I know, but i'll have to each time specify where my .properties files are stored, and where I want them to be packaged in the JAR, this is not a solution for me since I have multiple source folders (hundreds) regularly updated.
<resource>
<targetPath>com\vermeg\jar2</targetPath>
<filtering>true</filtering>
<directory>${basedir}/a/jar2</directory>
<includes>
<include>*.properties</include>
</includes>
<excludes>
<exclude>*.java</exclude>
</excludes>
</resource>
Will I have, for each source folder, to write this in my POM, does anyone knows a simpler automatic way to do this ?
Regards,
Generally you can use Maven properties and profiles to solve this kind of problem.
For example edit your pom to:
<resource>
<targetPath>${myresources.targetpath}</targetPath>
<directory>${myresources.directory}</directory>
...
</resource>
and define myresources.directory and myresources.targetpath in command line using -Dname=value or in conditional profile or by using other properties available in your build.
If you explain your project structure and/or conditions and their relation to your variable (targetPath and directory) I may be able to help more with your question.
Specify it once in a parent pom instead, and all the children should inherit the same setup...
Would it be impossible to change to using the standard Maven layout, with all your properties in a parallel 'package' hierarchy under src/main/resources? Then you don't need to specify anything; all .properties files will be packaged.
If you do this, you'll need to enable filtering as it's off by default. You may have to explicitly declare the resource directories again, as when you declare them, this seems to override the ones you get 'for free'.
As for your multiple source folders, a multi-module Maven project would probably be the best fit, with A and B being children of some new parent project.
This might seem like quite a lot of work, but Maven's conventions are fairly reasonable, and it tends to be a painful experience if you go against them.