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
Related
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);
}
}
I got confused trying to integrate Actuator to a project using Spring Boot 1.5.11's static resource serving feature:
Spring Boot Actuator does not work without #EnableWebMvc, HTTP 406 is returned because the right Http media converter is not installed.
But if I add #EnableWebMvc, it turns off serving resources from the static folder and other Spring Boot features.
Is there a way to initialize Actuator without losing Boot features?
Found a bug in Spring Boot 2.0, it seems it was there in Boot 1.5 as well. Workaround: setting favorPathExtension to false turns off buggy code in ServletPathExtensionContentNegotiationStrategy and Actuator endpoints start working.
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
In my spring boot application (powered by spring-boot-starter-jersey):
I can easily make a resource config (jersey way but not jaxrs way) like this:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends ResourceConfig {
And I just want to try with javax.ws.rs.core.Applicaiton:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends javax.ws.rs.core.Applicaiton{
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(SampleResource.class);
return classes;
}
But no lucky, it does not work.
Did I miss something?
Thanks
Leon
It won't work as the Spring Boot auto-configuration is made specifically to look for a bean of type ResourceConfig, not Application. If you want to use Application, you can't use the auto-configuration. You'll need to just create the JAX-RS servlet yourself and register it with a Spring Boot ServletRegistratiobBean, similar to what you'll see in the source code I linked to.
I want to use Spring boot with JAX-RS (Jersey Implementation). If we were not using Spring Boot, we could use the following code to register all the Rest service classes
#ApplicationPath("/myrest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorld.class);
return s;
}
}
This works fine in a Servlet 3.0 supported container.
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
Because Spring Boot uses the ResourceConfig type as the as a service that it injects into its auto configurer, namely the JerseyAutoConfiguration. If you look at the source code, you will see
#Autowired
private ResourceConfig config;
From there, Sprig Boot configures the app with that instance. If a ResourceConfig bean is not available in the Spring context, then not auto-configuration happens.
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);
}