spring boot - load app config before calling method run - spring-boot

is there a way to read yaml file of a spring boot app before launching the app, more exactly before calling method run.
here is my code :
#SpringBootApplication
public class CometeRestApi extends SpringBootServletInitializer {
private static void setMongoSecure() {
System.setProperty("javax.net.ssl.keyStore", System.getProperty("user.home") + "/.ssl/client-and-key.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "");
System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.home") + "/.ssl/certificateChain.jks");
System.setProperty("javax.net.ssl.trustPassword", "");
}
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
setMongoSecure();
return application.sources(CometeRestApi.class);
}
public static void main(final String[] args) {
setMongoSecure();
SpringApplication.run(CometeRestApi.class, args);
}
}
thanks in advance for help

Yes, there are several ways to do it, but the recommended way is to use an EventListener. Annotating a method with #EventListener(ApplicationReadyEvent.class) is ideal when your purpose is to automatically execute code after your application startup.

Related

how to package the springboot application with dynamic end points on application.properties file

I have 1 spring boot application. In this application i have configured 1 eCommerce system as elastic path(Configure the end point url of elastic path in application.properties file). Now i have to give my spring boot application to some other guys. which will be deploy on tomcat server. I don't want to give the source code. So i can make the war file but now problem is that they have their own elastic path eCommerce and they wants to configure their own eCommerce.
I want to externalize some properties which will override the existing property.
My springboot application have 2 modules :
1) elasticpath module which is having elasticpath-application.properties
2) salesforce - salesforce-application.properties
Now i have to externalize "C:\apache-tomcat-8.5.29\conf\ep-external.properties" file which will override the existing property. Now problem is that #PropertySource is loading in last position. So my external file is not able to override the property.
#SpringBootApplication
#PropertySource(value = {"classpath:application.properties", "classpath:elasticpath-application.properties", "classpath:salesforce-application.properties")
public class SpringBootDemo extends SpringBootServletInitializer implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(SpringBootDemo.class);
private ServletContext servletContext;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//application = application.properties("file:C:\\apache-tomcat-8.5.29\\conf\\ep-external.properties");
return application.sources(SpringBootDemo.class);
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
this.servletContext = servletContext;
super.onStartup(servletContext);
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo.class, args);
}
#Override
public void run(String... args) throws Exception {
}
}
Yes absolutely possible. Basically what you need is changing the property value as needed without changing jar/war
Passing command line args for jar
Package your spring boot application as jar and put the external application.properties file at any location and pass on the same location as command line argument as below :
java -jar app.jar --spring.config.location=file:<property_file_location>
This will pick up the external properties.
Passing command-line/dynamic args for war
1. Extend the SpringBootServletInitializer as below
#SpringBootApplication
class DemoApp extends SpringBootServletInitializer {
private ServletContext servletContext;
public static void main(String[] args){SpringApplication.run(DemoApp.class,args);}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
builder = builder.properties("test.property:${test_property:defaultValue}");
return builder.sources(DemoApp.class)
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
this.servletContext = servletContext;
super.onStartup(servletContext);
}
}
Access the property as usual like below anywhere you want :
#Value("${test.property}")
Before starting tomcat set the env variable named test_property. that's it
Additionally:
You can pass on the property like below as well if you want to supply complete file as external file.
.properties("spring.config.location:${config:null}")
Further reading about externalized configuration : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

How to bootstrap SpringBoot application (without mvc)?

I want to use spring-data & IOC container for some test app.
And the problem is: how to bootstrap the app?
In case of spring-mvc we move from controllers, but how to do this without mvc?
I need some main-like method for my code, but the application public static void main is already used for spring initialization:
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
So, where should I place my code?
There is a CommandLineRunner interface that just means to do that.
#Service
class FooBar implements CommandLineRunner {
// Inject whatever collaborator you need
#Override
void run(String... args) throws Exception {
// Execute whatever you need.
// command-line arguments are available if you need them
}
}

How to check if Spring boot is running in standalone or embedded mode?

Is there some reliable way how to check if spring boot is running in JAR (standalone with embedded tomcat) or WAR (in j2ee server) mode?
There's no built in API to check which environment you're running in. Probably the most robust way would be to use different configuration for your application depending on whether it's started via its main method or via its SpringBootServletInitializer subclass. Exactly what you should do depends on your reason for needing to know and also personal preference.
For example, you could configure a property that you can the query via the Environment, using #Value, etc:
#SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ExampleApplication.class).properties(
"com.example.mode:servlet-container");
}
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(ExampleApplication.class).properties(
"com.example.mode:standalone").run(args);
}
}
Another option would be to provide a configuration class in addition to ExampleApplication.class that's different depending on what mode you're running in:
#SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ExampleApplication.class,
ServletContainerConfiguration.class);
}
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(ExampleApplication.class,
StandaloneConfiguration.class).run(args);
}
}
Exactly what you do in ServletContainerConfiguration or StandaloneConfiguration is then up to you. You could, for example, publish a bean that remembers the mode and then query it whenever you need to know.
Yet another option would be to activate different profiles depending on the mode.

Why do I need main method if I develop web app as war using Spring Boot?

I am developing web app using Spring Boot. My typical deployment is generating war and place it in webapps folder in Tomcat directory.
I noticed with SpringBoot, I will need a main method. I am wondering why this is needed. If there is a way to avoid it, what would that be?
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Main method is not required for the typical deployment scenario of building a war and placing it in webapps folder of Tomcat. All you need is:
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
However, if you want to be able to launch the app from within an IDE (e.g. with Eclipse's Run As -> Java Application) while developing or build an executable jar or a war that can run standalone with Spring Boot's embedded tomcat by just java -jar myapp.war command, an entry point class with a main method might be helpful.
To run in a separate web container
You don't need the main method, all you need is to do is to extend SpringBootServletInitializer as Kryger mentioned.
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
....
....
To run in the command line as a standalone application
Here you need the main method, so that you can run it using java -jar from the command line.
public class Application {
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
}
....
....
Source: https://spring.io/guides/gs/convert-jar-to-war/
In Spring Boot one will basically need three things :
1) use the #SpringBootApplication annotation
2) extend SpringBootServletInitializer
3) overwrite the configure method as shown above
and that's it !

How to configure Spring Data REST to return the representation of the resource created for a POST request?

I am following the spring-data-rest guide Accessing JPA Data with REST. When I http post a new record it is inserted (and the response is a 201). That is great, but is there a way to configure the REST MVC code to return the newly created object? I'd rather not have to send a search request to find the new instance.
You don't have to search for the created entity. As the HTTP spec suggests, POST requests returning a status code of 201 Created are supposed to contain a Location header which contains the URI of the resource just created.
Thus all you need to do is effectively issuing a GET request to that particular URI. Spring Data REST also has two methods on RepositoryRestConfiguration.setReturnBodyOnCreate(…) and ….setReturnBodyOnUpdate(…) which you can use to configure the framework to immediately return the representation of the resource just created.
Example with Spring Boot:
#Configuration
#EnableMongoRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
RepositoryRestConfiguration restConfiguration = ctx.getBean(RepositoryRestConfiguration.class);
restConfiguration.setReturnBodyOnCreate(true);
}
}
or
#Configuration
#EnableMongoRepositories
#EnableAutoConfiguration
public class Application extends RepositoryRestMvcConfiguration {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
super.configureRepositoryRestConfiguration(config);
config.setReturnBodyOnCreate(true);
}
}
Good Luck!
If you are using Spring Boot, you can add the following lines to your application.properties file for POST (create) and PUT (update) respectively
spring.data.rest.return-body-on-create=true
spring.data.rest.return-body-on-update=true
Here's another variant that uses DI rather than extending RepositoryRestMvcConfiguration or using the ConfigurableApplicationContext.
#SpringBootApplication
#EnableConfigurationProperties
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Autowired private RepositoryRestConfiguration repositoryRestConfiguration;
#PostConstruct
public void exposeIds() {
this.repositoryRestConfiguration.setReturnBodyForPutAndPost(true);
}
}

Resources