Spring Boot Fundamentals (Deep dive for beginners)



This content originally appeared on DEV Community and was authored by Jack Pritom Soren

Welcome — this is Chapter 1 of a beginner-friendly, deep-dive mini-course on Spring Boot. We’ll cover everything you need to get started: what Spring Boot is, how to install Java/IntelliJ/Maven on Windows/Ubuntu/macOS, creating a project (Spring Initializr + IntelliJ), Maven basics, the standard project structure, how @SpringBootApplication works (IOC / DI), and a step-by-step REST API CRUD example using Spring Boot + H2. I’ll keep explanations concrete and show small, copy-pasteable code examples.

What is Spring Boot? (short deep dive)

Spring Boot is an opinionated framework built on top of the Spring ecosystem that makes it fast and straightforward to build production-ready applications. It:

  • Auto-configures components for common use-cases so you don’t write boilerplate configuration.
  • Provides starters (e.g., spring-boot-starter-web) that bring together common dependencies.
  • Runs with an embedded server (Tomcat by default) so you can run apps as standalone JARs.
  • Includes developer conveniences (DevTools), metrics and health checks (Actuator), and easy packaging via Maven/Gradle plugins.

Why use Spring Boot? it lets you focus on business logic instead of wiring up servers, servlet containers, or complicated XML configs.

Prerequisites for this chapter

  • Basic familiarity with Java (classes, annotations).
  • A computer (Windows / Ubuntu / macOS).
  • Terminal/command-line comfort.
  • We’ll use Java 17+ (LTS) or newer. Spring Boot 3+ requires Java 17+.

1. Install Java & IntelliJ (Windows / Ubuntu / macOS)

Below are practical, stable options. After each install, verify with java -version.

Windows (recommended)

  1. Download JDK
  • Go to Eclipse Temurin / Adoptium / Oracle and download the Windows x64 installer for Java 17+ (Temurin is free and commonly used).
  • Run the installer and follow steps.
  1. Set JAVA_HOME (if installer didn’t)
  • Open System Properties → Advanced → Environment Variables.
  • Add JAVA_HOME = C:\Program Files\...temurin-17... (path where JDK installed).
  • Add %JAVA_HOME%\bin to Path.
  1. Install IntelliJ IDEA
  • Download IntelliJ Community (free) or Ultimate (paid) from JetBrains and run the installer.
  • Alternatively use Windows package managers: winget or choco (if you use them).
  1. Verify
   java -version

Ubuntu / Debian (recommended commands)

  1. Install OpenJDK 17 (example)
   sudo apt update
   sudo apt install openjdk-17-jdk -y

Or use SDKMAN to manage versions (recommended if you try many versions):

   curl -s "https://get.sdkman.io" | bash
   source "$HOME/.sdkman/bin/sdkman-init.sh"
   sdk install java 17.0.8-tem
  1. Install IntelliJ
  • Snap:

     sudo snap install intellij-idea-community --classic
    
  • Or use JetBrains Toolbox app.

  1. Verify
   java -version

macOS

  1. Install JDK (Homebrew or SDKMAN)
  • Homebrew (Temurin):

     brew install --cask temurin
    
  • SDKMAN:

     curl -s "https://get.sdkman.io" | bash
     sdk install java 17.0.8-tem
    
  1. Install IntelliJ
  • Homebrew:

     brew install --cask intellij-idea-ce
    
  • Or download from JetBrains site / Toolbox.

  1. Verify
   java -version

2. Install Maven (Windows / Ubuntu / macOS)

Maven builds Java projects and is the most common build tool for Spring Boot (Maven or Gradle both supported).

Ubuntu

sudo apt update
sudo apt install maven -y
mvn -v

macOS

brew install maven
mvn -v

Windows

  • Download binary from Apache Maven site, extract, set MAVEN_HOME, and add %MAVEN_HOME%\bin to Path.
  • Or use package managers: choco install maven or winget.

Verify

mvn -v

3. Download a Spring Boot project from Spring Initializr

Option A — Web UI (easy)

  1. Open https://start.spring.io
  2. Choose:
  • Project: Maven Project
  • Language: Java
  • Spring Boot: choose a stable 3.x version.
  • Project Metadata: Group (e.g. com.example), Artifact (e.g. student-api)
  • Packaging: Jar (default)
  • Java: 17 or later

    1. Add dependencies, e.g.:
  • Spring Web (for REST)

  • Spring Data JPA (for DB)

  • H2 Database (in-memory for quick testing)

  • optional: Lombok, Spring Boot DevTools, Validation

    1. Click Generate → download a ZIP.

Option B — IntelliJ New Project (Spring Initializr integration)

  • File → New → Project → choose Spring Initializr → fill details → pick dependencies → Finish. IntelliJ will generate the project and open it.

4. Create / Import the Spring Boot project in IntelliJ

From ZIP:

  1. File → Open → select extracted folder containing pom.xml.
  2. IntelliJ will import Maven project and download dependencies.

New Project (built-in):

  1. File → New → Project → Spring Initializr.
  2. Fill Group/Artifact, pick Java version and dependencies.
  3. Finish → project created and ready.

IntelliJ has a Run green triangle next to the main class. Use it to run the app.

5. What is Maven and how it works with Java & Spring Boot? (deep dive)

Maven is a build automation and dependency management tool.

  • POM (pom.xml): Project Object Model — defines project coordinates (groupId, artifactId, version), dependencies, build plugins, and configuration.
  • Lifecycle: validatecompiletestpackageinstalldeploy. mvn package creates the JAR, mvn install installs it in the local Maven repo (~/.m2/repository).
  • Repositories: Maven resolves dependencies from remote repositories (Maven Central) into your local repo. Transitive dependency resolution means a dependency’s dependencies are fetched automatically.
  • Plugins: e.g., spring-boot-maven-plugin builds executable JAR/WAR and handles repackage steps.

How Spring Boot uses Maven:

  • Spring Boot projects typically use the spring-boot-starter-parent in the POM or the Spring Boot dependency management plugin. This parent sets sensible defaults (dependency versions, plugin config).
  • The spring-boot-starter-* dependencies are meta-dependencies — they pull in the libraries you need (e.g., spring-boot-starter-web brings Spring MVC + Tomcat).
  • spring-boot-maven-plugin provides mvn spring-boot:run and the mechanism to create an executable jar with the embedded server.

Minimal pom.xml snippet (illustrative)

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.1.0</version> <!-- example -->
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

6. Structure of a Spring Boot application (what’s inside)

Typical file/directory layout:

student-api/
 ├─ pom.xml
 └─ src/
    ├─ main/
    │  ├─ java/
    │  │   └─ com/example/studentapi/
    │  │       ├─ StudentApiApplication.java   <-- main class
    │  │       ├─ controller/
    │  │       ├─ service/
    │  │       └─ repository/
    │  └─ resources/
    │      ├─ application.properties
    │      ├─ static/
    │      └─ templates/
    └─ test/
       └─ java/

Important files:

  • pom.xml: build & deps.
  • src/main/java/...Application.java: main() bootstraps Spring.
  • application.properties or application.yml: runtime config (datasource, server port, logging).
  • src/main/resources/static and templates: for web assets / server-side templates.
  • src/test/java: tests.

Note: Place the main application class in a root package so component scanning picks up controllers/services in subpackages. For example, com.example.studentapi.StudentApiApplication will @ComponentScan under com.example.studentapi.*.

7. @SpringBootApplication — internal working (IOC container & dependency injection)

@SpringBootApplication is a meta-annotation that expands to:

@Configuration
@EnableAutoConfiguration
@ComponentScan

What that means:

  • @Configuration — marks the class as a source of bean definitions.
  • @EnableAutoConfiguration — asks Spring Boot to automatically configure beans based on the classpath (e.g., if Spring MVC is on the classpath, it configures a DispatcherServlet). Spring Boot provides many auto-configuration classes; it tries to configure what you need.
  • @ComponentScan — tells Spring to scan the package where the main class resides and its subpackages for Spring components: @Controller, @Service, @Repository, @Component, etc.

SpringApplication.run():

  • Creates an ApplicationContext (the IOC container).
  • Scans components and registers beans.
  • Applies auto-configurations based on @Conditional rules and available classes.
  • Starts the embedded servlet container (for web apps).
  • Calls lifecycle callbacks (e.g., @PostConstruct).

IOC container & Dependency Injection (DI):

  • The ApplicationContext holds bean definitions and manages lifecycle (creation, dependency injection, destruction).

  • Injection styles:

    • Constructor injection (recommended):
    @Service
    public class StudentService {
      private final StudentRepository repo;
      public StudentService(StudentRepository repo) {
        this.repo = repo;
      }
    }
    
    • Field injection (not recommended):
    @Autowired
    private StudentRepository repo;
    
    • Setter injection: setter methods annotated with @Autowired.
  • Bean Scopes:

    • singleton (default): one instance per ApplicationContext.
    • prototype: new instance each request.
    • others exist for web contexts (request, session).

Important: Prefer constructor injection — it makes code easier to test and avoids nulls.

8. Create a REST API using Spring Boot — CRUD example (step-by-step)

We’ll build a simple Student CRUD API with H2 (in-memory) and Spring Data JPA.

1) Project setup

Create project with dependencies:

  • spring-boot-starter-web
  • spring-boot-starter-data-jpa
  • com.h2database:h2
  • (optional) spring-boot-devtools, lombok

Example pom.xml (core parts only):

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.1.0</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

2) application.properties (simple)

src/main/resources/application.properties

spring.datasource.url=jdbc:h2:mem:studentsdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
  • ddl-auto=update creates tables automatically (good for dev).
  • H2 console available at /h2-console when app runs.

3) Main application class

StudentApiApplication.java

package com.example.studentapi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentApiApplication {
  public static void main(String[] args) {
    SpringApplication.run(StudentApiApplication.class, args);
  }
}
  • @SpringBootApplication triggers component scanning and auto-configuration.

4) Entity

Student.java

package com.example.studentapi.model;

import jakarta.persistence.*;

@Entity
@Table(name = "students")
public class Student {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(nullable = false)
  private String name;

  private String address;
  private String phone;

  // Constructors
  public Student() {}
  public Student(String name, String address, String phone) {
    this.name = name;
    this.address = address;
    this.phone = phone;
  }

  // Getters and setters...
  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }
  public String getAddress() { return address; }
  public void setAddress(String address) { this.address = address; }
  public String getPhone() { return phone; }
  public void setPhone(String phone) { this.phone = phone; }
}

Note: I used jakarta.persistence.* as modern Spring Boot uses Jakarta packages.

5) Repository

StudentRepository.java

package com.example.studentapi.repository;

import com.example.studentapi.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
  // Spring Data JPA provides CRUD methods automatically
}

6) Service (optional but good practice)

StudentService.java

package com.example.studentapi.service;

import com.example.studentapi.model.Student;
import com.example.studentapi.repository.StudentRepository;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class StudentService {
  private final StudentRepository repo;
  public StudentService(StudentRepository repo) { this.repo = repo; }

  public Student create(Student s) { return repo.save(s); }
  public List<Student> findAll() { return repo.findAll(); }
  public Optional<Student> findById(Long id) { return repo.findById(id); }
  public Student update(Long id, Student s) {
    s.setId(id);
    return repo.save(s);
  }
  public void delete(Long id) { repo.deleteById(id); }
}

7) Controller (REST endpoints)

StudentController.java

package com.example.studentapi.controller;

import com.example.studentapi.model.Student;
import com.example.studentapi.service.StudentService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/api/students")
public class StudentController {
  private final StudentService service;
  public StudentController(StudentService service) { this.service = service; }

  @PostMapping
  public ResponseEntity<Student> create(@RequestBody Student s) {
    Student created = service.create(s);
    return ResponseEntity.created(URI.create("/api/students/" + created.getId())).body(created);
  }

  @GetMapping
  public List<Student> all() { return service.findAll(); }

  @GetMapping("/{id}")
  public ResponseEntity<Student> getById(@PathVariable Long id) {
    return service.findById(id)
      .map(ResponseEntity::ok)
      .orElse(ResponseEntity.notFound().build());
  }

  @PutMapping("/{id}")
  public ResponseEntity<Student> update(@PathVariable Long id, @RequestBody Student s) {
    // simple approach: set id and save
    Student updated = service.update(id, s);
    return ResponseEntity.ok(updated);
  }

  @DeleteMapping("/{id}")
  public ResponseEntity<Void> delete(@PathVariable Long id) {
    service.delete(id);
    return ResponseEntity.noContent().build();
  }
}

8) Run the app

From IntelliJ: click the Run icon on StudentApiApplication.
Or from terminal:

mvn spring-boot:run

Application will start (default http://localhost:8080).

9) Test with curl (examples)

  • Create:
curl -X POST http://localhost:8080/api/students \
  -H "Content-Type: application/json" \
  -d '{"name":"Aisha","address":"Dhaka","phone":"+8801..."}'
  • Get all:
curl http://localhost:8080/api/students
  • Get by id:
curl http://localhost:8080/api/students/1
  • Update:
curl -X PUT http://localhost:8080/api/students/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"Aisha Updated","address":"Dhaka","phone":"0123"}'
  • Delete:
curl -X DELETE http://localhost:8080/api/students/1

You can also use Postman / Insomnia / HTTPie.

9. Explanation: each key file and why it matters (quick line-by-line highlights)

  • StudentApiApplication.java — launches Spring, triggers auto-configuration and component scanning.
  • pom.xml — defines dependencies and spring-boot-maven-plugin so mvn spring-boot:run and mvn package produce runnable JAR.
  • application.properties — runtime settings (DB URL, logging, port). Changing spring.jpa.hibernate.ddl-auto impacts schema generation.
  • @Entity Student — JPA entity mapping. @Id + @GeneratedValue controls primary key generation.
  • StudentRepository — Spring Data JPA gives you save(), findAll(), findById(), deleteById() — no boilerplate SQL.
  • StudentService — encapsulates business logic and interacts with repository (keeps controller thin).
  • StudentController — exposes REST endpoints and maps HTTP verbs to CRUD operations.

10. Common pitfalls & debugging tips

  • Java version mismatch: If runtime complains about class file version, ensure java -version matches JDK used to compile.
  • Port in use: server.port=8080 can be changed in application.properties.
  • Dependency issues: Run mvn clean package and check for conflicting versions. Spring Boot parent usually manages versions for you.
  • H2 console not accessible: verify spring.h2.console.enabled=true and use correct JDBC URL jdbc:h2:mem:studentsdb.
  • Lombok problems: If using Lombok, enable annotation processing in IntelliJ (Preferences → Build, Execution, Deployment → Compiler).

Short checklist to run the example right now

  1. Java 17+ installed and java -version OK.
  2. Maven installed and mvn -v OK.
  3. Create Spring Boot project from start.spring.io or IntelliJ with dependencies: Web, JPA, H2.
  4. Paste entity/repository/service/controller code shown above.
  5. application.properties as provided.
  6. Run mvn spring-boot:run and test with curl.

Follow me on : Github Linkedin Threads Youtube Channel


This content originally appeared on DEV Community and was authored by Jack Pritom Soren