I have created one spring boot application, I do not want to keep datasource information in application.properties file as this information will keep on changing. So, All data source information have mentioned in external .txt file. This file is placed outside of project. I am reading this file programmatically. Here is the code,
#SpringBootApplication
public class SpringBootApplicationLuncher {
public static void main(String[] args) throws IOException {
Properties mainProperties = new Properties();
mainProperties.load(new FileInputStream("dbconnection.txt"));
SpringApplication.run(SpringBootApplicationLuncher.class,args);
}
file dbconnection.txt is having below information.
spring.datasource.url=jdbc:mysql://<ip address>:3306/<dbname>
spring.datasource.username=<username>
spring.datasource.password=<password>
When i execute the application, I am getting an error,
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Can anyone please help ?
If you want to pass mainProperties into Spring Boot application, you can use SpringApplicationBuilder for this:
#SpringBootApplication
public class SpringBootApplicationLuncher {
public static void main(String[] args) throws Exception {
Properties mainProperties = new Properties();
mainProperties.load(new FileInputStream("dbconnection.txt"));
new SpringApplicationBuilder()
.sources(SpringBootApplicationLuncher.class)
.properties(mainProperties)
.run(args);
}
}
However Spring Boot already provides a way to externiliaze your configuration, check this documentation for more details
Related
I am writing a Spring Boot project to Run a Cloud Config Server and 3 Micro-services to run as a Client.
I would want to check availability of all properties in application.properties or yaml file before starting the tomcat server.
We already have a similar one for Database Startup Validation, but here I am trying to achieve the same for Property file availability.
Can someone let me know or suggest possible solutions.
You can simply add whatever you want to add in application.properties / yaml file and then access the property and its value in SpringBoot Application like this.
I think this could help you.
application.properties
property1=true
property2=false
property3=abc
property5=1223243
and in SpringBoot Application
TestApplication.java
#SpringBootApplication
public class TestApplication{
#Value("${property1}")
private boolean property1
#Value("${property2}")
private boolean property2
#Value("${property3}")
private String property3
#Value("${property5}")
private int property5
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
[UPDATE]
If we are agreed to create a Pre-Script that run before tomcat startup then
Using the following code snippet we can parse the application.properties file and create object and then loop through the length of properties file and check the Key Value pairs
FileReader reader=new FileReader("application.properties");
Properties p=new Properties();
p.load(reader);
System.out.println(p.getProperty("user"));
System.out.println(p.getProperty("password"));
I want to achieve is that springboot gets the property values configured in the database to complete the automatic configuration. Just like using application.properties
It is possible to programatically override Spring properties at startup. This would be a good place to retrieve the properties from any database that you whish and set them.
Here is an example (copy/pasted from this answer) . You would have to add getting the configuration from the database
#SpringBootApplication
public class Demo40Application{
public static void main(String[] args){
SpringApplication application = new SpringApplication(Demo40Application.class);
Properties properties = new Properties();
properties.put("server.port", 9999);
application.setDefaultProperties(properties);
application.run(args);
}
}
There are so many properties which can be defined in application.properties of spring boot application.
But I want to pass properties to configure ssl to spring from inside the code.
server.ssl.enabled=true
# The format used for the keystore
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
server.ssl.key-store=keys/keystore.jks
# The password used to generate the certificate
server.ssl.key-store-password=changeit
# The alias mapped to the certificate
server.ssl.key-alias=tomcat
So as these will be spring defined properties to be used from application.properties. I just want to set them from the code based on some logic.
For non spring application, I still have some idea that they can be passed as application, session or context properties but I am not aware on how this works in spring.
Any help would be appreciated.
Since you know the properties to enable SSL in the spring boot app. You can pass these properties programmatically in your spring boot application like this:
#SpringBootApplication
public class SpringBootTestApplication {
public static void main(String[] args) {
// SpringApplication.run(SpringBootTestApplication.class, args);
Properties props = new Properties();
props.put("server.ssl.key-store", "/home/ajit-soman/Desktop/test/keystore.p12");
props.put("server.ssl.key-store-password", "123456");
props.put("server.ssl.key-store-type", "PKCS12");
props.put("server.ssl.key-alias", "tomcat");
new SpringApplicationBuilder(SpringBootTestApplication.class)
.properties(props).run(args);
}
}
As you can see I have commented out this:
SpringApplication.run(SpringBootTestApplication.class, args);
and used SpringApplicationBuilder class to add properties to the app.
Now, these properties are defined in the program, You can apply condition and change property values based on your requirements.
In Spring Boot, you can read and edit propeties using System.getProperty(String key) and System.setProperty(String key, String value)
public static void main(String[] args) {
// set properties
System.setProperty("server.ssl.enabled", "true");
System.setProperty("server.ssl.key-store-type", "PKCS12");
System.setProperty("server.ssl.key-store", "keys/keystore.jks");
System.setProperty("server.ssl.key-store-password", "changeit");
System.setProperty("server.ssl.key-alias", "tomcat");
// run
SpringApplication.run(DemoApplication.class, args);
}
Note:
This will overwrite the static properties (not all but the overwritten ones).
You need to define and register an ApplicationListener like this:
public class DynamicPropertiesListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
// modify the properties here, see the ConfigurableEnvironment javadoc
}
}
Now register the listener. If you run the application with the main method:
SpringApplication app = new SpringApplication(primarySources);
app.addListeners(new DynamicPropertiesListener());
app.run(args);
or, even better, create src\main\resources\META-INF\spring.factories file with this content:
org.springframework.context.ApplicationListener=x.y.DynamicPropertiesListener
Where x.y is the package of your listener.
I have this configurations which needs to be used for a spring boot application.
server.port=8085
server.servlet.context-path=/authserver
#data source
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=<url>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
By default spring-boot picks up up the application.properties file located in src/main/resources/
I want to alter this path and direct spring boot to different application.properties file
I can achieve this using
java -jar app.jar --spring.config.location=classpath:/another-location.properties
Is there any any alternative solution I can achieve this without passing args through command line?
I was using this
#PropertySource("file:C:\Users\test\.test\test.properties")
#ConfigurationProperties(prefix = "spring")
public class Configuration {
private String ddlAuto;
private String url;
private String username;
private String password;
private String driverClassName;
}
in my Main class
#SpringBootApplication
#EnableConfigurationProperties(Configuration.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There after I tried executing the app commenting out all datasource properties in application.properties under src/main/resources/
But it keeps giving me the error mentioned bellow and application fails to start
I was referring this tutorial : https://www.mkyong.com/spring-boot/spring-boot-configurationproperties-example/
but as it's mentioned I get this error when i start the spring boot application
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException:
Any help on this would be appreciated
The recommended way to have externalized properties is to use the spring.config.location system property, by starting your application like so:
java -jar -Dspring.config.location=/path/to/my/file.properties app.jar
The reason for this is that you don't add coupling between your code and your filesystem hierarchy.
Before Spring Boot 2.0 this property is additive, meaning that it will complement the default locations. After Spring Boot 2.0, spring.config.location replaces the default locations (e.g. classpath src/main/resources/application.properties). To keep the additive behaviour after 2.0, use spring.config.additional-location instead.
Please see here for official documentation on this matter.
I am able to make it work properly on Spring Boot 2.1.2.RELEASE. This is what I have done:
I have a test.properties in my /tmp folder with the following content:
test.myprop=hello
I also have the usual property file in the resources folder:
myprop=world
I have created a class for the custom property file:
#Configuration
#PropertySource("file:/tmp/test.properties")
#ConfigurationProperties(prefix = "test")
public class TestConfig {
private String myprop;
public String getMyprop() {
return myprop;
}
public void setMyprop(String myprop) {
this.myprop = myprop;
}
}
And then in my main class I have enabled to configuration properties:
#EnableConfigurationProperties(TestConfig.class)
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Now I have this test controller:
#RestController
public class TestController {
#Value("${test.myprop}")
private String externalisedProp;
#Value("${myprop}")
private String prop;
#GetMapping("test")
public void test() {
System.out.println("externalised: " + externalisedProp);
System.out.println("not externalised" + prop);
}
}
Which, once called, is properly printing:
externalised: hello
not externalised: world
My TestConfig class is in the same package as the MyApp main class.
What I have done is very similar, almost identical, to your solution, are you sure your path is correct? Also, I can see that the content of your property file is not matching what you have in your config class, the prefix is different. Maybe that is the problem?
Edit:
I have tried to remove the #Configuration annotation from my property class (which you do not have as well) and it is not able to pick up the externalised properties anymore. The error is different though but you should try to add it.
I am trying to create a AnnotationConfigApplicationContext programmatically. I am getting a list of Configuration classes and a list of property files to go with it in a Spring XML file.
Using that file, I am able to use XmlBeanDefinitionReader and load all #Configuration definitions fine. But, I am not able to load properties.
This is what I am doing to load properties..
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
for (String propFile : propertyFiles) {
propReader.loadBeanDefinitions(new ClassPathResource(propFile));
}
Code just runs through this without any issues, but once I call
ctx.refresh() -- it throws an exception
Caused by: java.lang.IllegalStateException: No bean class specified on bean definition
at org.springframework.beans.factory.support.AbstractBeanDefinition.getBeanClass(AbstractBeanDefinition.java:381)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:54)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
All the classes are available on the classpath, if I just don't load the above properties programmatically application just comes up fine (Because I am using other way to load properties).
Not sure, what I am doing wrong here. Any ideas? Thanks.
I am not sure why you are loading properties manually, but Spring standard for AnnotationConfigApplicationContext is
#Configuration
#PropertySource({"/props1.properties", "/props2.properties"})
public class Test {
...
as for programatic loading, use PropertySourcesPlaceholderConfigurer instead of PropertiesBeanDefinitionReader, this example works OK
#Configuration
public class Test {
#Value("${prop1}") //props1.properties contains prop1=val1
String prop1;
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(Test.class);
PropertySourcesPlaceholderConfigurer pph = new PropertySourcesPlaceholderConfigurer();
pph.setLocation(new ClassPathResource("/props1.properties"));
ctx.addBeanFactoryPostProcessor(pph);
ctx.refresh();
Test test = ctx.getBean(Test.class);
System.out.println(test.prop1);
}
}
prints
val1