Deferred Result: Make Spring Boot Non-Blocking

deferred result is non-blocking

Divyesh Kanzariya, Java Tutorials Spot

Non-blocking I/O is achievable in Spring using the deferred result. This article examines how to improve speed on a heavily trafficked website using Spring and how to test a deferred result.

Spring is fast but suffers from dedicating a single thread per request. The deferred result helps eradicate this issue.

Why is My Spring Boot Website Slow?

Spring is written in Java which does not block. However, Spring dedicates a single thread to each request. No other work is performed on the thread for the life of the request.

This means that performance tuning often revolves around dedicating more RAM or CPU to the website. The JVM must account for threads, and this can become cumbersome no matter how well built a system is.

Executing a single request per thread is particularly problematic when requests to other services are made or heavy computation is performed.  For instance, a program might create a call to a database system. The handling thread will wait until the response is received before continuing. A bottleneck occurs when thousands or millions of  requests are processed at once.

When Can Non-Blocking I/O Help?

Non-blocking I/O as outlined above performs a request on a thread pool. Computation and I/O laden requests are completed in the background while the main thread works on other tasks. By not blocking, the comptuer is free to perform more work this includes handling other requests in Spring.

Java contains a variety of mechanisms to avoid blocking.  A fork-join pool and thread pool are available to the developer.

Fork-join pools are particularly useful. In this pool, idle threads take up work from active threads.

How Can I Perform Non-Blocking I/O in Spring Boot?

Spring Boot allows for non-blocking I/O to be performed through the deferred result. Error or response objects are set in the deferred result which serves as the return value:

@PostMapping("/test_path")
public DeferredResult testDeferred(){
    DeferredResult deferred = new DeferredREsult();
    deferred.onTimeout(() -> Logging.info("timeout");
    Thread thread = (() -> {
        deferred.setResult("Success");
        //deferred.setErrorResult("error");
    });
    ForkJoinPool.commonPool().submit(thread);
    deferred;
}

A deferred object is thread-safe. The return value is set in the result. An error object and function executed on timeout may be configured as well.

How Can I Test Non-Blocking I/O in Spring?

Testing non-blocking I/O is possible through  MockMvc or RestAssured. MockMvc handles asynchronous requests differently from synchronous calls:

ResultActions resultActions = this.mockMvc.perform(post("/test_path"));
MvcResult result = resultActions.andExpect(request().asnycStarted()).andReturn();
result = this.mockMvc.perform(asyncDispatch()).andReturn();

 

After ensuring that the asynchronous behavior started execution and awaiting a return value, testing continues as before.

Conclusion

Spring and Spring Boot can perform non-blocking I/O calls. This allows the framework to wait for computation-heavy processes and asynchronous network requests to complete while other network calls are handled by the original thread.

A fork-join pool or thread pool ensures that only a certain number of threads are created to handle background tasks.

A Neat Little REST Trick

So there is a shared memory problem. We are using the REST template and a few solutions come to mind. Perhaps it is time to not rule out statics.

The Controller component is established as a Singleton whose methods are called by every connection. It is possible to include a static synchronized static object to avoid. Java’s concurrent classes have a few of these. Synchronized classes and maps of locks are way more complicated and likely to slow things down. Synchronized methods in fact lock all Class level methods and attributes (e.g. synchronize(this)).

As a warning though, the CopyOnWriteArrayList is thread safe but slow for writing to.

The example below is of a ConcurrentHashMap<String,Integer> but the types are sometimes not showing, sorry.

@RestController
public class RESTClass{
    private static ConcurrentHashMap<String,Integer> mp = new ConcurrentHashMap<String,Ingeter>(); 
}

Mixing Scala and Java in Java Spring

Scala downright rocks at certain things. Java is great in others. How do you mix Scala into an existing Java Spring Maven program without causing trouble? With a few simple tricks that really don’t require much.

Scala uses the JVM and has a matching java collections compatibility. Using these it is possible to update nearly any Java Spring-maven program with Scala classes.

Dependencies for Maven

There is one simple dependency for this to work, the Scala Programming Language. Add the language to your POM as follows.

    org.scala-lang
    scala-library
    2.11.3

This will cause the scala language to be included with Maven at runtime.

Wiring your Class with XML

In discovering this, I am using XML due to the need to easily manipulate a class many times. Spring is basically acting as GUI, enforcer, and code reducer.

Class variables are considered as part of the constructor and must include the scala.beans dependency. All variables need the @BeanProperty to work. Furthermore, importing scala.collection.JavaConversions._ will give java collections scala like properties such as the ability to use .foreach().

    import scala.beans._
    import scala.collection.JavaConversions._
    class MyClass{
       @BeanProperty
       var source:String = null
       
       @BeanProperty
       var fromImports:String = null
    }

This @BeanProperty annotation will create a getter and setter for Spring when the program builds. It is required even when using a constructor argument.

The following xml can be used to wire the bean.

      <property name="source" value="mySource"/>

If the variables are placed in a constructor, wire as such.

  <bean id="Notify" class="com.hygenics.parser.MyClass" parent="imports">
 	<constructor-arg name="source" value="mysource"/>
</bean>

Secure Your Data Series: Protecting from SQL Injection

I have been collecting data and building databases for a while. As I do so, I have come across a wide variety of mistakes in thought and code varying from the notion that a captcha works to a failure to adequately protect from SQL injection. Therefore, I am going to publish fixes to what I find here with examples utilizing Groovy or Spring and Java.

First up, the SQL injection attack. Attempts to stop these attacks range from  using JavaScript to setting variables. I recently came across a site that made an attempt to stop these attacks by limiting wildcards and querying with a variable. However, changing the header by resetting the variable actually gave me access to everything on the site in one fell swoop.

Suggestions

A few suggestions follow:

  • Do not check anything with JavaScript, this is too easy to get around by simply rewriting the page.
  • Write rules in the back end to protect from unauthorized access using SQL. Check variable combinations.
  • Eliminate any suspicious non-allowable wildcards and look for key terms like LIKE, ILIKE,%, and = that are common for WHERE clauses. Select statements in SQL/POSTGRESQL follow a form similar to SELECT –data list– FROM –table– WHERE –variable— ILIKE ‘%answer%’
  • Track IP Addresses and web pages using a symbol table (HashMap and the like) to eradicate any attempts to plainly just post to a server when it is not an API. This should be done in addition to any viewstate tracking and I strongly encourage the use of event validation.
  • Use event validation if available or come up with your own.

Implementation

Most requests occur through a POST request and most of the requests are handled in Java using spring or a format such as aspx with Groovy Grails starting to become popular.

  
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/path")
public class PostController{
      //RequestMethod.GET also exists
      @RequestMapping(value="/path",method=RequestMethod.POST)
      public ResponseEntity newAnswer(@RequestParam(value="stringq", required=true) String stringq,@RequestParam(value="",required=true) boolean wildcard){
           //prep response
           HttPHeaders headers=new HttpHeaders();
           headers.set("Content-Type","text/html; charset=utf-8");
           
           //get IP
           String ip=requestAttributes.getRequest().getRemoteAddr();

           String data=null;           

           //check for appropriate response page, assumes post-like nature with single url
           //makes a call to a HashMap entity setup at the beginning of the program
           // and accessible throughout the servers existance
           if(IPmap.get(ip).compareTo('appropriatePageURL')==0){
           
               //create variable data here with response JSON or string
           }else{
               //create innappropriate use message
           }
           return new ResponseEntity(data, headers, HttpStatus.CREATED);
      }
}

The hashmap in this case is a static hash map. However, for security (even if using package level access modifiers) a file may be the solution. This will add time to the response though.