Can we implement Spring batch application without Spring Boot ?
Instead of an executable JAR you can also deploy a Spring Boot application as a WAR to JBoss.
The SpringBootApplication class will look a bit different:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And you have to use
<packaging>war</packaging>
Please find more information in the official documentation: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file
Related
I have a spring boot application, packaged as a war file and deployed on tomcat server. I noticed that some component load twice in startaup:
when application is started
when ServletInitializer is started.
It caused me some problem because one of my components is EnableAsync and should do some scheduled task frequently. when it load twice in tow separated context each task is done twice and make duplicated rows in database.
Is there a way that force some component just load in single context in Spring boot? it means prevent bean to be initialized in ServletInitializer for example.
That's my SpringBootServletInitializer code:
#SpringBootApplication
#EnableScheduling
#EnableAsync
public class TestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(TestApplication.class);
}
}
Thanks to M. Deinum I found out there is an extra SpringBootServletInitializer in my code! I deleted it and Every thing is Ok now!
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
I am trying to deploy two spring boot application services on external tomcat.
Eureka service
Client service
When I deployed these two services on external tomcat, I am able to deploy and I am able to access these two services separately but my client service is not able register with Eureka service and I can't see it on eureka console.
My Eureka service properties file:
#EureakaService.properties#
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
spring.application.name=EurekaServiceApplication
logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF
Below is my Client service properties file
#ClientService.properties#
spring.application.name=CBEApplication
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka-server-1.8.0
I am not sure what is wrong with my configuration settings.
EurekaService class as below# #EnableEurekaServer
#SpringBootApplication
public class EurekaServiceApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(EurekaServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
} #Client Class code as below# #SpringBootApplication
#EnableDiscoveryClient
public class CBEApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(CBEApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(CBEApplication.class, args);
}
}
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.
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 !