Birth of Spring Boot: From Servlets to Simplicity 🚀

Ekansh SaxenaEkansh Saxena
9 min read

Spring Boot revolutionized how we build Java applications by simplifying configurations, streamlining deployment, and providing robust development tools. But to appreciate the elegance of Spring Boot, it's essential to understand its origins and the challenges it solves. Let’s take a step back and uncover the journey, starting from servlets, moving to Spring MVC, and finally landing at the marvel that is Spring Boot.

How Java Applications Worked Before Spring: Servlets and Servlet Containers 🛠️

1. Understanding Servlets

Before Spring and Spring Boot, Java applications relied heavily on Servlets for web development. A Servlet is a Java class that processes HTTP requests and generates responses. To support the GET and POST mapping, we must override the doGet and doPost methods in that class.

1.1 Role of Servlet Containers
A Servlet Container like Apache Tomcat or Jetty managed these servlets. The container handled:

  • Receiving HTTP requests.

  • Invoking the appropriate servlet based on the URL mapping.

  • Managing the servlet lifecycle (loading, initializing, and destroying servlets).

Here’s an example to showing a servlet:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.getWriter().println("<h1>Hello, World!</h1>");
    }
}

To deploy this servlet, we needed to configure it in web.xml:

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

For every new endpoint, developers had to write additional mappings in web.xml, leading to verbosity.

2. Build and Run Architecture of Servlet Applications

Here’s a simplified sequence diagram to illustrate how servlet-based applications work:

Sequence diagram to show request flow in servlet applicaiton

  1. The developer writes code and packages it into a WAR file.

  2. The WAR file is deployed to a servlet container (e.g., Tomcat).

  3. The servlet container:

    • Loads and initializes the servlet.

    • Maps incoming requests to the appropriate servlet based on web.xml.

    • Executes the servlet and sends the response back to the client.

3. Challenges in Servlet-Based Applications 🚨

3.1 Overuse of Conditional Statements
Imagine you need to handle multiple endpoints in a single servlet. You’d end up writing something like this:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String path = request.getPathInfo();

    if ("/login".equals(path)) {
        response.getWriter().println("<h1>Login Page</h1>");
    } else if ("/register".equals(path)) {
        response.getWriter().println("<h1>Register Page</h1>");
    } else {
        response.sendError(HttpServletResponse.SC_NOT_FOUND, "Page Not Found");
    }
}

This quickly gets out of hand as the number of endpoints grows, making the code harder to read and maintain.

3.2 Bloated web.xml
For large applications, the web.xml file grew unwieldy, increasing the chances of errors and maintenance overhead.

3.3 Manual Dependency Management
Developers had to explicitly manage dependencies, often leading to classloader issues and conflicts.

3.4 Lack of Modularity
Each servlet was tightly coupled to a specific logic, making it hard to reuse or test components independently.

Why Spring MVC Was Introduced🌟

1. Understanding Spring MVC

Spring MVC brought structure and simplicity to Java web applications:

  • Annotations instead of XML: Developers used annotations like @Controller and @RequestMapping, reducing reliance on web.xml. Don’t bother; we’ll learn about annotations in depth in upcoming blogs.

  • Separation of Concerns: Controllers handled requests, and views rendered responses.

  • Dependency Injection: This allowed cleaner, testable, and loosely coupled code. We’ll discuss more on this in our next blogs.

Here’s an example of Spring MVC:

public class HelloController {
    @RequestMapping("/hello")
    public String sayHello(Model model) {
        model.addAttribute("message", "Hello, Spring MVC!");
        return "hello";
    }
}

Instead of manually mapping URLs, @RequestMapping handled the routing elegantly. 🎯

2. Architecture of Spring MVC 🏗️

Here’s how Spring MVC improved upon servlets:

Sequence diagram to show request flow in spring MVC applicaiton

  1. DispatcherServlet: The central servlet that intercepts all requests and route them to the correct handlers. Let’s see how it works:

    • The web.xml file maps all requests to the DispatcherServlet.

    • The servlet scans for annotated classes (e.g., @Controller).

    • Based on annotations, it routes requests to the correct handler method.

  2. HandlerMapping: It determines which controller should handle the request. It comes with different types:

    • RequestMappingHandlerMapping (default, uses annotations)

    • SimpleUrlHandlerMapping (URL pattern matching)

    • BeanNameUrlHandlerMapping (matches URLs to bean names)

  3. HandlerAdapter: It consists of three main methods:

    • preHandle(): Before controller execution

    • postHandle(): After controller execution, before view rendering

    • afterCompletion(): After complete request processing

  4. Controller: It has functions with required mappings to methods like Get and Post which can handle business logic itself or one can keep logic in the Service layer..

  5. View Resolver: Maps logical view names to actual views (e.g., JSP files).

Key Difference:
Unlike servlets, where everything was tightly coupled, Spring MVC promoted a layered and modular architecture.

3. How Spring MVC Avoids If-Else in case of multiple endpoint requests.

The @RequestMapping annotation directly maps URLs to methods:

public class UserController {
    @RequestMapping("/login")
    public String login() {
        return "loginPage";
    }

    @RequestMapping("/register")
    public String register() {
        return "registerPage";
    }
}

No more if-else spaghetti code! 🎉

4. Issues and Complexities in Spring MVC

While Spring MVC solved many issues, it introduced new complexities:

3.1 DispatcherServlet Configuration
The DispatcherServlet required explicit setup and multiple configuration files.

3.2 External Servlet Containers
Spring MVC applications relied on external servlet containers like Tomcat. Developers had to package their applications as WAR files, which were then deployed manually to the server.

3.3 Lack of Embedded Server Support
Without embedded servers, running and testing applications locally required additional setup.

Why Spring Boot Came into the Picture 🎉

1. Understanding Spring Boot

Spring Boot made developers' lives easier by:

  • Embedding Servers: Spring Boot introduced embedded servers (e.g., Tomcat, Jetty) that allowed developers to run applications as standalone JAR files.

  • Convention Over Configuration: Spring Boot minimized boilerplate code by offering sensible defaults. Example: application.properties replaced verbose XML configurations.

  • Auto-Configuration: Spring Boot automatically configured beans and components based on the classpath and environment.

      @SpringBootApplication
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
    

    If you didn’t understand the above code, Don’t worry, we’ll go deeper into this in upcoming blogs.

  • Spring Boot Actuator: Provides features for administering and monitoring applications, including health checks, metrics, auditing, and tracing.

Starter Dependencies: With Spring Boot, dependency management was streamlined using "starters." For example:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Adding spring-boot-starter-web automatically sets up: Embedded Tomcat, Spring MVC, and RESTful endpoints.

No need for web.xml or DispatcherServlet configuration. Simply include spring-boot-starter-web, and you're good to go! 🚀

2. Architecture of Spring Boot

2.1 Typical Spring Boot Application Startup Flow:

  1. @SpringBootApplication annotation triggers auto-configuration

  2. Embedded server starts

  3. Spring Context is created

  4. Dependency Injection occurs

  5. Beans are initialized

  6. Application becomes ready to serve requests

Sequence diagram to show request flow in spring boot applicaiton

2.2 Key Architectural Advantages:

  1. Opinionated Configuration: Spring Boot follows a convention over configuration philosophy, providing default configurations for common scenarios to reduce boilerplate.

    • Example: Adding spring-boot-starter-web automatically configures Spring MVC and an embedded Tomcat server without requiring explicit configurations.

    • Developers can override these defaults for custom needs.

  2. Embedded Server Support: Spring Boot supports embedded web servers like Tomcat, Jetty, and Undertow, which eliminates the need for deploying WAR files to external servers. How It Helps:

    • Run applications independently using java -jar.

    • Simplifies local development and CI/CD pipelines.

  3. Production-ready features: Spring Boot includes features to enhance production-readiness through its Actuator module:

    • Health checks (/actuator/health).

    • Metrics (/actuator/metrics).

    • Application insights and management endpoints.

These features help in seamless monitoring and troubleshooting.

  1. Simplified Dependency Management: Spring Boot introduces starter dependencies that bundle related libraries to simplify dependency management:

    • Example: spring-boot-starter-data-jpa includes Hibernate, JPA, and H2 database.

    • Developers only need to include one dependency instead of managing individual library versions.

  2. Easy Externalized Configuration: Spring Boot applications support externalized configuration using application.properties or application.yml. Why It’s Useful:

    • Simplifies environment-specific configurations (e.g., dev, test, prod).

    • Supports profiles for switching configurations easily (e.g., spring.profiles.active=prod).

Key Differences between Servlet-Based Apps, Spring MVC, and Spring Boot

AspectServlet-Based ApplicationSpring MVCSpring Boot
Central ControlNo centralized control; developers manually handle routing and logic using servlets.Centralized control through DispatcherServlet, acting as the front controller to route requests.Extends Spring MVC with additional features like auto-configuration and embedded server support for simplified development.
Separation of ConcernsLimited; business logic, routing, and response handling often mix in the same servlet class.Promotes separation using Controller, Service, and Repository layers.Enforces separation with layered architecture, providing additional abstractions like starter dependencies for modularized codebases.
ConfigurationRequires verbose, manual configuration in web.xml and Java classes.Reduced boilerplate with annotations like @Controller and @RequestMapping.Drastically simplified with auto-configuration; uses application.properties or application.yml for declarative configuration.
Request ProcessingHandled explicitly through overridden methods like doGet() and doPost().Managed by DispatcherServlet with request mapping via annotations.Streamlined further with auto-mapping of request paths and embedded server initialization.
MaintainabilityLow; tightly coupled code makes refactoring and scaling challenging.Better maintainability due to clear separation of layers and use of annotations.High maintainability with modular starters, externalized configurations, and minimal boilerplate.
FlexibilityHigh flexibility but requires significant manual coding for even basic features.Balanced flexibility with built-in features and extension capabilities.Extremely flexible with minimal manual setup, allowing quick customization through plugins and auto-configuration.
TestingDifficult to test due to the lack of abstractions and dependency injection.Easier testing with dependency injection, mock frameworks, and integration testing support.Simplified testing through tools like Spring Boot Test, MockMvc, and out-of-the-box testing configurations.
Exception HandlingCustom handling required in each servlet using try-catch blocks or error pages.Centralized exception handling using @ControllerAdvice and @ExceptionHandler annotations.Built-in support for exception handling with Actuator endpoints for detailed error analysis.
Embedded Server SupportNot supported; applications must be deployed on external servers like Tomcat.Requires external server deployment, though simplifies the process.Built-in support for embedded servers like Tomcat, Jetty, and Undertow, enabling standalone execution with java -jar.
Startup TimeManual and slow, requiring server deployment steps.Faster than servlets but still requires external server deployment.Very fast, as the embedded server starts directly with the application.
Ease of UseSteep learning curve due to verbose configuration and manual management.Easier than servlets but requires knowledge of Spring annotations and configurations.Highly user-friendly; auto-configuration and starters make it ideal for beginners and advanced users alike.
Production-ReadinessMinimal; developers need to integrate external tools for monitoring and managing applications.Supports monitoring through additional libraries but requires custom integration.Production-ready features out of the box with Actuator, metrics, health checks, and monitoring endpoints.
Learning CurveHigh; developers need to understand low-level details like servlet lifecycles and manual request routing.Moderate; requires understanding of Spring Framework concepts like Dependency Injection and Annotations.Low; opinionated defaults reduce the need for in-depth framework knowledge while still allowing advanced customizations.

🌟 Stay Tuned for More! 🌟

Thank you for diving into the journey of understanding Spring Boot with me! 🚀 This is just the beginning—there’s so much more to explore! In the upcoming blogs, we’ll uncover deeper concepts like Spring Boot security, advanced auto-configuration, custom annotations, testing strategies, Maven and deploying Spring Boot applications in production-ready environments. Each blog will be packed with detailed explanations, hands-on examples, and practical insights to empower you to master Spring Boot. So, keep an eye out—exciting content is just around the corner! 😊

30
Subscribe to my newsletter

Read articles from Ekansh Saxena directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ekansh Saxena
Ekansh Saxena