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);
}
}
Related
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.
I've got a Spring WebFlux application running successfully as a standalone spring boot application.
I am attempting to run the same application in a Tomcat container, and following the documentation, I've created a class that extends AbstractReactiveWebInitializer. The class requires that I implement a method getConfigClasses that would return classes normally annotated with #Configuration. If the working spring boot app started with a class called ApplicationInitializer, then the resulting implementations would look like this:
#SpringBootApplication(scanBasePackages = "my.pkg")
#EnableDiscoveryClient
#EnableCaching
public class ApplicationInitializer {
public static void main(String... args) {
SpringApplication.run(ApplicationInitializer.class, args);
}
}
and
public class ServletInitializer extends AbstractReactiveWebInitializer {
#Override
protected Class<?>[] getConfigClasses() {
return new Class[] {ApplicationInitializer.class};
}
}
When deployed, the only thing that starts is ApplicationInitializer, none of the autoconfigured Spring Boot classes (Cloud Config, DataSource, etc) ever kick off.
The documenation states this is the class I need to implement, I just expected the remainder of the spring environment to "just work".
How should I be using this class to deploy a Reactive WebFlux Spring Boot application to a Tomcat container ?
Edit:
After some additional research, I've narrowed it down to likely just Cloud Config. During bean post processing on startup, the ConfigurationPropertiesBindingPostProcessor should be enriched with additional property sources (from cloud config), but it appears to be the default Spring properties instead, with no additional sources.
The misisng properties is causing downstream beans to fail.
Spring Boot does not support WAR packaging for Spring WebFlux applications.
The documentation you're referring to is the Spring Framework doc; Spring Framework does support that use case, but without Spring Boot.
you can extend SpringBootServletInitializer, add add reactive servlet on onStartup method
I have a Spring Boot application that is getting deployed as a WAR to a Tomcat server. There is already a currently deployed Spring Boot application on Tomcat server that has an application.properties file on classpath that is overriding the one bundled in the WAR. I need to do the same thing for my application, but I can't use the name application.properties as it is already taken, and my application is trying to use the application.properties on the classpath from Tomcat, which is intended for the other Spring Boot application.
Is there a way I can tell Spring Boot to look for a properties file on the classpath called myapp.properties or something along those lines?
I tried doing the following, but it doesn't seem to work when being deployed as a WAR.
#SpringBootApplication
public class ParameterManagerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ParameterManagerApplication.class)
.properties("spring.config.name:parameter-portal")
.build()
.run(args);
}
}
By default, Spring Boot looks for the application.properties file in these locations.
/config subdir of the working directory
The working directory
config package in the classpath
classpath root
So, the following worked for us when we placed myserver.properties under any of these locations.
public static void main(String[] args){
System.setProperty("spring.config.name","myserver");
SpringApplication.run(Application.class,args);
}
Otherwise, You can try setting the spring.config.location as below.
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:application,myserver",
"spring.config.location:classpath:/external/myproperties/")
.build().run(args);
We can also optionally define a custom source where we’re storing these properties, else the default location (classpath:application.properties) is looked up. So we now add the above annotations to the existing properties class:
#Configuration
#PropertySource("classpath:configprops.properties")
#ConfigurationProperties(prefix = "dev")
public class ConfigProperties {
// previous code
}
Now any properties defined in the property file that has the prefix dev and the same name as one of the properties are automatically assigned to this object.
#Simple properties
dev.host=mailer#mail.com
dev.port=9000
Check this
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.
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);
}