Skip to content

Latest commit

Β 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸƒ learning-spring-boot

Three isolated Spring Boot environments, one repository.

Coursework, personal experiments and the graded project β€” each in its own container, on its own ports, running side by side without ever clashing.

Java Spring Boot Maven Docker Dev Containers

English Β· PortuguΓͺs πŸ‡§πŸ‡·


πŸ“š Table of contents


🎯 Why three environments

Study code, assignments and a graded project have different needs. Mixing them in one workspace means the graded project drowns in scratch files, and a broken experiment can take down the thing being submitted.

So each lives in its own container:

Folder What goes here Tooling
πŸŽ“ class-content/ Lecture notes and assigned exercises minimal
πŸ§ͺ playground/ Personal research, outside coursework full
πŸš€ projects/ The graded college project full

Minimal is JDK 21, Maven, git and curl β€” nothing more, so nothing distracts from the exercise.

Full adds database clients (psql, mysql, redis-cli), network tools (netcat, dig, ping), jq, httpie, ripgrep, tree, graphviz and editors.


πŸ“‚ Repository layout

learning-spring-boot/
β”‚
β”œβ”€β”€ πŸŽ“ class-content/          Minimal environment
β”‚   β”œβ”€β”€ theory/                Lecture notes and reference material
β”‚   └── exercises/             One Maven project per assignment
β”‚       └── challange-01/      Games API β€” see its own README
β”‚
β”œβ”€β”€ πŸ§ͺ playground/             Full environment β€” throwaway experiments
β”‚
β”œβ”€β”€ πŸš€ projects/               Full environment β€” the graded project
β”‚
β”œβ”€β”€ 🐳 docker/
β”‚   β”œβ”€β”€ Dockerfile             Multi-stage: base Β· full Β· build Β· production
β”‚   β”œβ”€β”€ docker-compose.yml     The three dev services + the production one
β”‚   └── docker-compose.override.yml   Optional NVIDIA GPU reservation
β”‚
└── βš™οΈ  .devcontainer/
    β”œβ”€β”€ class-content/         One devcontainer definition per environment
    β”œβ”€β”€ playground/
    └── projects/

Every folder also carries a CLAUDE.md with instructions specific to it.


πŸ”Œ Ports

Environment App Debugger Docker stage
πŸŽ“ class-content 8082 5005 base
πŸš€ projects 8083 5007 full
πŸ“¦ projects (production image) 8084 β€” production
πŸ§ͺ playground 8085 5006 full

⚠️ Host ports vs. container ports

Those are ports on your machine. Inside every container the app always listens on 8081 and the debugger on 5005. Nothing in the Java code or in application.properties mentions 8082/8083/8085 β€” the remap exists purely so all three can run at once, and is defined only in docker-compose.yml.

The one place the host port matters is a front-end: the browser runs on your machine, so fetch calls and the API's CORS config must use the host port, not 8081.


πŸ›  Requirements

  • 🐳 Docker β€” Docker Desktop on Windows or macOS, Docker Engine on Linux
  • πŸ’» VS Code with the Dev Containers extension, for the devcontainer workflow

Nothing else. Java and Maven live inside the containers β€” no local JDK needed.


πŸš€ Quick start

Option A β€” VS Code Dev Containers (recommended)

  1. Open the repository in VS Code
  2. Run Dev Containers: Reopen in Container from the command palette (F1)
  3. Pick the environment you want to work in
  4. In the container terminal, start the app:
mvn spring-boot:run

The Java extensions and the Maven cache come preconfigured.

Option B β€” plain Docker Compose

# Start all three dev environments
docker compose -f docker/docker-compose.yml up -d

# Open a shell in one of them
docker exec -it learning-spring-boot-projects bash

# Then, inside:
mvn spring-boot:run

πŸ’‘ Nothing starts by itself

Containers idle on purpose β€” they do not launch an app on their own, so you decide when something starts. They carry no healthcheck and simply show Up; only the production service is health-checked.

Closing a devcontainer window also leaves the containers running, so the other environments are not disturbed. Stop everything with docker compose -f docker/docker-compose.yml down.


🧰 Everyday commands

Run these inside a container, from the folder holding the pom.xml:

Command What it does
mvn spring-boot:run Start the app on port 8081 (container-side)
mvn test Run unit tests
mvn verify Tests plus configured lint and coverage
mvn clean package Build the jar into target/
mvn dependency:tree Inspect the dependency graph
jshell Java REPL β€” quick experiments with no project

From your machine:

Command What it does
docker compose -f docker/docker-compose.yml up -d Start all environments
docker compose -f docker/docker-compose.yml down Stop them
docker compose -f docker/docker-compose.yml build --no-cache Rebuild images from scratch
docker compose -f docker/docker-compose.yml logs -f projects Follow one service's logs
docker ps See status and health of every container

🐞 Debugging

No installation needed β€” the JDWP agent ships with the JVM, so remote debugging works in every environment, including the minimal one. This is unlike Python, where you would pip install debugpy first.

Start the app with the debug flag:

mvn spring-boot:run -Dspring-boot.run.jvmArguments="$JAVA_DEBUG_OPTS"

$JAVA_DEBUG_OPTS is preset in the image and opens port 5005 inside the container. Then attach your IDE to the host debug port for that folder:

// .vscode/launch.json β€” adjust the port per environment
{
  "type": "java",
  "name": "Attach to container",
  "request": "attach",
  "hostName": "localhost",
  "port": 5007        // 5005 class-content Β· 5006 playground Β· 5007 projects
}

Also available inside any container, straight from the JDK:

Tool Use
jdb Command-line debugger
jstack <pid> Thread dump β€” find deadlocks
jmap <pid> Heap dump β€” chase memory leaks
jcmd <pid> Thread.print Live JVM commands
jfr Java Flight Recorder β€” profiling

βœ… Testing and code quality

Java has no system-installed equivalent of pytest or pylint. The tools are Maven dependencies and plugins declared per project, which means adding them never requires rebuilding the Docker image.

Role Java tool Python analogue Declared in
Test runner JUnit 5 pytest <dependencies>
Assertions / mocks AssertJ, Mockito β€” bundled with the starter
Controller tests MockMvc β€” bundled with the starter
Real DBs in tests Testcontainers β€” <dependencies>
Style Checkstyle pylint <plugins>
Static analysis SpotBugs, PMD pylint <plugins>
Coverage JaCoCo coverage.py <plugins>

JUnit, AssertJ, Mockito and MockMvc all arrive together through a single dependency:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
mvn test      # unit tests only
mvn verify    # tests + lint + coverage

πŸ“¦ Production image

projects/ can also be built as a lean runtime image, for when the graded project has to be delivered or deployed:

  • πŸͺΆ JRE only, Alpine based β€” no Maven, no git, no compiler
  • πŸ”’ Non-root user
  • ⚑ Starts the jar directly via ENTRYPOINT, no build step at runtime
  • 🧠 -XX:MaxRAMPercentage=75.0, so the JVM respects the container's memory limit

It compiles during the image build, so it needs a working pom.xml in projects/ first. Until then it stays behind a Compose profile and is skipped by a plain up:

docker compose -f docker/docker-compose.yml --profile prod up projects-prod

Served on host port 8084, and it is the only service that becomes healthy without you starting anything.


🐳 How the Docker setup works

One multi-stage Dockerfile produces every image. The stages inherit from each other, so the JDK is installed once and shared:

base ──────────► full ──────────► build ──────────► production
JDK 21           + db clients      copies source     JRE only
Maven, git       + net tools       runs the build    non-root
curl             + jq, httpie…     (internal)        runs the jar

   β–²                  β–²                                  β–²
   β”‚                  β”‚                                  β”‚
class-content   playground, projects                projects-prod

Two details worth knowing before editing anything:

  • πŸ“ The build context is the project root, not docker/. COPY paths in the Dockerfile are relative to the root.
  • πŸ” docker-compose.override.yml is merged automatically by that exact filename. It only reserves an NVIDIA GPU and is inert without one. Skip it with docker compose -f docker/docker-compose.yml up.

πŸ”§ Troubleshooting

Symptom Cause Fix
port is already allocated Something on the host already uses 8082–8085 Free the port, or change the host side in docker-compose.yml
Debugger will not attach App started without the debug flag Restart with -Dspring-boot.run.jvmArguments="$JAVA_DEBUG_OPTS"
Maven re-downloads everything The maven-cache volume was removed Normal on first run; it repopulates
Front-end gets a CORS error CORS allows 8081 instead of the host port Allow http://localhost:8083 (or the relevant host port)

❓ FAQ

Why different host ports instead of 8081 everywhere?

Two processes cannot bind the same host port. With all three mapped to 8081:8081, only one could run at a time and the others would fail with port is already allocated. Splitting the host side lets you run an exercise and your own version of it side by side β€” while inside the containers everything stays on the canonical 8081.

Why one Dockerfile instead of one per folder?

All three environments are Java 21 + Spring Boot; they differ only in how much tooling is installed. Multi-stage handles exactly that: the JDK layer is built once and shared, and there is no risk of three files drifting to different Java versions. Splitting only makes sense when the runtimes genuinely diverge.

Why isn't Checkstyle or JUnit installed in the image?

In Java they cannot be. There is no apt install junit that a build would use β€” they are artifacts Maven resolves from a pom.xml. Keeping them there means adding a tool is a one-line edit with no image rebuild.

Why does class-content get a debug port if it is the "minimal" environment?

Because debugging costs nothing to include: JDWP is part of the JVM, not an add-on. And coursework exercises are exactly where stepping through a breakpoint teaches the most.

Do I need Java installed on my machine?

No. The JDK, Maven and every tool live inside the containers. Docker is the only requirement.

About

This repository documents my journey learning Spring Boot framework. It's organized into class exercises, isolated experiments, and personal projects, each running in its own Dockerized environment.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages