How do you wire MessageDispatcherServlet with ServletRegistrationBean in a Spring Boot app, and why can't you reuse the default DispatcherServlet?
answer
- MessageDispatcherServlet = SOAP front controller
- ServletRegistrationBean maps it to /ws/*
- setApplicationContext(ctx) to reuse Boot context
- setTransformWsdlLocations(true) rewrites soap:address
- payload-root dispatch, not URL/verb
basics
~10 sRegister MessageDispatcherServlet as a separate servlet via a ServletRegistrationBean mapped to something like /ws/*. It's Spring-WS's own front controller for SOAP; the regular DispatcherServlet handles MVC/REST, not SOAP message dispatching or WSDL serving.
solid answer
~40 sSpring-WS ships its own front controller, MessageDispatcherServlet, which knows how to route incoming SOAP messages to @Endpoint beans and how to serve generated WSDLs. In Spring Boot you expose it with a ServletRegistrationBean: construct MessageDispatcherServlet, call setApplicationContext(context) so it shares the Boot context, enable setTransformWsdlLocations(true) so advertised location URIs get rewritten to the caller's host, and register it at a URL mapping like /ws/*. That mapping is the SOAP boundary — every request under it goes through message dispatching. You keep it separate from the auto-configured DispatcherServlet (which owns /) because DispatcherServlet does HTTP-verb/handler-based MVC dispatch, whereas MessageDispatcherServlet does SOAP-payload-based dispatch (PayloadRootAnnotationMethodEndpointMapping etc.) and hosts the WsdlDefinition beans. Two servlets, two mappings, one ApplicationContext.
code
java · 13 lines@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(
ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext); // reuse Boot context
servlet.setTransformWsdlLocations(true); // rewrite soap:address
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
}go deeper
Know MessageDispatcherServlet is registered via ServletRegistrationBean at a path like /ws/*.
Explain setApplicationContext and setTransformWsdlLocations and why a second servlet is needed.
Contrast payload-root dispatch vs MVC handler dispatch and discuss the child-context pitfall.
Address security boundaries for /ws/*, proxy/location rewriting strategy, and coexistence with MVC in one context.
## Two different front controllers Spring MVC's front controller is **`DispatcherServlet`** — it dispatches HTTP requests to `@Controller`/`@RestController` handlers based on URL + HTTP method. SOAP is different: the *operation* is identified by the **payload** (the root element of the SOAP body), not by URL/verb. So Spring-WS provides **`org.springframework.ws.transport.http.MessageDispatcherServlet`**, a subclass that performs **message dispatching**: it consults endpoint mappings like `PayloadRootAnnotationMethodEndpointMapping` (match by request payload root element) or `SoapActionAnnotationMethodEndpointMapping` to find the right `@Endpoint` method. It *also* knows how to locate `WsdlDefinition` beans (your `DefaultWsdl11Definition`) and serve them as `/{beanName}.wsdl`. You cannot reuse the default `DispatcherServlet` for this: it has no concept of payload-root dispatch and does not serve `WsdlDefinition` beans. They coexist — MVC on `/`, SOAP on `/ws/*`. ## Wiring with ServletRegistrationBean In a Spring Boot app you register an extra servlet by declaring a `ServletRegistrationBean<MessageDispatcherServlet>`: ```java @Bean public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext ctx) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(ctx); servlet.setTransformWsdlLocations(true); return new ServletRegistrationBean<>(servlet, "/ws/*"); } ``` Key points: - **`setApplicationContext(ctx)`** — critical. `MessageDispatcherServlet` normally creates its *own* child WebApplicationContext from an XML/config file. In Boot you want it to reuse the existing Boot context (where your `@Endpoint`, `XsdSchema`, and `DefaultWsdl11Definition` beans live), so you inject the current `ApplicationContext` and set it explicitly. Forgetting this leads to it not finding your endpoints/WSDL beans. - **URL mapping `/ws/*`** — the second constructor arg. This is the SOAP boundary. `/ws/countries.wsdl` (GET) returns the WSDL; POSTs of SOAP messages under `/ws/*` are dispatched to endpoints. - **`setTransformWsdlLocations(true)`** — rewrites the `soap:address location` in the generated WSDL to match the host/port/context the client used, instead of the static `locationUri`. Essential behind proxies/load balancers or when the app doesn't know its public URL. - **`@EnableWs`** — put on a `@Configuration` class (often extending `WsConfigurerAdapter`); it imports the Spring-WS infrastructure (endpoint mappings, adapters, marshalling support). ## Gotchas - **Mapping overlap**: don't map the SOAP servlet to `/` — it would shadow MVC. Give it a dedicated prefix. - **Load order / bean name**: the WSDL URL path segment is the `DefaultWsdl11Definition` *bean name*, resolved relative to the servlet mapping. Bean `countries` at `/ws/*` -> `/ws/countries.wsdl`. - **Child-context surprise**: if you forget `setApplicationContext`, `MessageDispatcherServlet` looks for a `*-servlet.xml` and fails to see Boot beans. - **Security**: the `/ws/*` path is separate from your MVC security; configure Spring Security matchers for it explicitly. ## When to use Any Spring Boot SOAP service. Boot has no starter that auto-registers `MessageDispatcherServlet` for you beyond `spring-boot-starter-web-services` bringing the dependency; you still supply this `@Bean`.
- Why must you call setApplicationContext on the MessageDispatcherServlet in Spring Boot?By default it spins up its own child WebApplicationContext from an XML config and wouldn't see your Boot-managed @Endpoint/XsdSchema/DefaultWsdl11Definition beans. Injecting the current ApplicationContext makes it reuse them.
- What does setTransformWsdlLocations(true) do?It rewrites the soap:address location URI in the generated WSDL to reflect the actual request host/port/context path, so clients behind proxies get a reachable endpoint instead of the static locationUri.
- How does MessageDispatcherServlet decide which endpoint handles a request?By the SOAP payload root element (PayloadRootAnnotationMethodEndpointMapping) or SOAPAction, not by URL/HTTP verb like DispatcherServlet.
saying these in an interview costs you the question
- Claiming the regular DispatcherServlet can serve WSDL/SOAP
- Mapping the SOAP servlet to '/' and shadowing MVC
- Omitting setApplicationContext so endpoints aren't found
- Thinking SOAP operations are chosen by URL path/HTTP method