Apache Axis2 Spring Boot Starter
axis2-spring-boot-starter reduces Axis2 + Spring Boot integration from a multi-day configuration project to a single Maven dependency. It handles servlet registration, repository configuration, and OpenAPI/MCP endpoint activation with sensible defaults — for both SOAP and JSON-RPC services.
What Axis2 brings to Spring Boot
- Large JSON streaming (10MB–1GB+) — the streaming JSON formatter flushes HTTP/2 DATA frames every 64KB, keeping server memory flat regardless of response size. No reactive stack required.
- Native HTTP/2 with backpressure — the H2TransportSender provides connection multiplexing, flow control, and ALPN negotiation as a drop-in transport layer. See also the HTTP/2 overview.
- AI-ready services (MCP) — Axis2 auto-generates an MCP tool catalog from deployed services. AI assistants discover and call your services as tools without hand-authored definitions. See MCP examples for live demos.
- Response field selection — the
?fields=query parameter lets clients request only the fields they need, reducing payload size and AI token consumption at the serialization layer with zero application code. - OpenAPI schemas from Hibernate mappings — the
JPA/Hibernate schema generator
produces read and write JSON Schemas directly from
@Entityannotations or.hbm.xmlfiles, including a batch CLI tool for large codebases. No hand-authored API contracts — the schema stays in sync with the database model by construction. - Built-in pagination — the
PaginatedResponsewrapper provides offset/limit pagination with server-enforced safety limits,totalCountfor page controls, andhasMorefor infinite scroll — mapping directly to JPA/Hibernate'ssetFirstResult/setMaxResults. - SOAP + JSON from the same services — serve both SOAP/XML and JSON-RPC from the same Spring beans, selected by configuration. Useful for enterprises maintaining both legacy and modern clients.
This starter supports both WAR deployment to an external container
(Tomcat 11, WildFly 32/39) and embedded Tomcat for local development.
For embedded mode, set axis2.repo in application.properties
to the exploded WAR directory from your build.
See Deployment Model for details.
- 0. Deployment Model (WAR + Embedded)
- 1. Quick Start
- 2. How AxisServlet Works (SOAP vs JSON)
- 3. Configuration Properties
- 4. SOAP Mode vs JSON Mode
- 5. What Gets Autoconfigured
- 6. What Stays in Your Application
- 7. OpenAPI and MCP Support
- 8. Migration from Manual Configuration
- 9. Container Support
- 10. HTTP/2 and Streaming
0. Deployment Model
Axis2 supports two Spring Boot deployment modes:
| Mode | How | Use Case |
|---|---|---|
| External container (WAR) | Package as WAR, deploy to Tomcat 11 or WildFly 32+ | Production — the recommended deployment model |
| Embedded Tomcat | mvn spring-boot:run -Pembedded |
Local development and testing |
External container (production)
For production, deploy as a WAR to an external servlet container.
Your Spring Boot application must extend
SpringBootServletInitializer and be packaged as a WAR.
External containers provide operational advantages for long-running
Axis2 deployments:
- Container-managed TLS, thread pools, and connection pools
- Hot-redeploy via exploded WAR without JVM restart
- Central certificate management (Tomcat's
server.xml, WildFly's Elytron) - HTTP/2 with ALPN (via container connector, not application code)
Embedded Tomcat (development)
For local development and testing, the sample application supports
Spring Boot's embedded Tomcat via a Maven profile. Axis2's
WarBasedAxisConfigurator requires a filesystem layout
(WEB-INF/conf/axis2.xml, WEB-INF/services/*.aar,
WEB-INF/modules/*.mar) that embedded Tomcat does not
provide from its temp docbase. The -Daxis2.repo system
property tells the configurator where to find the exploded WAR
from the build:
# Build first (creates the exploded WAR with services and modules) mvn clean install -DskipTests # Run with embedded Tomcat mvn spring-boot:run -Pembedded \ -Dspring-boot.run.arguments="--server.port=9090" \ -Dspring-boot.run.jvmArguments="-Daxis2.repo=target/deploy/axis2-json-api/WEB-INF"
The sample application requires authentication. Log in first to obtain a token, then pass it as a Bearer token on subsequent requests:
# 1. Log in (sample credentials)
TOKEN=$(curl -s http://localhost:9090/services/loginService \
-H 'Content-Type: application/json' \
-d '{"doLogin":[{"arg0":{"email":"java-dev@axis.apache.org","credentials":"userguide"}}]}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['response']['token'])")
# 2. Call a service with the token
curl -s http://localhost:9090/services/FinancialBenchmarkService \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $TOKEN" \
-d '{"portfolioVariance":[{"arg0":{"weights":[0.5,0.5],"covarianceMatrix":[[0.04,0.006],[0.006,0.09]]}}]}'
OpenAPI and MCP endpoints do not require authentication:
curl -s http://localhost:9090/openapi.json curl -s http://localhost:9090/openapi-mcp.json
For production, external containers remain the recommended deployment:
- Container-managed thread pools, connection pools, and monitoring (Actuator/Micrometer)
- Hot-redeploy via exploded WAR without JVM restart
- Central TLS/certificate management (Tomcat's
server.xml, WildFly's Elytron) - Established operational tooling (WildFly CLI, Tomcat Manager, deployment scanners)
Which external containers?
| Container | JDK | Tested |
|---|---|---|
| Apache Tomcat 11 | OpenJDK 17, 21, 25 | Yes (21/25 live-tested; 17 is the minimum supported by Tomcat 11 and Spring Boot 3.x) |
| WildFly 32 | OpenJDK 17, 21 | Yes (production-tested on WildFly 32 + OpenJDK 17) |
| WildFly 39 | OpenJDK 21, 25 | Yes (live-tested with OpenJDK 25) |
Minimum JDK version: OpenJDK 17. Axis2 core and the starter
compile and pass CI tests with -Dmaven.compiler.release=17.
Spring Boot 3.x and Tomcat 11 both require Java 17 as a minimum. The sample
applications target Java 21 source level but Axis2 itself imposes no version
above 17.
Other Jakarta EE 9+ containers (WebSphere Liberty, Payara) should work but are not tested.
Embedded mode limitations
Embedded Tomcat requires a pre-built exploded WAR on the filesystem
(pointed to by axis2.repo). This means you must run
mvn install before mvn spring-boot:run so
that the .aar service archives and axis2.xml
are staged in the build output directory. Changes to service metadata
(operations, message receivers, MCP descriptions) require a rebuild.
Note that the service code itself is a Spring
@Component bean on the classpath — the .aar
file contains only metadata (services.xml) that tells
Axis2 which Spring bean to call, which operations to expose, and
which message receivers to use. The SpringBeanName
parameter in services.xml bridges Axis2 service
dispatch to Spring's application context. A future improvement
could scan for services.xml resources on the classpath,
eliminating the filesystem requirement entirely.
1. Quick Start
Add the starter to your pom.xml:
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!-- Optional: OpenAPI/MCP endpoints -->
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-openapi</artifactId>
<version>2.0.1</version>
</dependency>
This single dependency replaces ~30 individual Axis2 dependencies
(axis2-kernel, axis2-transport-http,
axis2-json, axis2-spring, axis2-jaxws,
etc.) and eliminates the need for a hand-coded Axis2WebAppInitializer
or OpenApiServlet class.
The starter auto-registers AxisServlet at /services/*.
If you also add the optional axis2-openapi dependency (shown above),
the starter additionally registers endpoints for OpenAPI spec generation
(/openapi.json), Swagger UI (/swagger-ui), and MCP
tool discovery (/openapi-mcp.json). See
Section 7 for details.
2. How AxisServlet Works (SOAP vs JSON)
org.apache.axis2.transport.http.AxisServlet is the single entry
point for all Axis2 service calls — SOAP and JSON-RPC alike.
The servlet itself is protocol-agnostic. It does not know or care whether the
incoming request is SOAP 1.1, SOAP 1.2, or JSON-RPC.
The protocol handling is determined entirely by axis2.xml:
| Component | SOAP | JSON-RPC |
|---|---|---|
| Message Receivers Parse the incoming payload and invoke the service method |
RawXMLINOutMessageReceiverRawXMLINOnlyMessageReceiver(read SOAP XML envelopes) |
JsonRpcMessageReceiverJsonInOnlyRPCMessageReceiver(read JSON-RPC {"op":[{"arg0":{}}]} envelope) |
| Dispatchers Route the request to the correct service and operation |
Multi-handler chain:SOAPActionBasedDispatcherRequestURIBasedDispatcherSOAPMessageBodyBasedDispatcherHTTPLocationBasedDispatcher(routes by SOAPAction header, WS-Addressing, message body) |
Single handler:JSONBasedDefaultDispatcher(routes by URL path only) |
enableJSONOnly |
false (the default since Axis2 1.0, 2006) |
true (skips SOAP envelope processing) |
SOAP and JSON cannot coexist in a single deployment. The message receivers and dispatchers are incompatible — a SOAP receiver cannot parse JSON, and the JSON dispatcher cannot route by SOAPAction. This is not a starter limitation; it is how Axis2's processing pipeline works.
AxisServlet Initialization Sequence
When AxisServlet starts (init()), it:
- Creates a
WarBasedAxisConfigurator - Locates the repository (
WEB-INF/) using, in order:axis2.repository.pathservlet init-parameter (if set explicitly)axis2.repository.urlservlet init-parameter (if set explicitly)ServletContext.getRealPath("/WEB-INF")(automatic fallback)
- Reads
WEB-INF/conf/axis2.xmlto configure the engine - Scans
WEB-INF/services/*.aarto deploy services - Scans
WEB-INF/modules/*.marto load modules (e.g., OpenAPI) - Stores the
ConfigurationContextin theServletContext— this is how other servlets (OpenAPI, MCP) access the Axis2 engine
The starter sets axis2.repository.path eagerly at startup as a
workaround for WildFly VFS timing issues where getRealPath() can
return null during lazy servlet initialization.
3. Configuration Properties
| Property | Default | Description |
|---|---|---|
axis2.enabled |
true |
Set to false to disable Axis2 entirely (e.g., for server roles that don't serve web services) |
axis2.mode |
json |
soap or json — selects the built-in axis2.xml template (see Section 4) |
axis2.services-path |
/services |
URL path for AxisServlet. Servlet is registered at {services-path}/* |
axis2.configuration-file |
(empty) | Path to a custom axis2.xml. Overrides axis2.mode. Supports classpath: prefix |
axis2.openapi.enabled |
true |
Register OpenAPI/MCP servlet (requires axis2-openapi on classpath) |
axis2.openapi.paths |
/openapi.json, /openapi.yaml, /swagger-ui, /openapi-mcp.json |
URL paths for OpenAPI endpoints |
4. SOAP Mode vs JSON Mode
The starter ships two built-in axis2.xml templates, selected by
axis2.mode:
JSON mode (axis2.mode=json, the default)
# application.properties axis2.mode=json
Uses JsonRpcMessageReceiver, JSONBasedDefaultDispatcher,
and enableJSONOnly=true. Choose this for new services, MCP/AI integration,
and REST/OpenAPI consumers.
SOAP mode (axis2.mode=soap)
# application.properties axis2.mode=soap
Uses RawXMLINOutMessageReceiver, the full SOAP dispatcher stack,
and enableJSONOnly=false. Choose this for WSDL-first services,
WS-Security, WS-Addressing, or interop with .NET/PHP SOAP clients. This is the
classic Axis2 configuration that has been in use since version 1.0 (2006).
Custom axis2.xml
# application.properties axis2.configuration-file=classpath:my-axis2.xml
Overrides both built-in templates. Use this when you need custom phases, modules, transport configurations, or any axis2.xml settings not covered by the built-in templates.
The starter only stages axis2.xml if WEB-INF/conf/axis2.xml
does not already exist. If your Maven build pre-stages it (e.g., via
maven-antrun-plugin), the starter will not overwrite it.
5. What Gets Autoconfigured
| Component | What it replaces | Condition |
|---|---|---|
AxisServlet registration at /services/* |
Hand-coded Axis2WebAppInitializer |
Always (when axis2.enabled=true) |
axis2.xml staging (SOAP or JSON template) |
axis2.xml copy step in maven-antrun-plugin |
When WEB-INF/conf/axis2.xml does not already exist |
OpenAPI/MCP servlet at /openapi.json, /swagger-ui, /openapi-mcp.json |
Hand-coded OpenApiServlet class |
When axis2-openapi is on classpath and axis2.openapi.enabled=true |
6. What Stays in Your Application
The starter deliberately does not autoconfigure:
- Security — JWT authentication, mTLS, SAML, CSRF guard filter
chains are application-specific. The starter does not provide any
SecurityFilterChainbeans. - Service definitions —
services.xmlfiles inside.aararchives define operation names, Spring bean names, per-operation message receivers. These are service-specific. .aarfile creation — pre-built.aarfiles must be staged inWEB-INF/services/by the Maven build (maven-antrun-pluginoraxis2-aar-maven-plugin)..marmodule staging — the OpenAPI module JAR must be renamed to.marand placed inWEB-INF/modules/by the Maven build.- Container-specific descriptors — WildFly's
jboss-deployment-structure.xml,jboss-web.xml,beans.xml. @SpringBootApplicationclass — the consuming app still needs its main class extendingSpringBootServletInitializer.
7. OpenAPI and MCP Support
axis2-openapi is a separate Axis2 module (Maven artifact:
org.apache.axis2:axis2-openapi) that auto-generates an
OpenAPI
3.0.1 specification and
MCP
(Model Context Protocol) tool catalog from your deployed Axis2 services.
OpenAPI is a standard format for describing REST APIs — tools like
Swagger UI use it to
generate interactive documentation. MCP is a protocol that lets AI
assistants (Claude, ChatGPT, etc.) discover and call your services
as tools.
The module auto-generates both from your deployed Axis2 services.
It reads each service's services.xml (inside the .aar
file) at runtime — specifically the operation names, message receiver types,
and MCP metadata parameters — and produces the specification automatically.
No annotations on your service code are needed.
How it works with the starter: The starter detects
axis2-openapi on the classpath via Spring Boot's
@ConditionalOnClass(OpenApiModule.class) and automatically
registers a servlet that delegates to Axis2's
SwaggerUIHandler.
No additional code is needed in your application.
To enable it, add the dependency to your pom.xml:
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-openapi</artifactId>
<version>2.0.1</version>
</dependency>
Your Maven build must also copy the axis2-openapi JAR as a
.mar (Module Archive) into WEB-INF/modules/ so the
Axis2 engine can load it:
<!-- In maven-antrun-plugin, prepare-package phase -->
<copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/${axis2.version}/axis2-openapi-${axis2.version}.jar"
tofile="${project.build.directory}/${project.build.finalName}/WEB-INF/modules/openapi-${axis2.version}.mar"
overwrite="true"/>
Once deployed, the following endpoints are available (no auth required):
GET /openapi.json— OpenAPI 3.0.1 specification (JSON)GET /openapi.yaml— same in YAML formatGET /swagger-ui— interactive Swagger UIGET /openapi-mcp.json— MCP tool catalog for AI assistants (includes operation names, input schemas, and payload templates)
The MCP catalog is generated from services.xml parameters
like mcpDescription and mcpInputSchema.
See the JSON-RPC MCP Integration Guide
for the full catalog format and how AI assistants discover and call Axis2
services.
8. Migration from Manual Configuration
If you have an existing Axis2 + Spring Boot project with manual servlet registration, follow these steps:
- Replace dependencies: Remove the ~30 individual Axis2
dependencies and add the single
axis2-spring-boot-starterdependency. - Delete
Axis2WebAppInitializer(or your equivalentServletContextInitializerthat registersAxisServlet). The starter handles this. - Delete
OpenApiServlet.javaif you have one. The starter provides it whenaxis2-openapiis on the classpath. - Set
axis2.modeinapplication.properties:jsonfor JSON-RPC services,soapfor SOAP services. - Keep your Maven build steps that create
.aarfiles and copy.marmodules — the starter does not replace these yet. - Keep your security configuration — the starter does not touch Spring Security.
For working reference implementations, see:
modules/samples/userguide/src/userguide/springbootdemo-tomcat11/README.mdmodules/samples/userguide/src/userguide/springbootdemo-wildfly/README.md
9. Tested Configurations
JSON-RPC / MCP (axis2.mode=json)
The starter was tested with the springbootdemo-tomcat11 sample
application, replacing ~30 individual Axis2 dependencies with the single
axis2-spring-boot-starter dependency and removing the hand-coded
Axis2WebAppInitializer. All endpoints confirmed working over
HTTPS/HTTP2 on Tomcat 11 with OpenJDK 25:
| Endpoint | Result |
|---|---|
GET /openapi.json |
Pass — OpenAPI 3.0.1 spec returned |
GET /openapi.yaml |
Pass |
GET /openapi-mcp.json |
Pass — MCP tool catalog with full inputSchema |
GET /swagger-ui |
Pass — HTTP 200 |
POST loginService/doLogin |
Pass — JWT token returned |
POST FinancialBenchmarkService/portfolioVariance |
Pass — SUCCESS, variance=0.03168 |
POST FinancialBenchmarkService/monteCarlo |
Pass — SUCCESS, 10K simulations |
POST FinancialBenchmarkService/scenarioAnalysis |
Pass — SUCCESS |
SOAP (axis2.mode=soap)
The SOAP axis2.xml template was validated by unit tests confirming correct
message receivers (RawXMLINOutMessageReceiver,
RawXMLINOnlyMessageReceiver), the full SOAP dispatcher stack
(SOAPActionBasedDispatcher, RequestURIBasedDispatcher,
SOAPMessageBodyBasedDispatcher, HTTPLocationBasedDispatcher),
and enableJSONOnly=false. The SOAP template is based on the
Axis2 configuration that has been in production since version 1.0 (2006) and is
identical in structure to the configuration used by the legacy userguide
example1 Echo service (MyService.echo() with
RawXMLINOutMessageReceiver).
Unit test suite
The starter includes 9 unit tests covering:
- Both axis2.xml templates exist on the classpath
- JSON template correctness (enableJSONOnly=true, JSONBasedDefaultDispatcher, no SOAP receivers)
- SOAP template correctness (enableJSONOnly=false, RawXMLINOut receivers, full SOAP dispatcher stack, no JSON dispatcher)
- Default property values
- AutoConfiguration.imports contains all required classes
Container matrix
See Section 0 for the full container compatibility matrix covering WAR deployment (Tomcat 11, WildFly 32/39) and embedded Tomcat for local development.
10. HTTP/2 and Streaming
Axis2/Java has built-in HTTP/2 support at the serialization layer, not just the transport layer. Unlike most frameworks where the servlet container handles HTTP/2 transparently and the serialization is unaware of the protocol, Axis2 integrates HTTP/2 awareness into the JSON message formatter pipeline:
- Dedicated HTTP/2 transport module
(
modules/transport-h2) — ALPN negotiation, per-stream flow control, adaptive buffering, compression optimization, and HTTP/1.1 fallback. See HTTP/2 Integration Guide. - Streaming JSON formatters — flush every 64 KB during serialization, converting a single buffered response into a stream of HTTP/2 DATA frames. A 50MB response arrives at the client as ~780 incremental frames, with the first frame arriving within milliseconds. See Streaming JSON Formatter.
- Field selection — callers add
?fields=status,resultto any service URL and the response includes only those fields, filtered during serialization with zero overhead when not used. See Field Selection. - C parity — the same streaming architecture exists
in Axis2/C via
Apache httpd
mod_h2. Both implementations use the same 64 KB flush interval, producing identical HTTP/2 DATA frame patterns.
For a detailed comparison of Axis2's HTTP/2 architecture with Spring MVC, JAX-RS, gRPC, and other frameworks, see the framework comparison in the HTTP/2 Integration Guide.
Apache Axis2
