| <!DOCTYPE html> |
| |
| |
| <!-- |
| | Generated by Apache Maven Doxia Site Renderer 2.0.0 from src/site/xdoc/docs/http2-java-client.xml at 2026-05-18 |
| | Rendered using Apache Maven Fluido Skin 2.0.0-M11 |
| --> |
| <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0" /> |
| <title>HTTP/2 Java Client — Sample Code – Apache Axis2</title> |
| <link rel="stylesheet" href="../css/apache-maven-fluido-2.0.0-M11.min.css" /> |
| <link rel="stylesheet" href="../css/site.css" /> |
| <link rel="stylesheet" href="../css/print.css" media="print" /> |
| <script src="../js/apache-maven-fluido-2.0.0-M11.min.js"></script> |
| </head> |
| <body> |
| <div class="container-fluid container-fluid-top"> |
| <header> |
| <div id="banner"> |
| <div class="pull-left"><div id="bannerLeft"><h1><a href="https://www.apache.org/"><img class="class java.lang.Object" src="https://www.apache.org/images/asf_logo_wide.png" /> Apache Axis2</a></h1></div></div> |
| <div class="pull-right"><div id="bannerRight"><h1><a href="https://axis.apache.org/axis2/java/core/"><img class="class java.lang.Object" src="https://axis.apache.org/axis2/java/core/images/axis.jpg" /></a></h1></div></div> |
| <div class="clear"><hr/></div> |
| </div> |
| |
| <div id="breadcrumbs"> |
| <ul class="breadcrumb"> |
| <li id="publishDate">Last Published: 2026-05-17<span class="divider">|</span> |
| </li> |
| <li id="projectVersion">Version: 2.0.1<span class="divider">|</span></li> |
| <li><a href="https://www.apache.org" class="externalLink">Apache</a><span class="divider">/</span></li> |
| <li><a href="../index.html">Axis2/Java</a><span class="divider">/</span></li> |
| <li class="active">HTTP/2 Java Client — Sample Code</li> |
| </ul> |
| </div> |
| </header> |
| <div class="row-fluid"> |
| <header id="leftColumn" class="span2"> |
| <nav class="well sidebar-nav"> |
| <ul class="nav nav-list"> |
| <li class="nav-header">Axis2/Java</li> |
| <li><a href="../index.html">Home</a></li> |
| <li><a href="../download.html">Downloads</a></li> |
| <li><a href="javascript:void(0)"><span class="icon-chevron-down"></span>Release Notes</a> |
| <ul class="nav nav-list"> |
| <li><a href="../release-notes/1.6.1.html">1.6.1</a></li> |
| <li><a href="../release-notes/1.6.2.html">1.6.2</a></li> |
| <li><a href="../release-notes/1.6.3.html">1.6.3</a></li> |
| <li><a href="../release-notes/1.6.4.html">1.6.4</a></li> |
| <li><a href="../release-notes/1.7.0.html">1.7.0</a></li> |
| <li><a href="../release-notes/1.7.1.html">1.7.1</a></li> |
| <li><a href="../release-notes/1.7.2.html">1.7.2</a></li> |
| <li><a href="../release-notes/1.7.3.html">1.7.3</a></li> |
| <li><a href="../release-notes/1.7.4.html">1.7.4</a></li> |
| <li><a href="../release-notes/1.7.5.html">1.7.5</a></li> |
| <li><a href="../release-notes/1.7.6.html">1.7.6</a></li> |
| <li><a href="../release-notes/1.7.7.html">1.7.7</a></li> |
| <li><a href="../release-notes/1.7.8.html">1.7.8</a></li> |
| <li><a href="../release-notes/1.7.9.html">1.7.9</a></li> |
| <li><a href="../release-notes/1.8.0.html">1.8.0</a></li> |
| <li><a href="../release-notes/1.8.1.html">1.8.1</a></li> |
| <li><a href="../release-notes/1.8.2.html">1.8.2</a></li> |
| <li><a href="../release-notes/2.0.0.html">2.0.0</a></li> |
| <li><a href="../release-notes/2.0.1.html">2.0.1</a></li> |
| </ul></li> |
| <li><a href="../modules/index.html">Modules</a></li> |
| <li><a href="../tools/index.html">Tools</a></li> |
| <li class="nav-header">Documentation</li> |
| <li><a href="../docs/toc.html">Table of Contents</a></li> |
| <li><a href="../docs/installationguide.html">Installation Guide</a></li> |
| <li><a href="../docs/quickstartguide.html">QuickStart Guide</a></li> |
| <li><a href="../docs/userguide.html">User Guide</a></li> |
| <li><a href="../docs/jaxws-guide.html">JAXWS Guide</a></li> |
| <li><a href="../docs/pojoguide.html">POJO Guide</a></li> |
| <li><a href="../docs/spring.html">Spring Guide</a></li> |
| <li><a href="../docs/webadminguide.html">Web Administrator's Guide</a></li> |
| <li><a href="../docs/migration.html">Migration Guide (from Axis1)</a></li> |
| <li class="nav-header">Resources</li> |
| <li><a href="../faq.html">FAQ</a></li> |
| <li><a href="https://github.com/apache/axis-axis2-java-core" class="externalLink">Source Code</a></li> |
| <li class="nav-header">Get Involved</li> |
| <li><a href="../overview.html">Overview</a></li> |
| <li><a href="../mail-lists.html">Mailing Lists</a></li> |
| <li><a href="../release-process.html">Release Process</a></li> |
| <li><a href="../guidelines.html">Developer Guidelines</a></li> |
| <li><a href="../siteHowTo.html">Build the Site</a></li> |
| <li class="nav-header">Project Information</li> |
| <li><a href="https://github.com/apache/axis-axis2-java-core/graphs/contributors" class="externalLink">Contributors</a></li> |
| <li><a href="https://issues.apache.org/jira/projects/AXIS2/issues" class="externalLink">Issues</a></li> |
| <li class="nav-header">Apache</li> |
| <li><a href="https://www.apache.org/licenses/LICENSE-2.0.html" class="externalLink">License</a></li> |
| <li><a href="https://www.apache.org/foundation/sponsorship.html" class="externalLink">Sponsorship</a></li> |
| <li><a href="https://www.apache.org/foundation/thanks.html" class="externalLink">Thanks</a></li> |
| <li><a href="https://www.apache.org/security/" class="externalLink">Security</a></li> |
| </ul> |
| </nav> |
| <div class="well sidebar-nav"> |
| <div id="poweredBy"> |
| <div class="clear"></div> |
| <div class="clear"></div> |
| <a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a> |
| </div> |
| </div> |
| </header> |
| <main id="bodyColumn" class="span10"> |
| |
| |
| |
| <section><a id="HTTP.2F2_Java_Client_.E2.80.94_Sample_Code"></a> |
| <h1>HTTP/2 Java Client — Sample Code</h1> |
| |
| |
| <p><strong>What this is:</strong> A standalone sample client |
| (<code>Http2JsonClient</code>) that demonstrates how to call Axis2 |
| JSON-RPC services over HTTP/2 from plain Java using Apache HttpClient 5. |
| It is <em>not</em> part of the Axis2 framework — it is example code |
| in the userguide samples that you can copy and adapt for your own |
| project.</p> |
| |
| |
| <p><strong>Why it exists:</strong> Java's built-in |
| <code>HttpURLConnection</code> does not support HTTP/2. Apache |
| HttpClient 5's convenience classes (<code>SimpleHttpRequest</code> / |
| <code>SimpleHttpResponse</code>) support HTTP/2 but silently buffer |
| the entire response in memory, defeating the streaming benefit. |
| This sample shows the correct pattern — using |
| <code>AbstractBinResponseConsumer</code> with the async API — so |
| you don't have to rediscover it the hard way.</p> |
| |
| |
| <p>Two execution modes:</p> |
| |
| <ul> |
| |
| <li><strong>Buffered</strong> — returns the full response as a |
| <code>String</code>. Simple, suitable for responses that fit |
| in memory.</li> |
| |
| <li><strong>Streaming</strong> — writes response bytes to an |
| <code>OutputStream</code> in 64KB chunks as HTTP/2 DATA |
| frames arrive. Memory stays flat regardless of response size. |
| When paired with the |
| <a href="json-streaming-formatter.html">Streaming JSON |
| Formatter</a> (AXIS2-6103), data flows end-to-end in 64KB |
| chunks.</li> |
| </ul> |
| |
| </section> |
| |
| <section><a id="The_SimpleHttp.2A_Pitfall"></a> |
| <h1>The SimpleHttp* Pitfall</h1> |
| |
| |
| <p>Apache HttpClient 5 provides <code>SimpleHttpRequest</code> and |
| <code>SimpleHttpResponse</code> as convenience classes for async |
| requests. <strong>Do not use them for HTTP/2 workloads with large |
| responses.</strong> They appear to work, but they silently defeat |
| HTTP/2 streaming.</p> |
| |
| |
| <p><code>SimpleHttpResponse</code> is a buffering response object — |
| it accumulates the entire response body in memory before returning |
| it to the caller. For a 100MB response:</p> |
| |
| |
| <ul> |
| |
| <li><code>SimpleHttpResponse</code>: allocates 100MB+ of heap |
| (internal byte arrays, header maps, content type parsing) |
| before your code sees a single byte</li> |
| |
| <li><code>AbstractBinResponseConsumer</code>: your |
| <code>data(ByteBuffer)</code> callback fires for each 64KB |
| HTTP/2 DATA frame — memory stays flat at ~64KB working |
| set</li> |
| </ul> |
| |
| |
| <p>This is not obvious from the HttpClient 5 documentation, and |
| it is easy to write code that uses <code>SimpleHttpResponse</code>, |
| observes correct HTTP/2 ALPN negotiation in the logs, and concludes |
| that HTTP/2 streaming is working — when in fact the response is |
| fully buffered before your code runs. The sample client avoids this |
| by using <code>AbstractBinResponseConsumer</code> for all requests, |
| including the buffered convenience method.</p> |
| |
| </section> |
| |
| <section><a id="Dependencies"></a> |
| <h1>Dependencies</h1> |
| |
| |
| <p>Requires Java 11+ (ALPN built in) and Apache HttpClient 5.4+:</p> |
| |
| |
| <pre class="prettyprint"><code> |
| <!-- Maven --> |
| <dependency> |
| <groupId>org.apache.httpcomponents.client5</groupId> |
| <artifactId>httpclient5</artifactId> |
| <version>5.4.3</version> |
| </dependency> |
| <dependency> |
| <groupId>org.apache.httpcomponents.core5</groupId> |
| <artifactId>httpcore5-h2</artifactId> |
| <version>5.4.1</version> |
| </dependency> |
| </code></pre> |
| |
| |
| <p>These are the same dependencies used by Axis2's own |
| <code>H2TransportSender</code>. If you are already running Axis2 |
| with HTTP/2 transport, they are already on your classpath.</p> |
| |
| </section> |
| |
| <section><a id="Buffered_Execution"></a> |
| <h1>Buffered Execution</h1> |
| |
| |
| <p>POST JSON-RPC to any Axis2 service, get the response as a String:</p> |
| |
| |
| <pre class="prettyprint"><code> |
| String url = "https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService"; |
| String json = "{\"monteCarlo\":[{\"arg0\":{\"nSimulations\":100000,\"nPeriods\":252," |
| + "\"initialValue\":1000000,\"expectedReturn\":0.10,\"volatility\":0.223," |
| + "\"nPeriodsPerYear\":252,\"randomSeed\":42}}]}"; |
| |
| String response = Http2JsonClient.execute(url, json, 300); |
| System.out.println(response); |
| |
| Http2JsonClient.shutdown(); |
| </code></pre> |
| |
| |
| <p>The client negotiates HTTP/2 via ALPN on the TLS handshake. |
| Connections are pooled and multiplexed — multiple concurrent requests |
| share a single TCP connection.</p> |
| |
| </section> |
| |
| <section><a id="Streaming_Execution"></a> |
| <h1>Streaming Execution</h1> |
| |
| |
| <p>For large responses (10MB+), stream to a file or parser instead |
| of buffering in heap:</p> |
| |
| |
| <pre class="prettyprint"><code> |
| String url = "https://localhost:8443/axis2-json-api/services/BigDataH2Service"; |
| String json = "{\"generate\":[{\"arg0\":{\"datasetSize\":52428800}}]}"; |
| |
| try (FileOutputStream fos = new FileOutputStream("/tmp/result.json")) { |
| int status = Http2JsonClient.executeStreaming(url, json, 300, fos); |
| System.out.println("HTTP " + status); |
| } |
| |
| Http2JsonClient.shutdown(); |
| </code></pre> |
| |
| |
| <p>Each HTTP/2 DATA frame triggers a callback that writes directly |
| to your <code>OutputStream</code>. The <code>capacityIncrement()</code> |
| returns 64KB, creating natural HTTP/2 flow control backpressure — |
| the client tells the server "I can accept 64KB more" after each |
| chunk.</p> |
| |
| |
| <p>When the server uses the |
| <a href="json-streaming-formatter.html">Streaming JSON Formatter</a>, |
| data flows end-to-end without full-body buffering on either side:</p> |
| |
| |
| <pre class="prettyprint"><code> |
| Server (MoshiStreamingMessageFormatter) |
| → FlushingOutputStream flushes every 64KB |
| → HTTP/2 DATA frames |
| → Http2JsonClient.data() callback |
| → your OutputStream |
| </code></pre> |
| |
| </section> |
| |
| <section><a id="Timeout_and_Cancellation"></a> |
| <h1>Timeout and Cancellation</h1> |
| |
| |
| <p>Both methods accept a <code>timeoutSeconds</code> parameter for |
| <code>Future.get()</code>. If the timeout expires or the thread is |
| interrupted, the underlying HTTP request is cancelled to prevent |
| zombie requests that would continue consuming resources:</p> |
| |
| |
| <pre class="prettyprint"><code> |
| try { |
| response = future.get(timeoutSeconds, TimeUnit.SECONDS); |
| } catch (Exception e) { |
| requestFuture.cancel(true); // Cancel the HTTP request |
| if (e instanceof InterruptedException) { |
| Thread.currentThread().interrupt(); // Restore interrupt flag |
| } |
| throw e; |
| } |
| </code></pre> |
| |
| </section> |
| |
| <section><a id="Source_Code"></a> |
| <h1>Source Code</h1> |
| |
| |
| <p>The complete sample client is available on GitHub:</p> |
| |
| |
| <p><a href="https://github.com/apache/axis-axis2-java-core/blob/master/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/client/Http2JsonClient.java" class="externalLink"> |
| Http2JsonClient.java on GitHub</a></p> |
| |
| |
| <p>Copy and adapt it for your project. It has no dependency on |
| Axis2 itself — only Apache HttpClient 5 and httpcore5-h2.</p> |
| |
| </section> |
| |
| |
| </main> |
| </div> |
| </div> |
| <hr/> |
| <footer> |
| <div class="container-fluid"> |
| <div class="row-fluid"> |
| <p>© 2004–2026 |
| <a href="https://www.apache.org/">The Apache Software Foundation</a> |
| </p> |
| </div> |
| </div> |
| </footer> |
| </body> |
| </html> |