Sitemap

From Servlets to Spring Boot: Understanding the Evolution of Java Backend Development

10 min readJul 21, 2026

--

Servlet

A Servlet is a Java class that handles client requests, processes them, and returns the response.

We can create different servlets for different purposes:

  • One servlet for accepting REST API requests
  • Another servlet for accepting SOAP API requests
  • Another servlet for handling file uploads

For example, in Spring MVC, the DispatcherServlet is configured by default to handle all APIs using "/*" mapping.

Servlet classes are known as Servlet APIs.

A Servlet Container is responsible for managing servlets.

Custom Servlet

To create a custom servlet:

  • You need to extend the HTTPServlet class.
  • You need to override methods like:
doGet()
doPost()
doPut()
doDelete()

These methods handle different types of HTTP requests.

Java Application Without Any Framework

Previously, if you wanted to build an application using Java without any framework, you had to create servlet classes that would handle the incoming requests.

After creating servlets, you needed to map those servlets inside the web.xml file.

In web.xml, we needed to define:

  • What are all the servlets available
  • Which APIs each servlet handles
  • Which servlet should handle which request

The request flow was:

  1. The request first arrives at the Servlet Container (Tomcat).
  2. The servlet container checks web.xml.
  3. It identifies which servlet should handle the request.
  4. It invokes the particular method of that servlet that handles the request.

Problems with Servlets

1. web.xml File

In Servlet-based applications, everything was configured inside web.xml.

It contained:

  • All servlets
  • All servlet mappings
  • Which servlet handles which API
  • All filters
  • All listeners

For a large application, this became a huge problem because the file could contain thousands of lines of configuration.

2. Servlet Class Problem

Servlet classes also created problems.

A servlet can have only one method for each HTTP request type:

  • One doGet()
  • One doPost()
  • One doPut()
  • One doDelete()

But in real applications, we need multiple GET APIs, multiple POST APIs, and so on.

Because of this limitation, we had to use many if conditions inside methods.

For example, inside doGet(), we had to check the request path manually:

if (request.getPathInfo().equals("/users")) {
...
}
else if (request.getPathInfo().equals("/users/1")) {
...
}

The servlet method became responsible for handling multiple APIs.

3. Object Creation Problem

In Servlets:

  • We create objects manually using new.
  • Our class decides what objects to create and when to create them.

This causes:

  • Tight coupling
  • Hard-to-test code
  • Lifecycle management becomes our responsibility

4. Unit Testing is Much Harder

In Servlets, object creation depends on the Servlet Container.

Because of this dependency, mocking is not easy and unit testing becomes much harder.

5. WAR Deployment Problem

With Servlet-based applications:

  • We needed to create a WAR file of our application.
  • Then deploy it manually on Tomcat.

This process was time-consuming.

Spring Framework / Spring MVC

Because of the problems existing in Servlets, the Spring Framework was introduced.

Spring Framework does not support Java 25 yet.

Spring solved many problems that existed in traditional Servlet-based applications.

1. Removing the web.xml Problem

Spring introduced annotation-based configuration.

Instead of managing everything manually inside web.xml, we could configure things using annotations.

2. Inversion of Control (IoC)

IoC is a more flexible way to manage object dependencies and their lifecycle.

It works through Dependency Injection.

3. Unit Testing

Spring Dependency Injection makes unit testing much easier.

4. Easy API Creation

Spring made API creation easier.

We just need to use annotations like:

@GetMapping

to create GET APIs.

We can create multiple APIs in the same way.

5. Integration

Spring makes integration with other technologies easier, such as:

  • Hibernate
  • Security
  • Other frameworks

Problems with Spring Framework

Although Spring solved many problems that existed with Servlets, Spring itself had some problems.

1. Dependency Management Problem

While adding dependencies in Spring, we needed to add the dependency along with its version.

The added dependency should also be compatible with the already existing dependencies.

So, we needed to manually take care of dependency versions and compatibility.

2. WAR Deployment Problem

Similar to Servlet-based applications:

  • We still needed to create a WAR file of our application.
  • Then we had to deploy it on Tomcat manually.

This process was time-consuming.

Spring Boot

Because of these problems, Spring Boot was introduced.

Spring Boot follows the software principle:

Convention over Configuration

This means:

Prefer sensible defaults (convention) but allow developers to override them (configuration).

Convention vs Configuration

Convention

Convention means the default behavior that Spring Boot applies automatically.

Configuration

Configuration means custom settings that override the default behavior.

You can change the default behavior using:

  • application.properties
  • application.yml
  • Java @Bean definitions
  • Custom configuration classes

Spring Boot assumes that you want the most common setup, so it:

  • Auto-configures beans
  • Provides default settings
  • Detects dependencies and configures them
  • Chooses the default server (Tomcat)
  • Chooses the default port (8080)
  • Uses Jackson as the default JSON library
  • Uses Logback as the default logging framework

Embedded Server

Spring Boot automatically configures the server port by default.

This follows the convention approach.

The default port is:

8080

If we want to override it, we can configure:

server.port=8081

This is configuration.

Auto Configuration

Spring Boot automatically configures beans based on classpath dependencies.

What is Classpath Dependency?

Classpath dependencies mean the JAR files or libraries that exist in your project.

Examples:

  • spring-boot-starter-web
  • spring-boot-starter-data-jpa
  • spring-boot-starter-security

When certain libraries are present in your project, Spring Boot automatically creates and configures the required beans.

You do not need to manually write configuration classes.

Auto Configuration Example

Convention

Spring Boot checks what is present in the classpath and configures things automatically.

For example:

If your dependencies include:

spring-boot-starter-data-jpa

Spring Boot automatically configures:

  • EntityManagerFactory
  • HibernateJpaVendorAdapter
  • DataSource
  • TransactionManager
  • Repository scanning

You do not need to create these beans manually.

Configuration

You can override or customize auto-configured values using application.properties.

Example:

spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

Dependency Management

Spring Boot provides starter dependencies.

Examples:

  • spring-boot-starter-web
  • spring-boot-starter-test

These starters:

  • Automatically select compatible versions
  • Prevent dependency conflicts
  • Reduce manual work

You do not need to worry about versions anymore.

Spring vs Spring Boot

Spring Boot is a layer built on top of Spring that provides:

  • Auto Configuration
  • Embedded servers
  • Opinionated defaults
  • Easy project setup through Spring Initializr
  • Minimal configuration

Spring Framework

In Spring, we had to perform manual configuration.

This included:

  • Large XML files
  • Manual bean creation
  • Manual server setup
  • Complex configuration for MVC, JPA, Hibernate, and transactions

Server Setup in Spring

The server did not come embedded.

We had to:

  • Install an external server like Tomcat, Jetty, or WildFly
  • Create a WAR file
  • Deploy the application manually

Spring Boot

In Spring Boot:

  • Almost everything is auto-configured.
  • We just need to annotate and run.
  • No XML configuration is required.

Embedded Server in Spring Boot

Spring Boot comes with embedded servers:

  • Embedded Tomcat
  • Embedded Jetty
  • Embedded Netty

We can run the application using:

java -jar

and deploy it as an executable JAR.

Smart Defaults in Spring Boot

Spring Boot applies smart defaults.

For example:

When we add:

spring-boot-starter-web

Spring Boot automatically configures:

  • DispatcherServlet
  • WebMVC
  • Jackson
  • Tomcat
  • Validation
  • Logging
  • Error handling

We do not need to configure these manually.

Production Ready Defaults

Spring Boot provides production-ready defaults like:

  • Logging
  • Error pages
  • Metrics

Spring Boot provides pre-made dependencies, making it easier to write code.

Get Bashira Farhin’s stories in your inbox

Join Medium for free to get updates from this writer.

Examples:

  • spring-boot-starter-web
  • spring-boot-starter-data-jpa
  • spring-boot-starter-security

Cons of Spring Boot

Although Spring Boot makes development easier, it also has some disadvantages.

1. Less Control

Because of auto-configuration, we get less control over configurations.

2. Heavy Startup for Small Applications

For small applications, Spring Boot can have heavier startup time because it packages many libraries by default.

3. Larger JAR Size

Spring Boot applications have larger JAR sizes because the embedded server is included.

4. Difficult Auto-Configuration Debugging

Debugging auto-configuration issues can be difficult because too many auto-configured beans may confuse developers.

Application.properties vs Application.yml

Spring Boot allows configuration using two formats:

  • application.properties
  • application.yml

YAML or .yml is not related to Docker.

.properties File

Properties files use:

  • Flat key-value pairs
  • Dot (.) notation to represent hierarchy

Example:

spring.datasource.username=root
spring.datasource.password=1234

When we want nested configuration, there is a lot of repetition.

Properties files are:

  • Good for small configurations
  • Simple

But they become long and ugly when configurations are deeply nested.

Lists in Properties Files

For lists, properties files need special syntax.

Example:

spring.profiles.active[0]=dev
spring.profiles.active[1]=test

Spring Profiles in Properties Files

Spring uses configuration files based on the active profile.

The active profile is set using:

spring.profiles.active=dev

Spring Naming Rule

Default configuration file:

application.properties

Profile-specific configuration files:

application-{profile}.properties

These files are loaded only when that profile is active.

Examples:

application-dev.properties
application-qa.properties
application-prod.properties

Multiple Active Profiles

Example:

spring.profiles.active=prod,dev

This activates all mentioned profiles.

However, the configuration file loaded with higher priority will be the last profile mentioned.

In this case:

application-dev.properties

will be loaded.

If spring.profiles.active is not set:

application.properties

is used.

If both are set, priority is given to the user-provided configuration.

The value in application.properties can be changed from:

  • Terminal
  • Operating System
  • pom.xml

That is why it is dynamic.

Application.yml File

YAML files use the YAML format.

They provide:

  • Hierarchical structure
  • Clean and structured configuration
  • Better readability for complex configurations

Example:

spring:
datasource:
username: root
password: 1234

Lists in YAML

YAML supports lists naturally.

Example:

spring:
profiles:
active:
- dev
- test

In YAML, you can also use the dot operator to represent hierarchy.

However, there is no point in using it because YAML was introduced to remove the downside of .properties files.

Build Tool

Writing code is only part of the work.

To run an application, we often need to:

  • Compile source code
  • Download and manage dependencies (libraries)
  • Run tests
  • Create a final package (JAR, WAR, ZIP, Docker image, etc.)
  • Clean old builds
  • Deploy the application

A build tool automates all of these tasks.

Both Maven and Gradle are build tools.

Maven

Maven is a build automation tool primarily built for Java projects.

Later, it was configured to build projects written in other languages as well.

Maven builds a project using:

  • Project Object Model (POM)
  • A set of plugins

Maven is hosted by the Apache Software Foundation.

Initially, it was known as the Jakarta project.

Maven Configuration

In Maven, configuration is written in XML using:

pom.xml

Because XML requires many tags, Maven configuration contains a lot of boilerplate.

For adding a dependency in Maven, we need to use multiple tags.

Example:

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

Maven Performance

Maven is slower because it performs a full build from scratch every time we create a build.

Maven performs compilation every time, even if the input files have not changed.

Maven does not provide:

  • Advanced caching
  • Parallel build by default

Maven as a Project Management Tool

Maven is also a project management tool.

It helps developers with:

  • Build generation
  • Dependency resolution
  • Documentation

Maven uses the POM (Project Object Model) to achieve this.

When we run a Maven command:

  1. Maven looks for pom.xml in the current directory.
  2. It reads the required configuration from it.

Before Maven, there was a tool called Ant.

In Ant, we had to define:

  • What to do
  • How to do it

Maven Project Identification

groupId and artifactId are used to identify a particular project in Maven Central.

Every pom.xml is a child of another pom.xml.

By default, every pom.xml is a child of the super pom.xml.

Maven Lifecycle

Maven has different phases in its lifecycle.

The lifecycle phases are:

  1. Validate
  2. Compile
  3. Test
  4. Package
  5. Verify
  6. Install
  7. Deploy

Validate

Checks the project structure.

Compile

Compiles the source code.

Test

Runs tests on the code, such as unit tests.

Package

Packages the compiled code into:

  • JAR
  • WAR

Verify

Checks the integrity of the package.

Install

Installs the package into the local repository.

Deploy

Deploys the package into a remote repository.

Maven Commands

When we run:

mvn install

It runs every lifecycle step except the last one.

If you want to run a particular phase, then all previous phases will also run.

Each phase contains a list of goals/tasks.

If you want to run a specific goal of a particular phase:

  • All goals of previous phases will run.
  • Current phase goals before the defined goal will run.

Adding Custom Goals in Maven

If you want to add a new goal or task to any lifecycle, you can use:

<build>
</build>

inside the pom.xml file.

Gradle

Gradle is a build automation tool for multiple programming languages.

It was primarily built to remove the drawbacks of Maven.

Gradle introduces a Java and Groovy-based DSL (Domain Specific Language) for declaring project configuration.

What is DSL?

Gradle provides a customized language designed specifically for build configuration.

You can think of DSL as:

  • A special language inside Groovy or Kotlin
  • It provides special keywords offered by Gradle
  • It is designed to make build configuration easy to describe

Examples of Gradle DSL Keywords

Some common DSL keywords are:

dependencies { }
tasks { }
repositories { }
plugins { }

These are not standard Groovy or Kotlin keywords. They are Gradle DSL constructs.

Advantages of DSL

DSL avoids unnecessary boilerplate such as XML tags.

For example, to add a dependency in Gradle:

implementation 'org.springframework.boot:spring-boot-starter-web'

Since Gradle DSL is based on Groovy/Kotlin, you can write:

  • Functions
  • Conditions
  • Loops
  • Variables

DSL provides:

  • Better readability
  • Greater flexibility
  • Less boilerplate
  • The power of a real programming language
  • Easier custom builds

Gradle Performance

Gradle provides better performance because it performs incremental builds.

Gradle remembers the previous build and checks:

  • Have the input files changed?
  • Have the output files changed?

If nothing has changed, Gradle skips that task.

When a new build is triggered, Gradle only builds the newer or updated tasks instead of rebuilding everything.

It also avoids recompiling when there are no changes in the input files.

Gradle Build Workflow

Gradle is task-based, not phase-based.

It provides several optimization features:

  • Daemon
  • Caching
  • Parallel builds

Incremental Builds

Incremental builds mean Gradle rebuilds only what has changed.

Parallel Builds

Parallel builds make multi-module projects faster.

If your project has multiple independent modules, Gradle can build them simultaneously using multiple CPU cores.

Example modules:

  • user-service
  • auth-service
  • payment-service

If these modules do not depend on each other, Gradle builds them in parallel.

Build Cache

Gradle reuses outputs from previous builds using the build cache.

Daemon Process

Gradle normally runs a background process called a daemon, which stays running in memory.

This daemon keeps:

  • JVM preloaded
  • Classes already loaded
  • Build scripts parsed
  • Configuration cached

Without Daemon

For every build:

  1. Start the JVM
  2. Load Gradle
  3. Configure the environment
  4. Start the build

With Daemon

Gradle reuses the already-running JVM, allowing the build to start immediately.

--

--