Spring Boot - deploy .properties file to a folder different than 'WEB-INF/classes' - spring-boot

I'm trying to convert a traditional Tomcat Spring MVC webapp to Spring Boot. The new application should still use .war deployment.
For various reasons I have the obligatory requirement that the application.properties file resides inside a WEB-INF/conf folder in the deployed app and NOT inside the WEB-INF/classes folder where Spring Boot puts it by default.
In the original webapp I could put the application.properties file inside the src/main/webapp/WEB-INF/conf folder (so they get copied to WEB-INF/conf in the deployed application) and then use it like this:
<context:property-placeholder location="/WEB-INF/conf/application.properties"/>
What is the Spring Boot way to refer to this location?
I tried adding each of the following:
spring.config.location=WEB-INF/conf/application.properties
but my application.properties file still doesn't get loaded.

What finally worked was the following #PropertySource annotation.
#SpringBootApplication
#PropertySource(value = {"WEB-INF/conf/application.properties"})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
It seems that not specifying classpath: or file: at the beginning of a path makes it use a path relative to the webapp.
I'm still not sure as to why specifying
spring.config.location=WEB-INF/conf/application.properties
didn't have the same effect.

Related

jar with embedded tomcat, when using another spring project, is not working with just yml - it's needing a blank application.properties file as well

Been searching for others that have run into this issue, and not finding much out there, so it can't be that common.
I have a spring-boot project that I want to convert into a jar project, running with embedded tomcat. It's using yml files (application.yml and then the profile versions - eg appplication-dev.yml.) It ran fine as war with the yml files, however, when I convert it to a jar, and kick off the jar, the embedded tomcat never starts UNLESSS I add an empty application.properties file as well. (No errors just no Tomcat startup unless the empty application.properties file is added.)
I believe it's somehow related to one of our internal jar dependencies (also spring), since if I remove that dependency from the pom (and any of the code referencing it) I can get the jar to startup the embedded tomcat just fine (without providing the empty application.properties file.)
I could also, of course, forgo using yml files and just use .properties files, but I'd like to use yml files if possible. Why adding an empty applcation.properties file causes things to work has me stumped.
If it helps, the config in the dependency project that causes the issue we're seeing is set up as:
#Configuration
#EnableConfigurationProperties(OracleDataSourceProperties.class)
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.foo.data.services","com.foo.data.domain", "com.foo.utility", "com.foo.cipher.utility"})
#MapperScan(value = {"com.foo.data.services.mapper","com.foo.data.services.batchmapper"})
public class DataServicesPersistenceConfig { ... }
and the OracleDataSourceProperties class:
#ConfigurationProperties(prefix="oradb", ignoreUnknownFields = true)
public class OracleDataSourceProperties extends BaseVO implements InitializingBean{

Springboot Jboss system property issue

In our Springboot MVC project we need to get context path. The following code works fine if we use embedded tomcat. Otherwise if we deploy war file to jboss server, context path returns null.
I tried to add context-root property to jboss-web.xml but changed nothing. I also tried to add "server.servlet.contextPath" property to application.properties file but it doesn't work.
Spring boot version : 2.2.0.RELEASE
Code:
#Configuration
public class EurekaClientConfigBeanListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
String pathValue = System.getProperty("server.servlet.contextPath");
}

How can I load additional properties file in a spring boot application packaged as a war?

I have a standard springboot web app. I want to load properties file that's not in the classpath. application.properties is in the classpath and is being read correctly.
I don't have an issue when I'm building a jar. I just put the .properties alongside the jar and it works. But when I package a war, I couldn't get the application to read the properties file .
You put the properties file parallel to application.properties file and load it in a class like this:
#PropertySource("classpath:foo.properties")
public class My class {
#Value( "${some.property}" )
String myProp;
}
You can using ClassPathResource. given Class for loading resources.
This is sample code for you
ClassPathResource resource = new ClassPathResource("/application/context/blabla.yml");
InputStream inputStream = resource.getInputStream();
File file = resource.getFile();
// using inputStream or file
ClassPathResource
You can use spring application.properties to have spring profiles and use the spring profiles to define separate properties for each environment as you like.You can even separate out the spring profiles in to different files like appication-dev.properties etc so that you can have each spring profile in different files.
You can read the properties by using #Configuration annotation :
#Configuration
#EnableConfigurationProperties(TestProperties.class)
public class MySampleConfiguration {
}
Here TestProperties.class is used to map the values from the property file or yaml .
Reference in detail : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

File can not be loaded from src/test/resources while working on spring boot junit tests

I created one folder src/test/resources and added one file Test.json and trying to access in junit test like this
#RunWith(SpringRunner.class)
#WebMvcTest(value = ReadController.class, secure = false)
public class ReadControllerTest {
#Value("${classpath:Test.json}")
Resource testFile;
#Test
public void test() throws Exception{
File file = testFile.getFile();
System.out.println(file.exists());
}
}
When I run this unit test, it tries to find file in classpath but file is not present there.
How to add this file in classpath?
By Default, spring boot classpath will be pointed to src/main/resources but you are using src/test/resources.
Try to copy the JSON file to src/main/resources.

Spring boot on Tomcat with external configuration

I can't find an answer to this question on stackoverflow hence im asking here so I could get some ideas.
I have a Spring Boot application that I have deployed as a war package on Tomcat 8. I followed this guide Create a deployable war file which seems to work just fine.
However the issue I am currently having is being able to externalize the configuration so I can manage the configuration as puppet templates.
In the project what I have is,
src/main/resources
-- config/application.yml
-- config/application.dev.yml
-- config/application.prod.yml
-- logback-spring.yml
So how can I possibly load config/application.dev.yml and config/application.prod.yml externally and still keep config/application.yml ? (contains default properties including spring.application.name)
I have read that the configuration is load in this order,
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
Hence I tried to load the configuration files from /opt/apache-tomcat/lib to no avail.
What worked so far
Loading via export CATALINA_OPTS="-Dspring.config.location=/opt/apache-tomcat/lib/application.dev.yml"
however what I would like to know is,
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
And is there a better method to achieve this ?
You are correct about load order. According to Spring boot documentation
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).
[Note]
You can also use YAML ('.yml') files as an alternative to '.properties'.
This means that if you place your application.yml file to /opt/apache-tomcat/lib or /opt/apache-tomcat/lib/config it will get loaded.
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
However, if you place application.dev.yml to that path, it will not be loaded because application.dev.yml is not filename Spring is looking for. If you want Spring to read that file as well, you need to give it as option
--spring.config.name=application.dev or -Dspring.config.name=application.dev.
But I do not suggest this method.
And is there a better method to achieve this ?
Yes. Use Spring profile-specific properties. You can rename your files from application.dev.yml to application-dev.yml, and give -Dspring.profiles.active=dev option. Spring will read both application-dev.yml and application.yml files, and profile specific configuration will overwrite default configuration.
I would suggest adding -Dspring.profiles.active=dev (or prod) to CATALINA_OPTS on each corresponding server/tomcat instance.
I have finally simplified solution for reading custom properties from external location i.e outside of the spring boot project. Please refer to below steps.
Note: This Solution created and executed windows.Few commands and folders naming convention may vary if you are deploying application on other operating system like Linux..etc.
1. Create a folder in suitable drive.
eg: D:/boot-ext-config
2. Create a .properties file in above created folder with relevant property key/values and name it as you wish.I created dev.properties for testing purpose.
eg :D:/boot-ext-config/dev.properties
sample values:
dev.hostname=www.example.com
3. Create a java class in your application as below
------------------------------------------------------
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
#PropertySource("classpath:dev.properties")
#ConfigurationProperties("dev")
public class ConfigProperties {
private String hostname;
//setters and getters
}
--------------------------------------------
4. Add #EnableConfigurationProperties(ConfigProperties.class) to SpringBootApplication as below
--------------------------------------------
#SpringBootApplication
#EnableConfigurationProperties(ConfigProperties.class)
public class RestClientApplication {
public static void main(String[] args) {
SpringApplication.run(RestClientApplication.class, args);
}
}
---------------------------------------------------------
5. In Controller classes we can inject the instance using #Autowired and fetch properties
#Autowired
private ConfigProperties configProperties;
and access properties using getter method
System.out.println("**********hostName******+configProperties.getHostName());
Build your spring boot maven project and run the below command to start application.
-> set SPRING_CONFIG_LOCATION=<path to your properties file>
->java -jar app-name.jar

Resources