How prevent Spring boot war file load component twice in separated context? - spring

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!

Related

Can we implement Spring batch application without Spring Boot?

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

Run Spring Batch (JSR-352) application on Spring Boot

I have a simple Spring Batch application complying with JSR-352.
I need to deploy this as a managed Task on Spring Cloud Data Flow server. As far as I know - to be able to deploy this as a Task I need to convert this application as a Spring Boot app.
I have tried to add Spring Boot dependencies and Main class however it is not running the Batch job when I start the app.
Main Class
#SpringBootConfiguration
#EnableAutoConfiguration
#EnableBatchProcessing
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Batch File created at
META-INF/batch-jobs/myjob.xml
It works when I use JobOperator in the main class to start the job (without Spring Boot).
What am I missing to run this as a Spring Boot app?
You're missing #EnableTask annotation. With that, your batch-job will be run as a short-lived application. In other words, the application will run as long as the business logic in your XML needs to run, and it will gracefully shut down and free-up resources.
Please clone and try out the Spring Cloud Task samples [see: BatchJobApplication]. All of them should work as-is in SCDF as well.
#EnableBatchProcessing
#SpringBootApplication
public class BatchApplication {
public static void main(String[] args) {
SpringApplication.run(BatchApplication.class, args);
}
#Bean
public CommandLineRunner run(JobOperator jobOperator) {
return $ -> jobOperator.start("myjob", new Properties());
}
#Bean
JobParametersConverter jobParametersConverter(DataSource dataSource) {
return new JsrJobParametersConverter(dataSource);
}
#Bean
JobOperator jsrJobOperator(ApplicationContext applicationContext, JobExplorer jobExplorer,
JobRepository jobRepository, JobParametersConverter jobParametersConverter,
PlatformTransactionManager transactionManager) {
JsrJobOperator jobOperator = new JsrJobOperator(jobExplorer, jobRepository, jobParametersConverter,
transactionManager);
jobOperator.setApplicationContext(applicationContext);
jobOperator.setTaskExecutor(new SimpleAsyncTaskExecutor());
return jobOperator;
}
}
https://gist.github.com/rixwwd/8091a717ca24fd810ff71b4fdebbf9cc

Can I have two public classes in spring - boot?

In my springboot application I am needing to deploy to an existing tomcat server so I need to deploy the application as a war file. In order to do that I have to alter my main class a bit.
I currently have the following code in my main application class
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
private UserService userservice;
public Static void main(String[] args) {
SpringApplication.run(Application.class, args);
I need to change it to the following to be able to have maven change it to a war file instead of a jar.
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Autowired
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Problem is I need the commandlinerunner implemented as well. Can I have both? If so how would I go about doing this? I have searched and the information I have found so far has been ambiguous at best. Any assistance would be greatly appreciated as well as the documentation so I can review it as well as share it if I come across others having a similar issue.
EDIT: I did find one document that seemed to imply I could have both implimented within the same application.java and within the pom.xml file stating which one should be initialized first. Would this be a correct way of doing this? I read in another overstack that an individual that tried this ended up with two applications because of it. Unfortunately he did not provide much code to explain what he tried, only what his outcome was.
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}

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 !

Resources