DEV Community

Amoghmanoranjith Navade
Amoghmanoranjith Navade

Posted on

Without Spring boot

For the past four months, I have been exploring the Spring ecosystem, learning about architectures, design patterns, and how large Java backend systems are structured.
Among the many technologies in the ecosystem, one just sat in the backdrop silently making my life easier.

I already knew what Spring Boot did at a high level. It handles auto-configuration, embedded servers, starter dependencies, and opinionated defaults. But, I never truly appreciated why those features mattered.

So I decided to build a Spring MVC application without using Spring Boot.

The goal was simple: create a simple API.
What I ended up learning was far more valuable than the API itself.

The first thing I discovered was that Spring applications can actually have two separate configurations:

  • Root Application Context
  • Web Application Context

The Root Application Context contains beans shared across the entire application, such as services, repositories, data sources, and infrastructure-related beans.

The Web Application Context is specific to a DispatcherServlet.
This means a Spring MVC application can technically have multiple dispatcher servlets, each responsible for handling a different group of routes.

Each dispatcher servlet can have its own:

  • Controllers
  • View resolvers
  • Exception resolvers
  • Handler mappings

while still sharing common resources from the root context.

Understanding this made me realise something important:

Spring Boot heavily opinionates this architecture.

By default, it configures:

  • a single DispatcherServlet
  • a unified application context
  • sensible defaults for MVC infrastructure

The next part was deployment.

Without Spring Boot, there are primarily two ways to run a Spring MVC application:

  1. Package the application as a .war file and deploy it to an external Tomcat server
  2. Use an embedded Tomcat server directly inside the application

The first approach made me appreciate how difficult development used to be.

Traditional Tomcat deployment architecture

Every small change involved:

  • packaging the project
  • copying the WAR file
  • deploying it to Tomcat
  • restarting the server
  • checking whether the application even started correctly

A runtime error could easily cost several minutes.

With an embedded server, the application itself controls Tomcat.
Tomcat still hosts the DispatcherServlet inside its servlet container, but now the server lifecycle becomes part of the application lifecycle itself.
Embedded Tomcat architecture in Spring Boot

This architectural shift dramatically improves developer experience.

And then came the thing I probably underappreciated the most before this exercise:

Spring Boot starter dependencies.

At first glance, starters seem like simple dependency bundles.

But after manually configuring Spring MVC, servlet APIs, embedded Tomcat dependencies, and compatible versions, I finally understood their real value.

Spring Boot starters handle:

  • dependency compatibility
  • version alignment
  • transitive dependency management
  • boilerplate configuration

Without them, developers would spend a significant amount of time manually resolving library conflicts and configuration issues.

After building this small project without Spring Boot, I started appreciating Spring Boot far more than before.

Not because it makes things easy, but because I now understand the complexity it abstracts away.

I think this is true for many frameworks and tools in software engineering:
you only fully appreciate an abstraction after experiencing life without it.

references:
https://tomcat.apache.org/tomcat-5.5-doc/architecture/overview.html
https://medium.com/@dulanjayasandaruwan1998/understanding-spring-boot-architecture-flow-615d209b95f9

Top comments (0)