If you come from JavaScript, Python, or another programming background, the Java ecosystem can feel unnecessarily complicated.
You hear:
JDK, JVM, Servlet, JSP, Tomcat, Spring, Spring MVC, JPA, Hibernate, Spring Boot, Maven, Docker, Kubernetes...
Are these all different things?
Not really.
Most of them are layers that appeared over time to solve different problems.
The easiest way to understand Java is to follow the problems that developers were trying to solve.
1. Java: The Foundation
Java is a programming language, but the Java ecosystem is more than the language itself.
Java applications are compiled into bytecode, which runs on the JVM (Java Virtual Machine).
Java Code
↓
Compiler
↓
Bytecode
↓
JVM
↓
Operating System
The JDK (Java Development Kit) provides the tools needed to develop and build Java applications.
So, at the foundation:
Java → JDK → JVM → Operating System
But Java alone doesn't tell us how to build a web application.
That leads us to Servlets.
2. Java Goes to the Web: Servlet, Tomcat and JSP
A browser communicates using HTTP.
So we need something that can receive:
GET /users/10
and execute Java code in response.
Servlet
A Servlet is a standard Java component for handling web requests.
Browser
↓ HTTP
Servlet
↓
Java Application
But where does the Servlet run?
Tomcat
Apache Tomcat is a Servlet container.
It provides the environment that receives HTTP requests, manages Servlets, and runs Java web applications.
Browser
↓
Tomcat
↓
Servlet
↓
Application
Tomcat is therefore not Java. It is software that runs Java web applications.
JSP
Developers also needed a convenient way to generate HTML dynamically.
JSP (JavaServer Pages) allowed HTML pages to contain dynamic server-side content.
The older Java web world therefore looked roughly like:
Browser
↓
Tomcat
↓
Servlet
↓
JSP
↓
HTML
This worked, but as applications became larger, managing all the components and configuration became difficult.
That created the need for a better application framework.
3. Spring: Managing Complexity
Spring came with a different focus:
How do we build large Java applications without tightly coupling everything together?
One of its central ideas is Dependency Injection.
Instead of every component creating and managing all of its dependencies, Spring can manage those components and connect them together.
Conceptually:
Spring
↓
Manages application components
↓
Connects their dependencies
Spring wasn't just a web framework. It became a large ecosystem for building enterprise applications.
But we still needed a clean way to handle HTTP requests.
That led to Spring MVC.
4. Spring MVC: Bringing Structure to Web Applications
Spring MVC is Spring's web framework based on the Servlet model.
Instead of putting all the web logic into Servlets, Spring provides a structured model:
HTTP Request
↓
Spring MVC
↓
Controller
↓
Service
↓
Repository
The important thing to understand is the relationship:
Tomcat
↓
Servlet infrastructure
↓
Spring MVC
↓
Your application
Spring MVC didn't replace Tomcat.
It uses the Servlet infrastructure provided by containers such as Tomcat.
Now we had a cleaner way to build web applications.
But there was another major problem:
How do we work with databases?
5. Java and Databases: JDBC, JPA and Hibernate
Java needs a way to communicate with relational databases.
JDBC
JDBC (Java Database Connectivity) is the basic Java API for communicating with databases.
Java Application
↓
JDBC
↓
Database
But there is a mismatch.
Our application works with objects:
Customer
Order
Account
while a relational database works with tables:
CUSTOMER
ORDER
ACCOUNT
This is where ORM (Object-Relational Mapping) comes in.
ORM maps objects to database tables.
Hibernate
Hibernate is one of the most widely used Java ORM frameworks.
Java Objects
↕
Hibernate
↕
Database Tables
JPA
Then comes another confusing term:
JPA is a specification; Hibernate is an implementation of that specification.
Think of it like:
JPA
↓
Defines the standard
Hibernate
↓
Implements the standard
Modern Java applications often use JPA APIs with Hibernate underneath.
Spring then adds another layer:
Spring Data JPA
Spring Data JPA simplifies working with JPA.
The stack becomes:
Application
↓
Spring Data JPA
↓
JPA
↓
Hibernate
↓
JDBC
↓
Database
At this point we have web handling, application architecture and database persistence.
But there was still a problem:
There was a lot to configure.
6. Spring Boot: Putting It Together
Spring Boot was created to make Spring applications easier to configure, run and deploy.
It introduced things such as:
- Auto-configuration
- Starters
- Embedded servers
- Executable JARs
- Production-oriented configuration
One particularly important change was embedded Tomcat.
Traditionally:
Tomcat
↓
myapp.war
You installed Tomcat and deployed your application into it.
With Spring Boot:
myapp.jar
can contain:
Your Application
Spring Boot
Spring
Embedded Tomcat
Other Dependencies
So you can simply run:
java -jar myapp.jar
The application starts its embedded Tomcat itself.
Conceptually:
JVM
↓
Spring Boot
├── Your Application
└── Embedded Tomcat
This made Java applications much more self-contained.
A modern Spring Boot application might therefore look like:
HTTP Request
↓
Embedded Tomcat
↓
Spring MVC
↓
Controller
↓
Service
↓
Spring Data JPA
↓
Hibernate
↓
JDBC
↓
Database
Now we have an application.
But how do we build and deploy it?
7. From JAR to Production: Maven, Docker and Kubernetes
Maven / Gradle
Maven and Gradle are build and dependency management tools.
They can:
Source Code
↓
Compile
↓
Test
↓
Package
↓
application.jar
They also download and manage libraries such as Spring, Hibernate and database drivers.
Docker
Now we can package the application into a container.
Docker Container
│
├── Java Runtime
└── application.jar
The application can then run consistently across environments.
Kubernetes
Running one container is easy.
Running hundreds of containers across many servers is not.
Kubernetes manages containers at scale.
Kubernetes
↓
Containers
↓
Spring Boot Applications
↓
Java
Platforms such as OpenShift build an enterprise platform around Kubernetes.
Putting Everything Together
The modern Java application stack can now be understood as layers:
User / Client
│
HTTP
│
▼
┌─────────────────┐
│ Embedded Tomcat │
└────────┬────────┘
│
▼
Spring MVC
│
▼
Application
│
▼
Spring Data JPA
│
▼
JPA
│
▼
Hibernate
│
▼
JDBC
│
▼
Database
And around the application:
Developer
↓
Maven / Gradle
↓
Spring Boot JAR
↓
Docker Image
↓
Container
↓
Kubernetes / OpenShift
↓
Production
Underneath everything:
Operating System
↓
JVM
↓
Java
The Big Picture
The Java ecosystem makes much more sense when you stop looking at the technologies as independent names.
They represent an evolution:
Java gave us a portable programming platform.
Servlets gave Java a standard way to handle web requests.
Tomcat provided an environment to run those web applications.
JSP helped generate dynamic web pages.
Spring helped manage the complexity of large applications.
Spring MVC provided a structured web architecture.
JDBC connected Java to databases.
JPA standardized persistence.
Hibernate implemented ORM.
Spring Data JPA simplified database access.
Spring Boot brought these pieces together and made applications easier to configure and run.
Maven/Gradle build the application.
Docker packages it.
Kubernetes/OpenShift manages it in production.
Once you see the evolution, the Java ecosystem stops looking like a collection of random technologies.
It becomes a chain of solutions:
A problem appeared → a technology solved it → that solution created new possibilities → the next layer evolved.
And that is probably the simplest way to understand Java.