23. Getting Started with Spring Boot
Spring Boot lives by **convention over configuration** — you get an **immediately-runnable web app** without dozens of XML lines. It bundles an embedded Tomcat, so `java -jar` launches a server in one line.
What you'll learn
- 1Know the project layout produced by Spring Initializr
- 2Understand the role of `@SpringBootApplication`
- 3Understand dependency injection (DI)
- 4Change basic settings (port, logs) in `application.properties`
- 5Run with `mvn spring-boot:run`
Overview
Spring Boot lives by **convention over configuration** — you get an **immediately-runnable web app** without dozens of XML lines. It bundles an embedded Tomcat, so `java -jar` launches a server in one line.
Core Concepts
1) Spring Initializr
Visit https://start.spring.io, pick **Maven**, **Java 21**, and the **Spring Web** starter, then download and unzip the project.
2) Project layout
demo/
├── pom.xml
└── src/main/java/com/example/demo/DemoApplication.java3) `@SpringBootApplication`
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}- `@SpringBootApplication` bundles `@Configuration` + `@EnableAutoConfiguration` + `@ComponentScan`
- `SpringApplication.run` boots the embedded Tomcat
4) First REST endpoint
import org.springframework.web.bind.annotation.*;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() { return "Hello, Spring!"; }
}Run, then `curl http://localhost:8080/hello` → `Hello, Spring!`
5) Dependency injection (DI)
@RestController
public class HelloController {
private final Greeter greeter;
public HelloController(Greeter greeter) { this.greeter = greeter; } // constructor injection
@GetMapping("/hello")
public String hello() { return greeter.greet("World"); }
}Spring creates one bean per `@Component`/`@Service`/etc. and injects them via constructor parameters.
6) `application.properties`
# src/main/resources/application.properties
server.port=8081
logging.level.org.springframework=WARNExamples
Example 1 — `DemoApplication.java`
package com.example.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);
}
}Example 2 — `HelloController.java`
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() { return "Hello, Spring Boot!"; }
}mvn spring-boot:run
# → http://localhost:8080/hello
curl http://localhost:8080/helloExample 3 — Constructor-injected service
import org.springframework.stereotype.Service;
@Service
public class Greeter {
public String greet(String name) { return "Hi, " + name + "!"; }
}
@RestController
class GreetController {
private final Greeter greeter;
GreetController(Greeter greeter) { this.greeter = greeter; }
@GetMapping("/greet/{name}")
public String greet(@PathVariable String name) { return greeter.greet(name); }
}Example 4 — `application.properties`
server.port=8081
spring.application.name=demo
logging.level.root=INFOCommon Mistakes
- Putting your code in the **wrong package** — Spring scans only the package tree of `@SpringBootApplication`
- Forgetting `@RestController` and returning a String — Spring tries to resolve it as a view name
- Confusing `@Controller` (returns view names) with `@RestController` (returns the body directly)
- Hard-coding `localhost:8080` in clients instead of using a config
- Using field injection (`@Autowired` on a field) — constructor injection is preferred
Summary
- Spring Boot = convention over configuration → an executable web app in seconds
- `@SpringBootApplication` bootstraps everything
- Use constructor injection — it documents required dependencies
Practice
# Practice - 23. Getting Started with Spring Boot
## Exercise 1 — Generate a project
- Use Spring Initializr to create `demo` with Spring Web.
- Add `/ping` returning `pong` and run with `mvn spring-boot:run`.
Expected
$ curl http://localhost:8080/ping
pong## Exercise 2 — Inject a service
- Add `@Service class Clock { String now() { return java.time.Instant.now().toString(); } }`.
- Inject into a controller and expose `/now`.
## Solutions After trying it yourself, compare with [`answer/`](./answer/).
Solution code (homework/answer/)
answer/PingController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PingController {
@GetMapping("/ping")
public String ping() { return "pong"; }
}
answer/NowController.java
package com.example.demo;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Service
class Clock {
String now() { return java.time.Instant.now().toString(); }
}
@RestController
class NowController {
private final Clock clock;
NowController(Clock clock) { this.clock = clock; }
@GetMapping("/now")
public String now() { return clock.now(); }
}
Try It Yourself
mvn spring-boot:run
curl http://localhost:8080/helloNext Lecture
[24_REST](../24_REST_컨트롤러/) — build a full REST API with `@RestController`.
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗