DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux
  • Graceful Shutdown: Spring Framework vs Golang Web Services
  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4

Trending

  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices
  • Integration Isn’t a Task — It’s an Architectural Discipline
  • Intro to RAG: Foundations of Retrieval Augmented Generation, Part 1
  • How Can Developers Drive Innovation by Combining IoT and AI?
  1. DZone
  2. Coding
  3. Frameworks
  4. Understanding Spring Reactive: Servlet 3.1/Spring MVC Non-Blocking IO

Understanding Spring Reactive: Servlet 3.1/Spring MVC Non-Blocking IO

Want to learn more about using Spring Reactive? Check out this post to learn more about using the non-blocking IO in Spring Reactive and Spring MVC.

By 
Naveen Katiyar user avatar
Naveen Katiyar
·
Updated Oct. 03, 18 · Presentation
Likes (12)
Comment
Save
Tweet
Share
30.7K Views

Join the DZone community and get the full member experience.

Join For Free

Servlet 3.0 was released as part of Java EE 6 and made huge changes focused at ease-of-use. The idea was to leverage the latest language features, such as annotations and generics, and modernize how Servlets can be written. One of the major changes was Async Servlets. The web.xml was also made as optional as possible. Servlet 3.1, released as part of Java EE 7, was an incremental release, focusing on a couple of key features like non-blocking IO.

Non-blocking I/O with Servlet 3.0 (Async Servlets as discussed in the previous article) allowed asynchronous request processing, but only the traditional I/O was permitted, which is blocking. This can restrict that scalability of your applications. Non-blocking I/O allows you to build scalable applications.

Let’s discuss what I mean by the above. We have learned, in the previous article, that in the case of an async servlet, we must use non-blocking code. So, let’s modify our earlier MyServlet code and replace runnable logic as below:

Let’s revisit the code snippet that we discussed in the previous article:

@WebServlet(name="myServlet", urlPatterns={"/asyncprocess"}, asyncSupported=true)
public class MyServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
OutputStream out = response.getOutputStream();
            AsyncContext aCtx = request.startAsync(request, response); 
            doAsyncREST(request).thenAccept(json -> {
out.write(json);  ---> BLOCKING!
ctx.complete();
          });
}


In the above code, the container request thread is released and work is done in another thread. So, for the Async Servlet to actually work as expected, we have the following requirements:

  •  doAsyncREST() must use the Async library to call REST and return CompletableFuture.This is possible using AsyncHttpClient, which we have already used in the previous article.
  •  thenAccept() should use Async libraries.

But, in Servlet 3.0, IO was traditional for blocking, and hence, the thread calling out.write() will block.

Let’s say that we have to write a large JSON file back to the client. As we are using the NIO connector, OutputStream will first write to buffers and those buffers need to be emptied by clients, using the selector/channel mechanism of NIO. Now, if clients are on a slow network, then out.write() will have to wait until buffers are empty again, as  InputStream/OutputStream is blocking.

The above problem of blocking was removed by the Servlet 3.1 release by introducing Async IO.

Servlet 3.1 Async IO

Let’s discuss this with the help of the code snippet shown below:

 void doGet(request, response) {
        ServletOutputStream out = response.getOutputStream();
        AsyncContext ctx = request.startAsync();
        out.setWriteListener(new WriteListener() {
            void onWritePossible() {
                while (out.isReady()) {
                    byte[] buffer = readFromSomeSource();
                    if (buffer != null)
                        out.write(buffer); ---> Async Write!
                    else{
                        ctx.complete(); break;
                    }
                  }
                }
            });
        }


In the above code, we are making use of the Write/Read Listener, which were introduced in 3.1. WriteListener is an interface that has an onWritePossible() method, which gets called by the Servlet Container. ServletOutputStreamt.isReady()is used to check if it is possible to write in NIO channel buffers. In case it returns false, then it schedules a call on the Servlet container for the  onWritePossible() method, and at some later point, onWritePossible() is called on another thread. So, in this way, out.write() never blocks for the slow client to empty the channel buffers.

Non-Blocking IO in Spring?

To use this feature of non-blocking IO in the Spring application, we would need Spring 5, which has Java EE 7 as its baseline version. So, our earlier example, which is also mentioned below, will execute in full non-blocking mode if we run this code on Spring 5 MVC, Tomcat 8.5+:

@GetMapping(value = "/asyncNonBlockingRequestProcessing")
    public CompletableFuture<String> asyncNonBlockingRequestProcessing(){
            ListenableFuture<String> listenableFuture = getRequest.execute(new AsyncCompletionHandler<String>() {
                @Override
                public String onCompleted(Response response) throws Exception {
                    logger.debug("Async Non Blocking Request processing completed");
                    return "Async Non blocking...";
                 }
            });
            return listenableFuture.toCompletableFuture();
    }


By now, we have discussed how Servlet has evolved, along with Spring, to provide complete non-blocking support. This means that we can scale our application with a smaller number of threads. In our next article, we will be discussing the Spring Reactive stack (i.e. Spring Webflux). One might think that, if Spring MVC is capable of handling request in a non-blocking way, then why use Spring Webflux because it was released as a separate stack?

Stay tuned! We will answer this question in our next article.

Spring Framework

Published at DZone with permission of Naveen Katiyar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux
  • Graceful Shutdown: Spring Framework vs Golang Web Services
  • Actuator Enhancements: Spring Framework 6.2 and Spring Boot 3.4

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!