Ver2.0 ๐ฑ Spring Framework: ํต์ฌ ๊ฐ๋ ๊ณผ ์ํคํ ์ฒ ์์ ์ ๋ณต 2025 ๐ฑ

๐ฑ Spring Framework: ํต์ฌ ๊ฐ๋ ๊ณผ ์ํคํ ์ฒ ์์ ์ ๋ณต 2025 ๐ฑ
์๋ ํ์ธ์, ๊ฐ๋ฐ์ ์ฌ๋ฌ๋ถ! ๐ ์ค๋์ 2025๋ 3์ 15์ผ ๊ธฐ์ค์ผ๋ก ์ต์ Spring Framework์ ํต์ฌ ๊ฐ๋ ๊ณผ ์ํคํ ์ฒ์ ๋ํด ์์ ์ ๋ณตํด๋ณด๋ ์๊ฐ์ ๊ฐ์ ธ๋ณผ๊ฒ์. ์๋ฐ ๊ฐ๋ฐ์๋ผ๋ฉด ํ ๋ฒ์ฏค์ ๋ค์ด๋ดค์(์๋, ์ด๋ฏธ ์ฌ์ฉํ๊ณ ๊ณ์ค) Spring Framework! ์ด ๊ธ์ ํตํด Spring์ A๋ถํฐ Z๊น์ง ์ฝ๊ณ ์ฌ๋ฐ๊ฒ ์์๋ด์~
Spring์ ์๋ฐ ์ํฐํ๋ผ์ด์ฆ ๊ฐ๋ฐ์ ํธํ๊ฒ ํด์ฃผ๋ ์คํ์์ค ํ๋ ์์ํฌ๋ก, 2025๋ ํ์ฌ๊น์ง๋ ์๋ฐ ์ํ๊ณ์์ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ํ๋ ์์ํฌ ์ค ํ๋๋๋๋ค! โจ
๐ ๋ชฉ์ฐจ
- Spring Framework ์๊ฐ ๋ฐ ์ญ์ฌ
- Spring์ ํต์ฌ ์๋ฆฌ: IoC์ DI
- Spring์ ์ํคํ ์ฒ ๊ตฌ์กฐ
- Spring Boot์์ ๊ด๊ณ
- Spring์ ์ฃผ์ ๋ชจ๋ ์ดํด๋ณด๊ธฐ
- Spring MVC ์ํคํ ์ฒ
- Spring Data์ ๋ฐ์ดํฐ ์ก์ธ์ค
- Spring Security ๊ธฐ์ด
- Spring Cloud์ ๋ง์ดํฌ๋ก์๋น์ค
- Spring 6.0 ๋ฐ ์ต์ ํธ๋ ๋ (2025)
- ์ค์ Spring ํ๋ก์ ํธ ๊ตฌ์ฑ ํ
1. Spring Framework ์๊ฐ ๋ฐ ์ญ์ฌ ๐ฐ๏ธ
์ฌ๋ฌ๋ถ~ Spring์ด ์ด๋ป๊ฒ ํ์ํ๋์ง ์์ธ์? 2002๋ ์ Rod Johnson์ด๋ผ๋ ๊ฐ๋ฐ์๊ฐ ์์ ์ ์ฑ "Expert One-on-One J2EE Design and Development"์์ ์ฒ์ ์๊ฐํ์ด์. ๋น์ J2EE(์ง๊ธ์ Jakarta EE)๊ฐ ๋๋ฌด ๋ณต์กํ๊ณ ๋ฌด๊ฑฐ์์ ์ด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด ๋ง๋ค์ด์ก๋ต๋๋ค.
Spring์ ์ด๋ฆ์ ์ด๋์ ์์๊น์? ๋ฐ๋ก '๊ฒจ์ธ(J2EE์ ๋ณต์ก์ฑ)'์์ '๋ด(์๋ก์ด ์์)'์ผ๋ก ๋์ด๊ฐ๋ค๋ ์๋ฏธ์์ ์ง์ด์ก๋ค๊ณ ํด์. ์ผ์ค ์์ฃ ? ใ ใ ใ ๐ธ
2025๋ ํ์ฌ, Spring์ ๋จ์ํ DI ์ปจํ ์ด๋๋ฅผ ๋์ด ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ, ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ, ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ ๋ฑ ํ๋์ ์ธ ๊ฐ๋ฐ ํจ๋ฌ๋ค์์ ๋ชจ๋ ์ง์ํ๋ ์์ ์ฒด๋ก ์งํํ์ด์!
Spring์ด ์ด๋ ๊ฒ ์ค๋ซ๋์ ์ฌ๋๋ฐ๋ ์ด์ ๋ ๋ญ๊น์? ๋ฐ๋ก POJO(Plain Old Java Object) ๊ธฐ๋ฐ ๊ฐ๋ฐ์ ์งํฅํ๊ณ , ๋น์ฆ๋์ค ๋ก์ง์ ์ง์คํ ์ ์๊ฒ ํด์ฃผ๊ธฐ ๋๋ฌธ์ด์์. ๋ง์น ์ฌ๋ฅ๋ท์์ ๊ฐ์์ ์ฌ๋ฅ์ ์ง์คํ ์ ์๊ฒ ๋์์ฃผ๋ ๊ฒ์ฒ๋ผ์! ๐
2. Spring์ ํต์ฌ ์๋ฆฌ: IoC์ DI ๐งฉ
Spring์ ๊ฐ์ฅ ์ค์ํ ๊ฐ๋ ! ๋ฐ๋ก IoC(Inversion of Control, ์ ์ด์ ์ญ์ )๊ณผ DI(Dependency Injection, ์์กด์ฑ ์ฃผ์ )์ธ๋ฐ์. ์ด๊ฒ ๋ญ์ง ์ด๊ฐ๋จํ๊ฒ ์ค๋ช ํด๋ณผ๊ฒ์!
๐ค IoC๋?
์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋ฐ์๊ฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์กด์ฑ์ ์ฐ๊ฒฐํ๋ '์ ์ด๊ถ'์ ๊ฐ์ง๊ณ ์์ฃ . ํ์ง๋ง Spring์์๋ ์ด ์ ์ด๊ถ์ด ๊ฐ๋ฐ์์์ ํ๋ ์์ํฌ๋ก '์ญ์ '๋ฉ๋๋ค. ์ฆ, ๊ฐ์ฒด์ ์๋ช ์ฃผ๊ธฐ๋ฅผ Spring์ด ๊ด๋ฆฌํด์ค๋ค๋ ๊ฑฐ์์!
์ฝ๊ฒ ๋งํ๋ฉด "๋ด๊ฐ ํ์ํ ๊ฐ์ฒด๋ฅผ ์ง์ new๋ก ๋ง๋ค์ง ์๊ณ , Spring์ด ์์์ ๋ง๋ค์ด์ ๋ํํ ์ค!" ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ์. ใ ใ ใ
๐ DI๋?
DI๋ IoC๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ ์ค ํ๋์์. ๊ฐ์ฒด๊ฐ ํ์๋ก ํ๋ ์์กด์ฑ์ ์ธ๋ถ(Spring)์์ ์ฃผ์ ํด์ฃผ๋ ํจํด์ด์ฃ .
์๋ฅผ ๋ค์ด, ์นดํ์์ ์ปคํผ๋ฅผ ๋ง๋ค๋ ค๋ฉด ๋ฐ๋ฆฌ์คํ, ์๋, ๋ฌผ, ์ปต ๋ฑ์ด ํ์ํ์์์? ์ด๋ฐ '์์กด์ฑ'๋ค์ Spring์ด ์์์ ์ค๋นํด์ ์นดํ ๊ฐ์ฒด์ '์ฃผ์ 'ํด์ค๋ค๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค!
์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์ ํต์ ์ธ ๋ฐฉ์์์๋ Controller๊ฐ ์ง์ Service๋ฅผ ์์ฑ(new)ํ์ง๋ง, Spring์์๋ Container๊ฐ Bean์ ๊ด๋ฆฌํ๊ณ ํ์ํ ๊ณณ์ ์ฃผ์ ํด์ฃผ๋ ๊ฑธ ๋ณผ ์ ์์ด์!
์ด๋ฐ DI ํจํด ๋๋ถ์ ์ฝ๋์ ๊ฒฐํฉ๋๋ ๋ฎ์์ง๊ณ (๋์จํ ๊ฒฐํฉ), ํ ์คํธํ๊ธฐ ์ฌ์์ง๋ฉฐ, ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ด ๋์์ง๋ต๋๋ค! ๐
๐ป ์ฝ๋๋ก ๋ณด๋ DI ์์
// ์ ํต์ ์ธ ๋ฐฉ์
public class UserController {
private UserService userService = new UserServiceImpl(); // ๊ฐํ ๊ฒฐํฉ
// ๋ฉ์๋๋ค...
}
// Spring DI ๋ฐฉ์
@Controller
public class UserController {
private final UserService userService;
@Autowired // ์์ฑ์ ์ฃผ์
๋ฐฉ์
public UserController(UserService userService) {
this.userService = userService; // ๋์จํ ๊ฒฐํฉ
}
// ๋ฉ์๋๋ค...
}
2025๋ ํ์ฌ, Spring์์๋ ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ด ๊ฐ์ฅ ๊ถ์ฅ๋๋ ๋ฐฉ์์ด์์. ์๋ํ๋ฉด ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ๊ณ , ํ์ ์์กด์ฑ์ ๋ช ํํ ํ ์ ์๊ฑฐ๋ ์! ํ๋ ์ฃผ์ (@Autowired private Service service;)์ ์ด์ ๋ ๊ฑฐ์๋ก ์ทจ๊ธ๋ฐ๋ ์ถ์ธ๋๋๋ค. ์์๋์ธ์~ ๐
3. Spring์ ์ํคํ ์ฒ ๊ตฌ์กฐ ๐๏ธ
Spring Framework๋ ์ฝ 20๊ฐ์ ๋ชจ๋๋ก ๊ตฌ์ฑ๋์ด ์์ด์. ์ด ๋ชจ๋๋ค์ Core Container, Data Access/Integration, Web, AOP, Instrumentation, Test ๋ฑ์ ๋ ์ด์ด๋ก ๊ตฌ๋ถ๋ฉ๋๋ค.
์ ๊ทธ๋ฆผ์์ ๋ณผ ์ ์๋ฏ์ด, Spring์ ์ฌ๋ฌ ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋์ด ์์ด์. ๊ฐ ๋ ์ด์ด๋ ํน์ ๊ธฐ๋ฅ์ ๋ด๋นํ๋ฉฐ, ํ์ํ ๋ชจ๋๋ง ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ต๋๋ค. ์ด๋ฐ ๋ชจ๋์ ๊ตฌ์กฐ๊ฐ Spring์ ํฐ ์ฅ์ ์ค ํ๋์ฃ ! ๐งฉ
๐ฑ ์ฃผ์ ๋ชจ๋ ์ค๋ช
1. Core Container
Spring์ ํต์ฌ! IoC์ DI ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ชจ๋๋ค์ด ์ฌ๊ธฐ ์์ด์.
- Core: ๊ธฐ๋ณธ ์ ํธ๋ฆฌํฐ ์ ๊ณต
- Beans: Bean Factory ํจํด ๊ตฌํ, ๊ฐ์ฒด ์์ฑ ๋ฐ ๊ด๋ฆฌ
- Context: ApplicationContext, ๊ตญ์ ํ, ์ด๋ฒคํธ ์ ํ ๋ฑ
- SpEL: Spring Expression Language, ๋ฐํ์์ ๊ฐ์ฒด ๊ทธ๋ํ ์กฐํ/์กฐ์
2. AOP์ Aspects
๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ง์ํ๋ ๋ชจ๋์ด์์. ๋ก๊น , ํธ๋์ญ์ ๊ด๋ฆฌ ๋ฑ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค.
3. Data Access/Integration
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ์ฝ๊ฒ ํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ชจ๋๋ค์ด์์.
- JDBC: JDBC ์ถ์ํ ๋ ์ด์ด
- ORM: JPA, Hibernate ๋ฑ ORM ํ๋ ์์ํฌ ํตํฉ
- Transactions: ์ ์ธ์ ํธ๋์ญ์ ๊ด๋ฆฌ
4. Web
์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ๋ชจ๋๋ค์ด์์.
- WebMVC: Model-View-Controller ์ํคํ ์ฒ ๊ตฌํ
- WebFlux: ๋ฆฌ์กํฐ๋ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ์ง์
์ด๋ฐ ๋ชจ๋์ ๊ตฌ์กฐ ๋๋ถ์ Spring์ ํ์ฅ์ฑ์ด ๋ฐ์ด๋๊ณ , ํ์ํ ๊ธฐ๋ฅ๋ง ๊ณจ๋ผ์ ์ฌ์ฉํ ์ ์์ด์. ๋ง์น ์ฌ๋ฅ๋ท์์ ํ์ํ ์ฌ๋ฅ๋ง ์ ํํด์ ์ด์ฉํ๋ ๊ฒ์ฒ๋ผ์! ๐
2025๋ ํ์ฌ, Spring์ ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ์ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ๋ ๋ง์ ์ด์ ์ ๋ง์ถ๊ณ ์์ด์. WebFlux ๋ชจ๋์ ์ค์์ฑ์ด ๊ณ์ ์ปค์ง๊ณ ์๋ต๋๋ค!
4. Spring Boot์์ ๊ด๊ณ ๐
Spring์ ๊ณต๋ถํ๋ค ๋ณด๋ฉด ํญ์ ๋ฐ๋ผ์ค๋ Spring Boot! ์ด ๋์ ๊ด๊ณ๊ฐ ๋ญ์ง ํท๊ฐ๋ฆฌ์๋ ๋ถ๋ค ๋ง์ผ์ค ํ ๋ฐ์, ๊ฐ๋จํ ์ค๋ช ํด๋๋ฆด๊ฒ์.
Spring Framework vs Spring Boot
Spring Framework: ์๋ฐ ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ํฌ๊ด์ ์ธ ํ๋ก๊ทธ๋๋ฐ ๋ฐ ๊ตฌ์ฑ ๋ชจ๋ธ์ ์ ๊ณตํ๋ ํ๋ ์์ํฌ
Spring Boot: Spring Framework๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋, '์ค์ ๋ณด๋ค ๊ด๋ก(Convention over Configuration)' ์ฒ ํ์ ๋ฐ๋ผ ์ต์ํ์ ์ค์ ์ผ๋ก Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ
Spring Boot์ ์ฃผ์ ํน์ง์ ์ดํด๋ณผ๊น์? ๐
- ์๋ ์ค์ (Auto-configuration): ํด๋์คํจ์ค์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ํด์ค๋๋ค.
- ์คํํฐ ์์กด์ฑ(Starter Dependencies): ํน์ ๊ธฐ๋ฅ์ ์ํ ์์กด์ฑ์ ํ ๋ฒ์ ๊ฐ์ ธ์ฌ ์ ์์ด์. ์: spring-boot-starter-web
- ๋ด์ฅ ์๋ฒ(Embedded Server): ๋ณ๋์ ์น ์๋ฒ ์ค์น ์์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ ์ ์์ด์.
- Actuator: ์ด์ ํ๊ฒฝ์์ ์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง ๋ฐ ๊ด๋ฆฌ ๊ธฐ๋ฅ ์ ๊ณต
- Spring CLI: ๋ช ๋ น์ค์์ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ํ๋กํ ํ์ดํํ ์ ์์ด์.
๐ป Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@RestController
class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}
Spring Boot๋ Spring Framework๋ฅผ ๋์ฒดํ๋ ๊ฒ์ด ์๋๋ผ, Spring์ ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ์์! ๋ด๋ถ์ ์ผ๋ก๋ ์ฌ์ ํ Spring Framework์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ณ ์๋ต๋๋ค. ๐
2025๋ ํ์ฌ, Spring Boot 3.x ๋ฒ์ ์ด ์ฃผ๋ก ์ฌ์ฉ๋๊ณ ์์ผ๋ฉฐ, ์ด๋ Spring Framework 6.x๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ์์ด์. Java 17 ์ด์์ ๊ธฐ๋ณธ์ผ๋ก ์ง์ํ๋ฉฐ, GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ์ง์์ด ๊ฐํ๋์๋ต๋๋ค!
5. Spring์ ์ฃผ์ ๋ชจ๋ ์ดํด๋ณด๊ธฐ ๐ฆ
Spring์ ์ฃผ์ ๋ชจ๋๋ค์ ์ข ๋ ์์ธํ ์ดํด๋ณผ๊ฒ์! ๊ฐ ๋ชจ๋์ด ์ด๋ค ์ญํ ์ ํ๋์ง ์๋ฉด Spring์ ๋ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์๋ต๋๋ค.
๐ Spring Core
Spring Framework์ ํต์ฌ ๋ชจ๋๋ก, IoC์ DI ๊ธฐ๋ฅ์ ์ ๊ณตํด์. ์ด ๋ชจ๋ ์์ด๋ Spring์ ์ฌ์ฉํ ์ ์๋ค๊ณ ๋ด๋ ๋ฌด๋ฐฉํด์!
์ฃผ์ ๊ธฐ๋ฅ:
- Bean ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
- ApplicationContext ๊ตฌํ
- Resource ์ถ์ํ
- ๊ตญ์ ํ(i18n) ์ง์
- ์ด๋ฒคํธ ๋ฐํ-๊ตฌ๋ ๋ฉ์ปค๋์ฆ
๐ช Spring AOP
๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ(Aspect-Oriented Programming)์ ์ง์ํ๋ ๋ชจ๋์ด์์. ํก๋จ ๊ด์ฌ์ฌ(cross-cutting concerns)๋ฅผ ๋ถ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- ์ ์ธ์ AOP ์ง์
- @AspectJ ์ด๋ ธํ ์ด์ ์ง์
- ํ๋ก์ ๊ธฐ๋ฐ AOP ๊ตฌํ
AOP๋ ๋ก๊น , ํธ๋์ญ์ ๊ด๋ฆฌ, ๋ณด์๊ณผ ๊ฐ์ ๊ณตํต ๊ธฐ๋ฅ์ ๋น์ฆ๋์ค ๋ก์ง์์ ๋ถ๋ฆฌํ ์ ์๊ฒ ํด์ค์. ์ฝ๋๊ฐ ํจ์ฌ ๊น๋ํด์ง๋ต๋๋ค!
๐๏ธ Spring Data Access
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ์ฝ๊ฒ ํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ชจ๋๋ค์ด์์.
์ฃผ์ ๊ตฌ์ฑ์์:
- JDBC: ํ ํ๋ฆฟ ํจํด์ ์ฌ์ฉํด JDBC ์์ ๊ฐ์ํ
- ORM: Hibernate, JPA ๋ฑ๊ณผ์ ํตํฉ
- Transactions: ์ ์ธ์ ํธ๋์ญ์ ๊ด๋ฆฌ(@Transactional)
- Spring Data: ๋ฐ์ดํฐ ์ก์ธ์ค ๋ ์ด์ด ์ถ์ํ(JPA, MongoDB, Redis ๋ฑ)
๐ Spring Web
์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ๋ชจ๋๋ค์ด์์.
์ฃผ์ ๊ตฌ์ฑ์์:
- Spring MVC: ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ MVC ํ๋ ์์ํฌ
- Spring WebFlux: ๋ฆฌ์กํฐ๋ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ
- Spring REST: RESTful ์น ์๋น์ค ๊ฐ๋ฐ ์ง์
- Spring WebSocket: WebSocket ํ๋กํ ์ฝ ์ง์
2025๋ ํ์ฌ, WebFlux๋ ๊ณ ์ฑ๋ฅ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ํ์ ๋ชจ๋๋ก ์๋ฆฌ์ก์์ด์. ํนํ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ ๋ง์ด ์ฌ์ฉ๋๋ต๋๋ค!
๐ Spring Security
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณด์์ ๋ด๋นํ๋ ๋ชจ๋์ด์์. ์ธ์ฆ๊ณผ ๊ถํ ๋ถ์ฌ๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ํด์ค๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- ๋ค์ํ ์ธ์ฆ ๋ฐฉ์ ์ง์(ํผ ๋ก๊ทธ์ธ, OAuth2, JWT ๋ฑ)
- ๊ถํ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
- CSRF, XSS ๋ฑ ๋ณด์ ์ทจ์ฝ์ ๋ฐฉ์ด
- ๋ฉ์๋ ์์ค ๋ณด์(@Secured, @PreAuthorize ๋ฑ)
์ด ์ธ์๋ Spring Integration, Spring Batch, Spring Cloud ๋ฑ ๋ค์ํ ๋ชจ๋์ด ์์ด์. ํ์์ ๋ฐ๋ผ ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ต๋๋ค! ๐
์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ ์ฐพ์ ์ ์๋ฏ์ด, Spring์์๋ ๋ค์ํ ๋ชจ๋์ ํตํด ์ํ๋ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ด์. ๊ฐ ๋ชจ๋์ ํน์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ค๊ณ๋์์ง๋ง, ๋ชจ๋ Spring์ ํต์ฌ ์ฒ ํ์ ๋ฐ๋ฅด๊ณ ์๋ต๋๋ค! ๐ฑ
6. Spring MVC ์ํคํ ์ฒ ๐๏ธ
Spring MVC๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ Spring์ ์ฃผ์ ๋ชจ๋ ์ค ํ๋์์. MVC(Model-View-Controller) ํจํด์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, ์น ์์ฒญ ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
Spring MVC์ ํต์ฌ ์ปดํฌ๋ํธ๋ค์ ์ดํด๋ณผ๊ฒ์! ๐
๐ DispatcherServlet
Spring MVC์ ํต์ฌ ์ปดํฌ๋ํธ๋ก, ๋ชจ๋ HTTP ์์ฒญ์ ๋ฐ์ ์ ์ ํ ํธ๋ค๋ฌ์๊ฒ ์ ๋ฌํ๊ณ ์๋ต์ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐํํ๋ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ(Front Controller) ์ญํ ์ ํด์.
DispatcherServlet์ Spring MVC์ ์ฌ์ฅ์ด๋ผ๊ณ ํ ์ ์์ด์! ๋ชจ๋ ์์ฒญ์ด ์ฌ๊ธฐ์ ์์๋๊ณ ๋๋ฉ๋๋ค.
๐บ๏ธ HandlerMapping
ํด๋ผ์ด์ธํธ์ ์์ฒญ URL์ ์ด๋ค ์ปจํธ๋กค๋ฌ๊ฐ ์ฒ๋ฆฌํ ์ง ๊ฒฐ์ ํด์ฃผ๋ ์ธํฐํ์ด์ค์์. Spring์ ์ฌ๋ฌ HandlerMapping ๊ตฌํ์ฒด๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ๊ตฌํ์ฒด:
- RequestMappingHandlerMapping: @RequestMapping ์ด๋ ธํ ์ด์ ์ ์ฒ๋ฆฌ
- SimpleUrlHandlerMapping: URL ํจํด๊ณผ ์ปจํธ๋กค๋ฌ๋ฅผ ์ง์ ๋งคํ
๐ฎ Controller
ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ค์ ๋ก ์ฒ๋ฆฌํ๋ ์ปดํฌ๋ํธ์์. @Controller ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด ์ ์ํ๋ฉฐ, ์์ฒญ ์ฒ๋ฆฌ ํ Model๊ณผ View ์ด๋ฆ์ ๋ฐํํฉ๋๋ค.
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public String listUsers(Model model) {
model.addAttribute("users", userService.getAllUsers());
return "userList"; // ๋ทฐ ์ด๋ฆ
}
}
๐ Model
์ปจํธ๋กค๋ฌ์์ ๋ทฐ๋ก ์ ๋ฌํ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ์ปจํ ์ด๋์์. Map ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์์ต๋๋ค.
๐ ViewResolver
์ปจํธ๋กค๋ฌ๊ฐ ๋ฐํํ ๋ทฐ ์ด๋ฆ์ ์ค์ View ๊ฐ์ฒด๋ก ๋ณํํด์ฃผ๋ ์ธํฐํ์ด์ค์์.
์ฃผ์ ๊ตฌํ์ฒด:
- InternalResourceViewResolver: JSP ๋ทฐ ํด์
- ThymeleafViewResolver: Thymeleaf ํ ํ๋ฆฟ ํด์
- FreeMarkerViewResolver: FreeMarker ํ ํ๋ฆฟ ํด์
๐๏ธ View
๋ชจ๋ธ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํด ํด๋ผ์ด์ธํธ์๊ฒ ๋ณด์ฌ์ค ๊ฒฐ๊ณผ๋ฅผ ๋ ๋๋งํ๋ ์ธํฐํ์ด์ค์์.
Spring MVC๋ ์ด๋ฐ ์ปดํฌ๋ํธ๋ค์ ์ํธ์์ฉ์ ํตํด ์น ์์ฒญ์ ์ฒ๋ฆฌํด์. ๊ฐ ์ปดํฌ๋ํธ๋ ๋จ์ผ ์ฑ ์ ์์น(SRP)์ ๋ฐ๋ฅด๋ฉฐ, ์ด๋ฅผ ํตํด ์ ์ฐํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์๋ต๋๋ค! ๐
2025๋ ํ์ฌ, Spring MVC๋ ์ฌ์ ํ ๋ง์ ๊ธฐ์ ์์ ์ฌ์ฉ๋๊ณ ์์ง๋ง, ๊ณ ์ฑ๋ฅ์ด ์๊ตฌ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ Spring WebFlux๋ก์ ์ ํ์ด ํ๋ฐํ ์ด๋ฃจ์ด์ง๊ณ ์์ด์. WebFlux๋ ๋น๋๊ธฐ-๋ ผ๋ธ๋กํน ๋ชจ๋ธ์ ์ฌ์ฉํด ๋ ์ ์ ๋ฆฌ์์ค๋ก ๋ ๋ง์ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋ต๋๋ค!
7. Spring Data์ ๋ฐ์ดํฐ ์ก์ธ์ค ๐พ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๊ฑฐ์ ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์์ ์ธ ๋ถ๋ถ์ด์ฃ . Spring์ ๋ฐ์ดํฐ ์ก์ธ์ค๋ฅผ ์ฝ๊ฒ ํ ์ ์๋๋ก ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํด์. ํนํ Spring Data ํ๋ก์ ํธ๋ ๋ฐ์ดํฐ ์ก์ธ์ค ๋ ์ด์ด ๊ฐ๋ฐ์ ํ๊ธฐ์ ์ผ๋ก ๊ฐ์ํํ๋ต๋๋ค!
Spring์ ๋ฐ์ดํฐ ์ก์ธ์ค ์ง์
- JDBC ์ถ์ํ: JdbcTemplate์ ํตํ JDBC ์์ ๊ฐ์ํ
- ORM ํตํฉ: Hibernate, JPA ๋ฑ๊ณผ์ ํตํฉ
- ํธ๋์ญ์ ๊ด๋ฆฌ: ์ ์ธ์ ํธ๋์ญ์ ๊ด๋ฆฌ(@Transactional)
- Spring Data: ๋ค์ํ ๋ฐ์ดํฐ ์ ์ฅ์์ ๋ํ ํตํฉ ์ธํฐํ์ด์ค ์ ๊ณต
๐ Spring Data ํ๋ก์ ํธ
Spring Data๋ ๋ค์ํ ํ์ ํ๋ก์ ํธ๋ก ๊ตฌ์ฑ๋์ด ์์ด์. ๊ฐ ํ๋ก์ ํธ๋ ํน์ ๋ฐ์ดํฐ ์ ์ฅ์ ๊ธฐ์ ์ ๋ง์ถฐ์ ธ ์๋ต๋๋ค.
Spring Data JPA๋ ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๋ Spring Data ํ๋ก์ ํธ ์ค ํ๋์์. JPA(Java Persistence API)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, ๋ฐ์ดํฐ ์ก์ธ์ค ๋ ์ด์ด ๊ฐ๋ฐ์ ํฌ๊ฒ ๊ฐ์ํํด์ค๋๋ค.
๐ป Spring Data JPA ์์
// ์ํฐํฐ ํด๋์ค
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// ์์ฑ์, getter, setter ๋ฑ
}
// ๋ฆฌํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค
public interface UserRepository extends JpaRepository<User, Long> {
// ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ์ฟผ๋ฆฌ ์์ฑ
List<User> findByNameContaining(String name);
// @Query ์ด๋
ธํ
์ด์
์ผ๋ก ์ง์ JPQL ์์ฑ
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain%")
List<User> findByEmailDomain(@Param("domain") String domain);
}
Spring Data JPA์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ์ธํฐํ์ด์ค๋ง ์ ์ํ๋ฉด ๊ตฌํ์ฒด๋ Spring์ด ์๋์ผ๋ก ์์ฑํด์ค๋ค๋ ๊ฑฐ์์! ๋ฉ์๋ ์ด๋ฆ๋ง์ผ๋ก ์ฟผ๋ฆฌ๊ฐ ์๋ ์์ฑ๋๋ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๊ฐ ๋ํญ ์ค์ด๋ค์ฃ . ๐
๐ Spring Data์ ์ฃผ์ ๊ธฐ๋ฅ
- ๋ฆฌํฌ์งํ ๋ฆฌ ์ถ์ํ: ๋ค์ํ ๋ฐ์ดํฐ ์ ์ฅ์์ ๋ํ ์ผ๊ด๋ ์ ๊ทผ ๋ฐฉ๋ฒ ์ ๊ณต
- ๋ฉ์๋ ์ด๋ฆ ๊ธฐ๋ฐ ์ฟผ๋ฆฌ ์์ฑ: findByXxx, countByXxx ๋ฑ
- ํ์ด์ง ๋ฐ ์ ๋ ฌ ์ง์: Pageable ์ธํฐํ์ด์ค ํ์ฉ
- ์ฟผ๋ฆฌ ๋ฉ์๋: @Query ์ด๋ ธํ ์ด์ ์ผ๋ก ์ง์ ์ฟผ๋ฆฌ ์ ์
- ์คํ ๊ธฐ๋ฐ ์ฟผ๋ฆฌ: JPA Criteria API๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ Specification ์ธํฐํ์ด์ค
- ํ๋ก์ ์ : ์ํฐํฐ์ ์ผ๋ถ ์์ฑ๋ง ์กฐํํ๋ ๊ธฐ๋ฅ
๐ป ํ์ด์ง ๋ฐ ์ ๋ ฌ ์์
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Page<User> getUsersByPage(int page, int size) {
// ํ์ด์ง ์์ฒญ ๊ฐ์ฒด ์์ฑ (0๋ถํฐ ์์)
PageRequest pageRequest = PageRequest.of(page, size, Sort.by("name").ascending());
// ํ์ด์ง ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ ๋ฐํ
return userRepository.findAll(pageRequest);
}
}
2025๋ ํ์ฌ, Spring Data R2DBC๊ฐ ์ ์ ๋ ์ธ๊ธฐ๋ฅผ ์ป๊ณ ์์ด์. R2DBC(Reactive Relational Database Connectivity)๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ๋ฆฌ์กํฐ๋ธ API๋ฅผ ์ ๊ณตํ๋ฉฐ, Spring WebFlux์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์์ ํ ๋ฆฌ์กํฐ๋ธ ์คํ์ ๊ตฌ์ฑํ ์ ์๋ต๋๋ค!
๐ป Spring Data R2DBC ์์
@Data
public class User {
private Long id;
private String name;
private String email;
}
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
Flux<User> findByNameContaining(String name);
@Query("SELECT * FROM users WHERE email LIKE :domain")
Flux<User> findByEmailDomain(String domain);
}
Spring Data๋ ๋ฐ์ดํฐ ์ก์ธ์ค ์ฝ๋๋ฅผ ํฌ๊ฒ ์ค์ฌ์ฃผ๊ณ , ๋ค์ํ ๋ฐ์ดํฐ ์ ์ฅ์ ๊ธฐ์ ์ ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ํด์ค์. ๋ง์น ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ ์ฝ๊ฒ ์ฐพ์ ์ ์๋ ๊ฒ์ฒ๋ผ, Spring Data๋ก ๋ค์ํ ๋ฐ์ดํฐ ์ ์ฅ์๋ฅผ ์ฝ๊ฒ ํ์ฉํ ์ ์๋ต๋๋ค! ๐
8. Spring Security ๊ธฐ์ด ๐
์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ณด์์ ์ ๋ง ์ค์ํ ๋ถ๋ถ์ด์ฃ ! Spring Security๋ Spring ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ธ์ฆ(Authentication)๊ณผ ๊ถํ ๋ถ์ฌ(Authorization)๋ฅผ ๋ด๋นํ๋ ๊ฐ๋ ฅํ ๋ณด์ ํ๋ ์์ํฌ์์.
Spring Security์ ์ฃผ์ ๊ธฐ๋ฅ
- ์ธ์ฆ(Authentication): ์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์ง ํ์ธํ๋ ๊ณผ์
- ๊ถํ ๋ถ์ฌ(Authorization): ์ธ์ฆ๋ ์ฌ์ฉ์๊ฐ ์ด๋ค ์์ ์ ์ํํ ์ ์๋์ง ๊ฒฐ์ ํ๋ ๊ณผ์
- ๋ณด์ ์ทจ์ฝ์ ๋ฐฉ์ด: CSRF, XSS, ์ธ์ ๊ณ ์ ๊ณต๊ฒฉ ๋ฑ ๋ฐฉ์ด
- ํตํฉ ์ง์: Servlet API, Spring MVC, WebFlux ๋ฑ๊ณผ์ ํตํฉ
Spring Security์ ๊ธฐ๋ณธ ์ค์ ์ ๊ฐ๋จํด์. Spring Boot๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋์ฑ ์ฝ์ฃ !
๐ป Spring Security ๊ธฐ๋ณธ ์ค์
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/register").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Spring Security 6.x๋ถํฐ๋ ๋๋ค ๊ธฐ๋ฐ ์ค์ ์ด ๋์ ๋์ด ๋ ์ฝ๊ธฐ ์ฝ๊ณ ํ์ ์์ ํ ์ค์ ์ด ๊ฐ๋ฅํด์ก์ด์! ์ ์ฝ๋๋ 2025๋ ํ์ฌ ๊ถ์ฅ๋๋ ๋ฐฉ์์ด๋๋๋ค. ๐
๐ก๏ธ Spring Security์ ์ฃผ์ ์ปดํฌ๋ํธ
- SecurityFilterChain: ๋ณด์ ํํฐ๋ค์ ์ฒด์ธ์ผ๋ก, ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ณผ์ ์์ ๋ค์ํ ๋ณด์ ๊ฒ์ฌ๋ฅผ ์ํํด์.
- AuthenticationManager: ์ธ์ฆ์ ์ฒ๋ฆฌํ๋ ์ฃผ์ ์ธํฐํ์ด์ค๋ก, ๋ค์ํ AuthenticationProvider๋ฅผ ์ฌ์ฉํด ์ธ์ฆ์ ์ํํด์.
- UserDetailsService: ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ก๋ํ๋ ์ธํฐํ์ด์ค๋ก, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋ค๋ฅธ ์ ์ฅ์์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์.
- GrantedAuthority: ์ฌ์ฉ์์๊ฒ ๋ถ์ฌ๋ ๊ถํ์ ๋ํ๋ด๋ ์ธํฐํ์ด์ค์์.
๐ป ์ฌ์ฉ์ ์ ์ UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles().toArray(new String[0]))
.build();
}
}
2025๋ ํ์ฌ, Spring Security๋ OAuth2, JWT, OIDC ๋ฑ ๋ค์ํ ์ธ์ฆ ๋ฉ์ปค๋์ฆ์ ์ง์ํ๊ณ ์์ด์. ํนํ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์๋ JWT ๊ธฐ๋ฐ ์ธ์ฆ์ด ๋ง์ด ์ฌ์ฉ๋๊ณ ์๋ต๋๋ค!
๐ป JWT ์ค์ ์์
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
Spring Security๋ ๋ณต์กํ ๋ณด์ ์๊ตฌ์ฌํญ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ํ๋ ์์ํฌ์์. ๊ธฐ๋ณธ ์ค์ ๋ง์ผ๋ก๋ ๋ง์ ๋ณด์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง๋ง, ํ์์ ๋ฐ๋ผ ์ปค์คํฐ๋ง์ด์ง๋ ๊ฐ๋ฅํ๋ต๋๋ค! ๐
9. Spring Cloud์ ๋ง์ดํฌ๋ก์๋น์ค โ๏ธ
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๊ฐ ๋์ธ์ธ ์์ฆ, Spring Cloud๋ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ๋ฐ์ ์ํ ํ์ ๋๊ตฌ๋ก ์๋ฆฌ์ก์์ด์. Spring Cloud๋ ๋ถ์ฐ ์์คํ ์ ๊ณตํต ํจํด์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ํด์ฃผ๋ ํ๋ก์ ํธ ๋ชจ์์ด๋๋๋ค!
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๋?
๋ง์ดํฌ๋ก์๋น์ค๋ ํ๋์ ํฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๊ฐ์ ์์, ๋ ๋ฆฝ์ ์ธ ์๋น์ค๋ก ๋ถ๋ฆฌํ๋ ์ํคํ ์ฒ ์คํ์ผ์ด์์. ๊ฐ ์๋น์ค๋ ์์ฒด ํ๋ก์ธ์ค์์ ์คํ๋๋ฉฐ, ๊ฒฝ๋ ๋ฉ์ปค๋์ฆ(์ฃผ๋ก HTTP ๊ธฐ๋ฐ API)์ผ๋ก ํต์ ํฉ๋๋ค.
๋ง์ดํฌ๋ก์๋น์ค์ ์ฅ์ : ํ์ฅ์ฑ, ์ ์ฐ์ฑ, ๊ธฐ์ ๋ค์์ฑ, ์ฅ์ ๊ฒฉ๋ฆฌ, ๋น ๋ฅธ ๋ฐฐํฌ ๋ฑ
๋ง์ดํฌ๋ก์๋น์ค์ ๋จ์ : ๋ถ์ฐ ์์คํ ์ ๋ณต์ก์ฑ, ๋คํธ์ํฌ ์ง์ฐ, ๋ฐ์ดํฐ ์ผ๊ด์ฑ ๋ฌธ์ ๋ฑ
Spring Cloud๋ ๋ค์ํ ํ์ ํ๋ก์ ํธ๋ก ๊ตฌ์ฑ๋์ด ์์ด์. ๊ฐ ํ๋ก์ ํธ๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ ํน์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๐ Spring Cloud ์ฃผ์ ํ๋ก์ ํธ
- Spring Cloud Config: ์ค์ ์ง์ค์ ์ธ๋ถ ์ค์ ๊ด๋ฆฌ
- Spring Cloud Netflix/Eureka: ์๋น์ค ๋ฑ๋ก ๋ฐ ๋ฐ๊ฒฌ
- Spring Cloud Gateway: API ๊ฒ์ดํธ์จ์ด
- Spring Cloud Circuit Breaker: ํ๋ก ์ฐจ๋จ๊ธฐ ํจํด ๊ตฌํ
- Spring Cloud Stream: ๋ฉ์์ง ๊ธฐ๋ฐ ๋ง์ดํฌ๋ก์๋น์ค ๊ตฌ์ถ
- Spring Cloud Sleuth: ๋ถ์ฐ ์ถ์
๐ป Spring Cloud Config ์์
// Config Server ์ค์
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
// application.yml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/myorg/config-repo
default-label: main
// ํด๋ผ์ด์ธํธ ์ค์ (bootstrap.yml)
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
Spring Cloud Config๋ฅผ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ๋ง์ดํฌ๋ก์๋น์ค์ ์ค์ ์ ์ค์์์ ๊ด๋ฆฌํ ์ ์์ด์. ์ค์ ์ด ๋ณ๊ฒฝ๋๋ฉด ์๋น์ค๋ฅผ ์ฌ์์ํ์ง ์๊ณ ๋ ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํ ์ ์๋ต๋๋ค! ๐
๐ป Spring Cloud Gateway ์์
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
// application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/users/**
- id: product-service
uri: lb://PRODUCT-SERVICE
predicates:
- Path=/products/**
filters:
- name: CircuitBreaker
args:
name: productCircuitBreaker
fallbackUri: forward:/fallback/products
2025๋ ํ์ฌ, Spring Cloud๋ Kubernetes์์ ํตํฉ์ด ๋์ฑ ๊ฐํ๋์์ด์. Spring Cloud Kubernetes ํ๋ก์ ํธ๋ฅผ ํตํด Kubernetes์ ConfigMap, Secret, Service Discovery ๋ฑ์ ๊ธฐ๋ฅ์ Spring ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ต๋๋ค!
๐ป Spring Cloud Kubernetes ์์
// pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>
// application.yml
spring:
cloud:
kubernetes:
config:
enabled: true
sources:
- namespace: default
name: user-service-config
reload:
enabled: true
mode: polling
period: 5000
Spring Cloud๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ ๋ณต์ก์ฑ์ ํฌ๊ฒ ์ค์ฌ์ฃผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์์. ์๋น์ค ๋ฐ๊ฒฌ, ๋ก๋ ๋ฐธ๋ฐ์ฑ, ์ค์ ๊ด๋ฆฌ, ํ๋ก ์ฐจ๋จ ๋ฑ์ ํจํด์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ํด์ค๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ ๋ฌธ๊ฐ๋ค์ด ๊ฐ์์ ์์ญ์์ ์ต๊ณ ์ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ฏ, Spring Cloud์ ๊ฐ ์ปดํฌ๋ํธ๋ ์์ ์ ์ญํ ์ ์๋ฒฝํ๊ฒ ์ํํ๋ต๋๋ค! ๐
10. Spring 6.0 ๋ฐ ์ต์ ํธ๋ ๋ (2025) ๐ฎ
2025๋ ํ์ฌ, Spring Framework๋ ๊ณ์ํด์ ์งํํ๊ณ ์์ด์. Spring 6.0 ์๋ฆฌ์ฆ์ ํจ๊ป ๋ฑ์ฅํ ์๋ก์ด ๊ธฐ๋ฅ๋ค๊ณผ ํธ๋ ๋๋ฅผ ์ดํด๋ณผ๊ฒ์!
Spring 6.0์ ์ฃผ์ ๋ณ๊ฒฝ์ฌํญ
- Java 17 ๊ธฐ์ค์ : Spring 6.0๋ถํฐ๋ Java 17์ด ์ต์ ์๊ตฌ์ฌํญ์ด ๋์์ด์.
- Jakarta EE 9+: Java EE์์ Jakarta EE๋ก์ ์ ํ์ด ์๋ฃ๋์์ด์.
- AOT(Ahead-of-Time) ์ฒ๋ฆฌ: ์ปดํ์ผ ์์ ์ต์ ํ๋ฅผ ํตํ ์ฑ๋ฅ ํฅ์
- GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ์ง์ ๊ฐํ: ๋น ๋ฅธ ์์ ์๊ฐ๊ณผ ๋ฎ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋
- HTTP ์ธํฐํ์ด์ค ํด๋ผ์ด์ธํธ: ์ ์ธ์ HTTP ํด๋ผ์ด์ธํธ ์ง์
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ง์ ๊ฐํ: ๋ ๋ง์ API์์ ํจ์ํ ์คํ์ผ ์ง์
- Observability(๊ด์ฐฐ ๊ฐ๋ฅ์ฑ) ๊ฐํ: Micrometer์์ ํตํฉ ๊ฐ์
๐ป HTTP ์ธํฐํ์ด์ค ํด๋ผ์ด์ธํธ ์์
// HTTP ์ธํฐํ์ด์ค ์ ์
public interface UserClient {
@GetExchange("/users")
List<User> getAllUsers();
@GetExchange("/users/{id}")
User getUserById(@PathVariable Long id);
@PostExchange("/users")
User createUser(@RequestBody User user);
}
// HTTP ์ธํฐํ์ด์ค ์ฌ์ฉ
@Service
public class UserService {
private final UserClient userClient;
public UserService(WebClient.Builder builder) {
this.userClient = HttpServiceProxyFactory.builder()
.clientAdapter(WebClientAdapter.forClient(
builder.baseUrl("https://api.example.com").build()))
.build()
.createClient(UserClient.class);
}
public List<User> getAllUsers() {
return userClient.getAllUsers();
}
}
HTTP ์ธํฐํ์ด์ค ํด๋ผ์ด์ธํธ๋ Spring 6.0์ ๊ฐ์ฅ ํฅ๋ฏธ๋ก์ด ๊ธฐ๋ฅ ์ค ํ๋์์! ์ธํฐํ์ด์ค๋ง ์ ์ํ๋ฉด Spring์ด ์๋์ผ๋ก ๊ตฌํ์ฒด๋ฅผ ์์ฑํด์ฃผ๋, ์ฝ๋๊ฐ ํจ์ฌ ๊ฐ๊ฒฐํด์ง์ฃ . ๋ง์น Spring Data JPA์ ๋ฆฌํฌ์งํ ๋ฆฌ์ฒ๋ผ์! ๐
๐ 2025๋ Spring ์ํ๊ณ ํธ๋ ๋
- ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ์ฑํ ์ฆ๊ฐ: GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฆ๊ฐํ๊ณ ์์ด์. ํนํ ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์์ ์ฝ๋ ์คํํธ ์๊ฐ์ ์ค์ด๋ ๋ฐ ํจ๊ณผ์ ์ด์ฃ .
- ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ ์ฃผ๋ฅํ: Spring WebFlux์ Project Reactor๋ฅผ ์ฌ์ฉํ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ด ๋ ๋ง์ ํ๋ก์ ํธ์์ ์ฑํ๋๊ณ ์์ด์.
- ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ๊ฐ๋ฐ: Kubernetes, ์๋น์ค ๋ฉ์, ์๋ฒ๋ฆฌ์ค ๋ฑ๊ณผ์ ํตํฉ์ด ๋์ฑ ๊ฐํ๋์์ด์.
- AI/ML ํตํฉ: Spring AI ํ๋ก์ ํธ๋ฅผ ํตํด AI ์๋น์ค์์ ํตํฉ์ด ์ฌ์์ก์ด์.
- GraphQL ์ฑํ ์ฆ๊ฐ: Spring for GraphQL์ ํตํ GraphQL API ๊ฐ๋ฐ์ด ์ฆ๊ฐํ๊ณ ์์ด์.
- ๋ชจ๋์ ๋ชจ๋ ธ๋ฆฌ์ค: ๋ง์ดํฌ๋ก์๋น์ค์ ๋ณต์ก์ฑ์ ํผํ๋ฉด์๋ ๋ชจ๋์ฑ์ ๊ฐ์ถ '๋ชจ๋์ ๋ชจ๋ ธ๋ฆฌ์ค' ์ํคํ ์ฒ๊ฐ ์ธ๊ธฐ๋ฅผ ์ป๊ณ ์์ด์.
๐ป Spring Native ์์
// pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
// ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ๋น๋
$ ./mvnw native:compile
GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ์๊ฐ์ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ์ค์ด๊ณ , ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ํฌ๊ฒ ์ค์ผ ์ ์์ด์. ํนํ AWS Lambda์ ๊ฐ์ ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์์ ํฐ ์ด์ ์ ์ ๊ณตํฉ๋๋ค!
๐ป Spring AI ์์
@RestController
public class AIController {
private final ChatClient chatClient;
public AIController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/chat")
public Map<String, String> chat(@RequestParam String prompt) {
ChatResponse response = chatClient.call(
new Prompt(prompt)
);
return Map.of("response", response.getResult().getOutput().getContent());
}
}
Spring AI๋ Spring ์ํ๊ณ์ ์๋ก์ด ๋ฉค๋ฒ๋ก, OpenAI, Azure OpenAI, Anthropic ๋ฑ ๋ค์ํ AI ์๋น์ค์์ ํตํฉ์ ์ ๊ณตํด์. 2025๋ ์๋ AI ๊ธฐ๋ฅ์ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฝ๊ฒ ํตํฉํ ์ ์๊ฒ ๋์๋ต๋๋ค! ๐ค
๐ป Spring for GraphQL ์์
// schema.graphqls
type Query {
bookById(id: ID!): Book
allBooks: [Book!]!
}
type Book {
id: ID!
title: String!
author: Author!
}
type Author {
id: ID!
name: String!
books: [Book!]!
}
// BookController.java
@Controller
public class BookController {
private final BookRepository bookRepository;
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@QueryMapping
public Book bookById(@Argument Long id) {
return bookRepository.findById(id).orElse(null);
}
@QueryMapping
public List<Book> allBooks() {
return bookRepository.findAll();
}
@SchemaMapping
public Author author(Book book) {
return book.getAuthor();
}
}
Spring for GraphQL์ GraphQL Java๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, Spring์ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ๊ณผ ํตํฉ๋์ด ์์ด์. REST API ๋์ GraphQL API๋ฅผ ๊ฐ๋ฐํ๋ ํ๋ก์ ํธ๊ฐ ์ ์ ๋์ด๋๊ณ ์๋ต๋๋ค!
2025๋ ํ์ฌ, Spring ์ํ๊ณ๋ ๊ณ์ํด์ ์งํํ๊ณ ์์ด์. ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ, ๋ฆฌ์กํฐ๋ธ, AI ํตํฉ ๋ฑ ์ต์ ํธ๋ ๋๋ฅผ ์ ๊ทน์ ์ผ๋ก ์์ฉํ๋ฉด์๋, ๊ธฐ์กด Spring์ ์ฒ ํ๊ณผ ์ฅ์ ์ ๊ทธ๋๋ก ์ ์งํ๊ณ ์๋ต๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์ด ๋ค์ํ ์ฌ๋ฅ์ ์ฐ๊ฒฐํ๋ฉด์๋ ํต์ฌ ๊ฐ์น๋ฅผ ์งํค๋ ๊ฒ์ฒ๋ผ์! ๐ฑ
11. ์ค์ Spring ํ๋ก์ ํธ ๊ตฌ์ฑ ํ ๐ก
Spring์ผ๋ก ์ค์ ํ๋ก์ ํธ๋ฅผ ๊ตฌ์ฑํ ๋ ์์๋๋ฉด ์ข์ ํ๋ค์ ๋ชจ์๋ดค์ด์! ์ด ํ๋ค์ 2025๋ ํ์ฌ ์ ๊ณ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ๋ฐ์ํ ๊ฒ์ด๋ ์ฐธ๊ณ ํ์ธ์~
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ ๋ ์ด์ด๋ง
Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- Presentation Layer (Controller): ํด๋ผ์ด์ธํธ ์์ฒญ ์ฒ๋ฆฌ ๋ฐ ์๋ต ๋ฐํ
- Service Layer: ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ
- Repository Layer: ๋ฐ์ดํฐ ์ก์ธ์ค
- Domain Layer: ๋น์ฆ๋์ค ์ํฐํฐ ๋ฐ ๊ท์น
๊ฐ ๋ ์ด์ด๋ ๋ช ํํ ์ฑ ์์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ฉฐ, ์์กด์ฑ์ ํญ์ ์์ชฝ์ผ๋ก ํฅํด์ผ ํด์(Controller โ Service โ Repository). ์ด๋ฅผ ํตํด ์ฝ๋์ ์ ์ง๋ณด์์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ด ํฅ์๋ฉ๋๋ค!
๐ป ํจํค์ง ๊ตฌ์กฐ ์์
com.example.myapp
โโโ config // ์ค์ ํด๋์ค
โโโ controller // ์ปจํธ๋กค๋ฌ
โโโ service // ์๋น์ค
โโโ repository // ๋ฆฌํฌ์งํ ๋ฆฌ
โโโ domain // ๋๋ฉ์ธ ๋ชจ๋ธ
โโโ dto // ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด
โโโ exception // ์์ธ ํด๋์ค
โโโ util // ์ ํธ๋ฆฌํฐ ํด๋์ค
๋๋ ๊ธฐ๋ฅ๋ณ๋ก ํจํค์ง๋ฅผ ๊ตฌ์ฑํ ์๋ ์์ด์:
๐ป ๊ธฐ๋ฅ๋ณ ํจํค์ง ๊ตฌ์กฐ ์์
com.example.myapp
โโโ config
โโโ common
โโโ user
โ โโโ controller
โ โโโ service
โ โโโ repository
โ โโโ domain
โโโ product
โ โโโ controller
โ โโโ service
โ โโโ repository
โ โโโ domain
โโโ order
โโโ controller
โโโ service
โโโ repository
โโโ domain
๐ Spring ๊ฐ๋ฐ ๋ฒ ์คํธ ํ๋ํฐ์ค
- ์์ฑ์ ์ฃผ์ ์ฌ์ฉํ๊ธฐ: ํ๋ ์ฃผ์ (@Autowired) ๋์ ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ์ธ์. ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ๊ณ ํ ์คํธํ๊ธฐ ์ฌ์์ง๋๋ค.
- Lombok ํ์ฉํ๊ธฐ: ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๋ฅผ ์ค์ด๊ธฐ ์ํด Lombok์ ์ฌ์ฉํ์ธ์. @Data, @Builder, @RequiredArgsConstructor ๋ฑ์ ์ด๋ ธํ ์ด์ ์ด ์ ์ฉํฉ๋๋ค.
- DTO ํจํด ์ฌ์ฉํ๊ธฐ: ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์ง์ ๋ ธ์ถํ์ง ๋ง๊ณ , DTO(Data Transfer Object)๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ผ์ธ์.
- ์์ธ ์ฒ๋ฆฌ ์ ๋ต ์๋ฆฝํ๊ธฐ: @ControllerAdvice์ @ExceptionHandler๋ฅผ ์ฌ์ฉํด ์ผ๊ด๋ ์์ธ ์ฒ๋ฆฌ ์ ๋ต์ ๊ตฌํํ์ธ์.
- ํ๋กํ์ผ ํ์ฉํ๊ธฐ: ๊ฐ๋ฐ, ํ ์คํธ, ์ด์ ํ๊ฒฝ๋ณ๋ก ๋ค๋ฅธ ์ค์ ์ ์ ์ฉํ๊ธฐ ์ํด Spring ํ๋กํ์ผ์ ํ์ฉํ์ธ์.
- ํ ์คํธ ์ฝ๋ ์์ฑํ๊ธฐ: ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ์ฌ ์ฝ๋์ ํ์ง์ ๋ณด์ฅํ์ธ์.
- API ๋ฌธ์ํํ๊ธฐ: Springdoc-OpenAPI(Swagger)๋ฅผ ์ฌ์ฉํด API๋ฅผ ๋ฌธ์ํํ์ธ์.
๐ป ์์ฑ์ ์ฃผ์ ์์
// ๊ถ์ฅํ์ง ์๋ ๋ฐฉ์ (ํ๋ ์ฃผ์
)
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// ๋ฉ์๋๋ค...
}
// ๊ถ์ฅํ๋ ๋ฐฉ์ (์์ฑ์ ์ฃผ์
)
@Service
public class UserService {
private final UserRepository userRepository;
// Spring์ด ์๋์ผ๋ก ์ฃผ์
ํด์ค๋๋ค
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ๋ฉ์๋๋ค...
}
// Lombok ์ฌ์ฉ ์ ๋ ๊ฐ๊ฒฐํ๊ฒ
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
// ๋ฉ์๋๋ค...
}
๐ป DTO ํจํด ์์
// ๋๋ฉ์ธ ๊ฐ์ฒด
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password; // ๋ฏผ๊ฐ ์ ๋ณด
private String email;
// ์์ฑ์, getter, setter ๋ฑ
}
// DTO ๊ฐ์ฒด
@Data
public class UserDto {
private Long id;
private String username;
private String email;
// password๋ ํฌํจํ์ง ์์
// ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DTO๋ก ๋ณํํ๋ ์ ์ ๋ฉ์๋
public static UserDto from(User user) {
UserDto dto = new UserDto();
dto.setId(user.getId());
dto.setUsername(user.getUsername());
dto.setEmail(user.getEmail());
return dto;
}
}
๐ป ์์ธ ์ฒ๋ฆฌ ์์
// ์ฌ์ฉ์ ์ ์ ์์ธ
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
// ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
// ๊ธฐํ ์์ธ ์ฒ๋ฆฌ ๋ฉ์๋๋ค...
}
// ์๋ฌ ์๋ต DTO
@Data
@AllArgsConstructor
public class ErrorResponse {
private String code;
private String message;
}
โก ์ฑ๋ฅ ์ต์ ํ ํ
- N+1 ๋ฌธ์ ํด๊ฒฐํ๊ธฐ: JPA๋ฅผ ์ฌ์ฉํ ๋ ๋ฐ์ํ๋ N+1 ์ฟผ๋ฆฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด fetch join์ด๋ EntityGraph๋ฅผ ์ฌ์ฉํ์ธ์.
- ์บ์ฑ ํ์ฉํ๊ธฐ: Spring Cache ์ถ์ํ๋ฅผ ์ฌ์ฉํด ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ๋ฅผ ์บ์ฑํ์ธ์.
- ๋น๋๊ธฐ ์ฒ๋ฆฌ ํ์ฉํ๊ธฐ: @Async ์ด๋ ธํ ์ด์ ์ด๋ CompletableFuture๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ์ธ์.
- ํ์ด์ง ์ฒ๋ฆฌํ๊ธฐ: ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋๋ ํญ์ ํ์ด์ง ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ์ธ์.
- ์ธ๋ฑ์ค ์ต์ ํํ๊ธฐ: ์์ฃผ ์กฐํํ๋ ์ปฌ๋ผ์ ์ธ๋ฑ์ค๋ฅผ ์ถ๊ฐํ์ธ์.
๐ป N+1 ๋ฌธ์ ํด๊ฒฐ ์์
// N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ ์ฝ๋
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUserId(Long userId);
}
// fetch join์ผ๋ก ํด๊ฒฐ
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.user.id = :userId")
List<Order> findByUserIdWithItems(@Param("userId") Long userId);
}
// EntityGraph ์ฌ์ฉ
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
@EntityGraph(attributePaths = {"items"})
List<Order> findByUserId(Long userId);
}
๐ป ์บ์ฑ ์์
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("users"),
new ConcurrentMapCache("products")
));
return cacheManager;
}
}
@Service
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
}
@CacheEvict(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@CacheEvict(value = "products", allEntries = true)
public void clearProductCache() {
// ์บ์ ์ ์ฒด ์ญ์
}
}
์ด๋ฐ ๋ฒ ์คํธ ํ๋ํฐ์ค์ ํ๋ค์ ์ ์ฉํ๋ฉด Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ง๊ณผ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ด์! ๋ง์น ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์ ์กฐ์ธ์ ๋ฃ๋ ๊ฒ์ฒ๋ผ, ์ด ํ๋ค์ ์ฌ๋ฌ๋ถ์ Spring ๊ฐ๋ฐ ์ฌ์ ์ ํฐ ๋์์ด ๋ ๊ฑฐ์์. ๐
๊ฒฐ๋ก : Spring Framework์ ๋ฏธ๋ ๐
์ง๊ธ๊น์ง Spring Framework์ ํต์ฌ ๊ฐ๋ ๊ณผ ์ํคํ ์ฒ์ ๋ํด ์์๋ดค์ด์. Spring์ ์๋ฐ ์ํฐํ๋ผ์ด์ฆ ๊ฐ๋ฐ์ ํ์ค์ผ๋ก ์๋ฆฌ ์ก์์ผ๋ฉฐ, ๊ณ์ํด์ ์งํํ๊ณ ์๋ต๋๋ค.
์์ฝ
- Spring์ IoC์ DI๋ฅผ ํตํด ๋์จํ ๊ฒฐํฉ๊ณผ ๋์ ์์ง๋๋ฅผ ๊ฐ์ง ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์๊ฒ ํด์ค๋๋ค.
- Spring์ ๋ชจ๋์ ์ํคํ ์ฒ๋ ํ์ํ ๊ธฐ๋ฅ๋ง ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
- Spring Boot๋ Spring ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค.
- Spring MVC, Spring Data, Spring Security ๋ฑ์ ํ๋ก์ ํธ๋ ๊ฐ๊ฐ์ ์์ญ์์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- Spring Cloud๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ํด์ค๋๋ค.
- Spring 6.0๊ณผ ํจ๊ป ๋ฑ์ฅํ ์๋ก์ด ๊ธฐ๋ฅ๋ค์ ๋ ํ๋์ ์ด๊ณ ํจ์จ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
2025๋ ํ์ฌ, Spring์ ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ, ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ, AI ํตํฉ ๋ฑ์ ํธ๋ ๋๋ฅผ ์ ๊ทน์ ์ผ๋ก ์์ฉํ๋ฉด์๋ ๊ธฐ์กด์ ๊ฐ์ ์ ์ ์งํ๊ณ ์์ด์. ์์ผ๋ก๋ Spring์ ์๋ฐ ์ํ๊ณ์ ์ค์ฌ์์ ํ์ ์ ์ด๋์ด ๋๊ฐ ๊ฒ์ผ๋ก ๊ธฐ๋๋ฉ๋๋ค!
Spring Framework๋ฅผ ๋ง์คํฐํ๋ ๊ฒ์ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ์ฌ์ ์ด์ง๋ง, ๊ทธ ๊ณผ์ ์์ ์ป๋ ์ง์๊ณผ ๊ฒฝํ์ ๊ฐ๋ฐ์๋ก์์ ์ฑ์ฅ์ ํฐ ๋์์ด ๋ ๊ฑฐ์์. ๋ง์น ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ๊ฒ์ฒ๋ผ์! ๐ฑ
์ด ๊ธ์ด ์ฌ๋ฌ๋ถ์ Spring ์ฌ์ ์ ๋์์ด ๋์๊ธธ ๋ฐ๋๋๋ค. ๊ณ์ํด์ ํ์ตํ๊ณ , ์คํํ๊ณ , ์ฑ์ฅํ์ธ์! ํ์ดํ ! ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.