Drama-free Way to Create a Modern Java Web Application

Valeria Listratova
SoftIndex
Published in
4 min readNov 20, 2019
Photo by Annie Spratt on Unsplash

Nowadays, Java web development is quite a challenge for newcomers. Most of the existing frameworks have high entry barriers and tend to massively inflate code with complicated layers of abstractions, a zoo of diverse technologies and boilerplate code. That’s why aspiring web developers often choose other simpler tools (bring greetings to Node.js).

In other words, there’s a strong demand for a new full-stack Java web solution to redefine the best designs without inheriting the aforementioned problems. It may sound quite impossible, but hold on: it’s already here!

Meet DataKernel — a full-stack Java web framework for creating efficient and scalable asynchronous web applications. Its main goal is to provide you with the most optimized full-stack tools to create lightweight web apps of any complexity without using any additional dependencies. The framework includes modules for creating all kinds of web apps, from simple HTTP servers/clients to high-performance memcached-like servers based on the binary RPC protocol.

HTTP is fully asynchronous and focuses on minimal latency, high performance and usability. Thus, it outperforms even highly-specialized microservices frameworks, for example, Vert.x:

In this article we’ll use DataKernel HTTP module as an efficient and high-performance solution for web applications.

Creating a “Hello World” server

To integrate DataKernel HTTP module into your project, add the following dependency to your pom.xml file:

You can also add a logger dependency (for example, logback-classic) for better clarity. Yet, it’s completely optional.

Now let’s write an HTTP server with bare minimum of DataKernel:

Yep, that’s it — no additional configurations are required. Now, let’s answer the main question:

How does it work?

We create the server via create(@NotNull Eventloop eventloop, @NotNull AsyncServlet servlet) method of AsyncHttpServer:

  • Eventloop is DataKernel’s solution that resembles Node.js Event Loop for efficient management of asynchronous operations without multithreading overhead. We manually create and pass the eventloop to the server.
  • The AsyncServlet is inlined via lambda that defines the processing of the received requests. What’s important to note is that we don’t use Java Futures for representing a result of asynchronous operations. Instead, we use DataKernel’s high-performance alternative — Promises.

All that’s left is to specify the listener port, make server listen, and run the eventloop.

Voila — you’ve got a running server! To check it out, open a browser and go to localhost:8080.

Improvement time!

The previous example was simple, but there’s room for improvement. Fortunately, the HTTP module includes a number of predefined solutions for typical use-cases. Moreover, with the help of additional DataKernel modules, such as DI, you will no longer have to worry about tedious low-level control. To showcase it, let’s improve our previous example and make it a little bit tidier:

Extending the HttpServerLauncher gives us two benefits. First, now we can use DI to specify the root HTTP listener servlet instead of doing it manually. We do it via the @Provides annotation. Second, the launch method of the superclass takes care of managing the app’s lifecycle: it injects dependencies, starts, runs and stops the app. Basically, Launcher is a highly abstracted and generalized implementation of main method.

Combining servlets

DataKernel HTTP module has much more to offer you. In addition to the showcased features, it also includes a lot of predefined servlet implementations:

..and many more. You can easily combine them to create a functional composition, for example:

Now you’ve got an asynchronous ultra high-performance server. Its final JAR file size with all the dependencies is only ~1MB.

Let’s see how it all works in a nutshell. We create an AsyncServlet provider method that returns a RoutingServlet, an AsyncServlet implementation. Adding a route to the servlet is made via map(@Nullable HttpMethod method, @NotNull String path, @NotNull AsyncServlet servlet) method. The method is pretty self-explanatory:

  • method (optional) is one of the HTTP methods (GET, POST, etc)
  • path is the path on the server
  • servlet defines the logic of request processing

loadBody method makes loading the request body a default setting. serve returns an AsyncServlet which processes the request. getPostParameter method gets the request’s post parameters. Another thing to notice in the example is the StaticServlet that is used for loading static content from a certain directory.

Let’s sum it up!

That’s it, we’ve just created a full-featured application-embedded server without any third-party dependencies or additional XML configurations. It is super-lightweight, asynchronous and features powerful DI, so you can extend the example and create web application of any complexity. What is more, it’s ready to be battle-tested in high-load scenarios due to the impeccable performance. And it all took us about 5 minutes!

Impressive, isn’t it? Want to see how it works from within and ensure that there is no hidden magic? Stay tuned for the next articles!

--

--

Valeria Listratova
SoftIndex

I’m a technical content writer who is interested in Java and new technologies