SpringBoot, run a daemon as CommandLine (JAR) and inside Tomcat (WAR)? - spring

I want to create a Java deamon process (MQ processor) which can be run both from the commandline (java -jar ...) but also as WAR inside a JEE Container like Tomcat. It should automatically start once the WebApp starts. This App is not going to have a WebGUI.
It seems that I can use SpringBoot for this. SpringBoot can both create WAR and JAR-files.
My question is: should I use SpringBoot ApplicationRunner for a portable daemon?
What is the best practice/recipe to create a portable (CLI/WebApp) daemon process with SpringBoot?
How does this work under the hood? If I use ApplicationRunner and create a WAR, does SpringBoot create a Servlet of this?
Tx

ApplicationRunner is new in Spring Boot 1.4. It is similar to CommandLineRunner of Spring Boot 1.3. It isn't involved in the wiring up of the Application context as such that interface wouldn't be responsible for creating any Servlets in the WAR deployment. Here is details on deploying your app as a WAR:
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
#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);
}
}
The SpringBootServletInitializer is what will create the servlet.
Now I am not sure how you are setting up the MQ processor but if it is wired up as a bean and has some listener thread for messages on a queue then you don't really need the ApplicationRunner. You would just need to wire up the processor as a bean and have a #PostConstruct annotation on it so that you can start the listener thread. If you don't have control of the annotations on the bean then you can use the ApplicationRunner and have it Autowired with the processor bean. The runner would then start up the listener thread.

Related

Importance of SpringBootServletInitializer in the WAR deployment

I have gone through some tutorials and learnt that ApplicationContext is responsible for managing all the beans created in the spring application. When the WAR is to be deployed to a servlet container, it is essential to extend SpringBootServletInitializer and from the documentation it says
An opinionated WebApplicationInitializer to run a SpringApplication from a traditional WAR deployment. Binds Servlet, Filter and ServletContextInitializer beans from the application context to the server.
Can someone help me understand what the above line means ? How ServletContext initializer is related to the SpringBootServletInitializer ? Why can't a servlet container create a ServletContext on it's own ? If this the case how can we get the hold of ServletContext reference of a SpringApplication programatically created by Tomcat after using SpringBootServletInitializer?
The web application uses the static main entry point when you run the embedded application server. The main entry point usually looks like this:
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
or this:
public static void main(final String[] args) {
SpringApplication springApplication = new SpringApplicationBuilder(Application.class)
.properties("spring.main.banner-mode=log")
.build();
springApplication.run(args);
}
Both use the SpringApplication.run method to scan, configure, and run the web application.
The static main doesn't mean anything to an application server. Instead we add a SpringBootServletInitializer implementation that implements in turn the WebApplicationInitializer interface.
Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically -- as opposed to (or possibly in conjunction with) the traditional web.xml-based approach.
Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet 3.0 container. See its Javadoc for details on this bootstrapping mechanism.
The SpringServletContainerInitializer gets bootstrapped by the Servlet 3.0+ container and executes the WebApplicationInitializer.onStartup(ServletContext context) methods to configure the ServletContext.
We implement the SpringServletContainerInitializer to define the SpringApplication[s] to be run.
The application server can create a ServletContext on its own, it just can't configure the ServletContext on its own.
Why do you want access to the ServletContext? Spring will handle the configuration for you.

Set default application server Spring Boot

I have multiple application servers on my classpath, namely Netty via spring-boot-starter-webflux and Tomcat through another dependency chain. How can I determine which application server to use in Spring Boot?
Currently, Tomcat is being started instead Netty.
Important note: I can't exclude any of them, Tomcat is used by CXF, Netty is used by WebClient.
Just use proper spring-boot-starter-package
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html
In your case it will be probably spring-boot-starter-reactor-netty
Also it would be wise to exclude multiple JEE embedded containers and remove those you don't need.
You can specify the application is reactive directly in you configuration at startup something like this
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(final String[] args) {
final SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.setWebApplicationType(WebApplicationType.REACTIVE);
springApplication.run(args);
}
}

Convert a Spring MVC application to Spring Boot - BeanCurrentlyInCreationException issue

I have a Spring MVC application, using Hibernate for my entities persistence management. I am able to build, deploy and run it on some application server such as glashfish or tomcat, all is fine.
Now, I want to convert it into a Spring Boot application. I added the following class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(Application.class, args);
}
}
and added the spring-boot, spring-boot-autoconfigure, and spring-boot-starter-tomcat dependencies to my pom.
Alas, when trying to run the application, I get the following error:
BeanCurrentlyInCreationException: Error creating bean with name
'MyClassDAO': Bean with name 'MyClassDAO' has been injected into
other beans [MyOtherClassDAO] in its raw version as part of a circular
reference, but has eventually been wrapped. This means that said other
beans do not use the final version of the bean. This is often the result
of over-eager type matching - consider using 'getBeanNamesOfType' with
the 'allowEagerInit' flag turned off, for example.
I don't know how to use 'getBeanNamesOfType' and set the allowEagerInit off (I do not use XML configuration). Of course, I'm not sure this would solve my issue anyway.
Any ideas on how I can fix this?
If it's really some intilization issue then i believe the you must be having your class in other package and due to some cache issues it doesn't include those classes in class path to scan in container so to do this manually you can put a annotation just below #springbootapllication is #EnableComponentScan("enter the package name of the class which is not initializing") also on that dao class put #service or #component annotation to let the application include then in container

Spring boot rest tomcat deployment error

I have created a rest api using Spring rest and Spring boot. When I am trying to deploy it on tomcat on linux server, I get following error:
rror during ServletContainerInitializer processing
javax.servlet.ServletException: Failed to instantiate WebApplicationInitializer class at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:160
Caused by: java.lang.ClassNotFoundException: org.glassfish.jersey.server.ResourceConfig
I am following exact Spring boot instruction for tomcat. My question is that I am not using anything related to Jersey for my application (apis) then why it is looking for Jersey related code, and how I can fix it.
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
Contoller code:
#RestController
#RequestMapping("/rest/cmscontent")
public class BatchController {
If you add spring-boot-starter-web into your POM file as dependency,
it will include embedded web container (Tomcat by default) automatically.
Therefore, just execute JAR directly without deploying it to any web container.

cannot resolve reference to bean 'jmsconnectionfactory' when using spring boot + spring integration

I had a problem i'm using hornetq using spring boot and had to create a jmschannel in spring configuration using spring integration <int-jms:channel id="jmsChannel" queue-name="${spring.hornetq.embedded.queues}" connection-factory="jmsConnectionFactory">
<int-jms:interceptors><int:wire-tap channel="logger"/></int-jms:interceptors>
</int-jms:channel>
This is working fine in local when loading with undertow, when deployed the war to Jboss it is throwing up saying bean named jmsConnectionFactory not found, any help is greatly appreiciated
Looks like there is nothing to do with the Spring Integration, but only Spring Boot stuff, which is called deployable war:
The first step in producing a deployable war file is to provide a SpringBootServletInitializer subclass and override its configure method. This makes use of Spring Framework’s Servlet 3.0 support and allows you to configure your application when it’s launched by the servlet container. Typically, you update your application’s main class to extend SpringBootServletInitializer:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}

Resources