Skip to main content

Spring Boot Quickstart

Spring Boot is an opinionated framework that simplifies the creation of stand-alone, production-grade Spring-based applications. It takes the “convention over configuration” approach.

1. The Magic of Spring Initializr

You rarely start a Spring project from scratch. You use the Spring Initializr.
  1. Go to start.spring.io
  2. Project: Maven / Gradle (We’ll use Maven for this course)
  3. Language: Java
  4. Spring Boot: 3.x.x (Latest stable)
  5. Project Metadata:
    • Group: com.devweekends
    • Artifact: demo
    • Packaging: Jar
    • Java: 17
  6. Dependencies (Add these):
    • Spring Web: For building REST APIs (uses Tomcat as default embedded server).
    • Spring Boot DevTools: For fast feedback loops (auto-restart).
    • Lombok: To reduce boilerplate code.
Click GENERATE, unzip the project, and open it in your IDE (IntelliJ or VS Code).

2. Project Structure

src/
├── main/
│   ├── java/
│   │   └── com/devweekends/demo/
│   │       └── DemoApplication.java  <-- Entry Point
│   └── resources/
│       ├── application.properties    <-- Configuration
│       ├── static/                   <-- Static assets (JS/CSS)
│       └── templates/                <-- Server-side templates (Thymeleaf)

The Entry Point

package com.devweekends.demo;

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

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
The @SpringBootApplication annotation is a convenience annotation that adds all of the following:
  • @Configuration: Tags the class as a source of bean definitions.
  • @EnableAutoConfiguration: Tells Spring Boot to start adding beans based on classpath settings (e.g., if spring-web is on the classpath, setup Tomcat).
  • @ComponentScan: Tells Spring to look for other components, configurations, and services in the com/devweekends/demo package.

3. Your First REST Controller

Create a new file HelloController.java next to DemoApplication.java.
package com.devweekends.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, Dev Weekends!";
    }
}
  • @RestController: Marks this class as a request handler where every method returns a domain object directly (JSON/XML) instead of a view.
  • @GetMapping("/hello"): Maps HTTP GET requests to /hello to the sayHello() method.

4. Running the Application

In your terminal (or IDE):
./mvnw spring-boot:run
You should see logs starting with the Spring banner. Look for: Tomcat started on port(s): 8080 (http) Open http://localhost:8080/hello in your browser. You should see “Hello, Dev Weekends!“.

5. Dependency Injection (DI) Basics

Spring’s core is the Application Context (the IoC container). It manages the lifecycle of your objects (Beans). Instead of new Service(), you ask Spring to give you an instance.
@Service // 1. Register this class as a Bean
public class GreetingService {
    public String getGreeting() {
        return "Welcome to Spring Boot Mastery";
    }
}

@RestController
public class HelloController {

    private final GreetingService greetingService;

    // 2. Constructor Injection (Recommended)
    public HelloController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/greet")
    public String greet() {
        return greetingService.getGreeting();
    }
}
This makes your code testable and loosely coupled.

6. Spring Boot Internals: How it Works

Many developers use @SpringBootApplication without knowing what it does. It’s a compound annotation:
  1. @SpringBootConfiguration: Just a specialized @Configuration.
  2. @ComponentScan: Scans the current package and sub-packages for Components.
  3. @EnableAutoConfiguration: The Magic.

How Auto-Configuration Works

Spring Boot looks at the classpath.
  • Is spring-webmvc on the classpath? -> Configure DispatcherServlet.
  • Is h2 on the classpath? -> Configure DataSource.
  • Is hibernate-core on the classpath? -> Configure EntityManagerFactory.
It uses META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports to find configuration classes and applies them conditionally (@ConditionalOnClass, @ConditionalOnMissingBean).

7. Bean Scopes & Lifecycle

By default, all beans are Singletons (created once per app). But you can change this.

Scopes

  • Singleton (Default): One instance per container.
  • Prototype: A new instance every single time it is requested.
  • Request: One instance per HTTP Request.
  • Session: One instance per HTTP Session.
@Component
@Scope("prototype")
public class UserAction {
    // New instance created every time
}

Lifecycle Callbacks

Sometimes you need to run logic right after a bean is created (e.g., open a socket) or before it dies (e.g., close file).
@Component
public class DatabaseConnection {

    @PostConstruct
    public void init() {
        System.out.println("Bean created! Opening connection...");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("App shutting down! Closing connection...");
    }
}

8. Type-Safe Configuration

Stop using @Value("${my.config}"). Ideally, group related properties into a POJO. application.yml
app:
  mail:
    host: smtp.gmail.com
    port: 587
    enabled: true
Java Config Class
@ConfigurationProperties(prefix = "app.mail")
public record MailConfig(String host, int port, boolean enabled) {}
Enable it in Main Class
@SpringBootApplication
@EnableConfigurationProperties(MailConfig.class)
public class DemoApplication {}
Now you can inject MailConfig anywhere!

9. Deep Dive: The IoC Container

The Inversion of Control (IoC) container is the heart of Spring. It manages the lifecycle of your objects (Beans).

BeanFactory vs ApplicationContext

  • BeanFactory: The root interface. Provides basic features (DI). Lazy loading.
  • ApplicationContext: A sub-interface. Adds enterprise specific functionality:
    • Internationalization (i18n).
    • Event publishing.
    • Web application support.
    • Eager loading (instantiates singletons on startup), which is better for detecting errors early.
In Spring Boot, SpringApplication.run() returns an ApplicationContext.

10. Dependency Injection Patterns

How should you inject dependencies?

1. Field Injection (Avoid)

@Autowired
private UserService userService;
  • Pros: Concise.
  • Cons: Hides dependencies. Impossible to unit test without reflection/mocks. Creates circular dependency risks.

2. Setter Injection (Optional Deps)

@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}
  • Pros: Allows optional dependencies (can re-configure later).
  • Cons: Bean is not immutable.
private final UserService userService;

public UserController(UserService userService) {
    this.userService = userService;
}
  • Pros:
    • Immutability: Fields can be final.
    • Testability: Just pass mocks in new UserController(mockService).
    • Safety: Object is fully initialized before use.
    • Circular Dependency Detection: Fails fast at startup if A -> B -> A.

multiple Implementations? Use @Qualifier or @Primary

If you have SmsNotificationService and EmailNotificationService implementing NotificationService, Spring gets confused.
  • @Primary: The default choice.
  • @Qualifier("sms"): Specific choice injecting time.
public class CheckoutService {
    public CheckoutService(@Qualifier("sms") NotificationService sender) { ... }
}

11. Advanced Bean Lifecycle

It’s not just “Create -> Use -> Destroy”.

BeanPostProcessors (BPP)

These are hooks that allow you to modify beans before they are fully initialized. Example: How @Transactional works. Spring has a BPP that scans for @Transactional. If found, it wraps your bean in a Proxy (CGLIB or JDK Dynamic Proxy) before handing it to the container. The container never holds your actual class, only the Proxy!