Spring 기본 구조와 작동 방식
Spring 백엔드 입문· 1 / 4
Spring는 Java의 객체지향 프로그래밍(OOP)을 활용하여 서버의 유연성과 확장성 제공하는 Java 기반의 대표적인 프레임워크다.
주요 특징은 아래와 같다.
- 의존성 주입(DI) 및 제어의 역전(IoC) 스프링 컨테이너(ApplicationContext)가 객체를 관리/주입하여 객체각 결합도를 낮춘다.
- 모듈화 및 확장성 Spring Core를 중심으로 다양한 모듈(Spring MVC, Spring Data, Spring Security 등)이 있어, 필요에 따라 유연하게 개발할 수 있다.
- JPA(Java Persistence API) JPA를 활용하여 객체와 관계형 데이터베이스 간의 매핑을 쉽게 처리할 수 있다.
- AOP(Aspect-Oriented Programming) 공통적으로 적용해야 하는 기능(로깅, 보안, 트랜잭션 관리 등)을 핵심 로직과 분리해 관리할 수 있다.
- 테스트 용이성 의존성 주입을 통해 단위 테스트 작성이 쉬우며, Mock 객체를 이용해 독립적으로 테스트를 수행할 수 있다.
- Spring Boot 지원 스프링 부트를 통해 설정이 간소화되고, 애플리케이션을 빠르게 개발하고 배포할 수 있다.
이외에도 Spring만의 다양한 특징이 있으며, 단일 프레임워크가 아닌, 다양한 모듈과 프로젝트를 포괄하는 생태계 또한 방대하다.
그중, 웹 개발 모듈인 Spring Web을 이용해 기본적인 서버를 만들어본다.
Spring 프로젝트 생성
Spring에서 지원하는 Spring Initializr 웹 툴을 이용해 프로젝트를 간단하게 생성할 수 있다.

위와 같이 기본 설정 후에 Dependencies 에 Spring Web 과 템플릿 엔진인 Thymeleaf 을 포함시켜준다.
이제 프로젝트를 생성해 다운받은 패키지를 IDE로 열어준다.
Spring 기본 라이브러리 살펴보기
# build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'angari.dev'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}Gradle 빌드 도구를 이용해 프로젝트를 생성하면 build.gradle 빌드 스크립트 파일이 루트에 생성된다.
dependencies를 보면 기본적인 의존성들이 포함되어 있다.
spring-boot-starter-thymeleaf: 템플릿 엔진spring-boot-starter-webspring-boot-starter-tomcat: 웹서버spring-webmvc: 스프링 웹 MVC
spring-boot-starter-testjunit: 단위 테스트 프레임워크mockito: Mock 객체 생성 라이브러리assertj: 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리spring-test: 통합 테스트 라이브러리
Spring Web 작동 방식
Spring 서버가 작동하는 방식은 크게 3가지로 구분된다.
- 정적 콘텐츠
- MVC + 템플릿 엔진
- API
정적 콘텐츠
HTML 파일을 그대로 전달하는 방식으로, 별도의 Controller를 필요로 하지 않는다.
요청 시 src/main/resources/static 패키지 하위에 위치한 HTML 파일이 자동으로 제공되는데, 이떄 파일명이 지정되지 않으면 기본적으로 index.html을 반환한다.
http://localhost:8080/hello-static.htmlhello-static.htmlMVC + 템플릿 엔진

MVC(Model-View-Controller) 모델 기반의 패턴으로 템플릿 엔진 라이브러리를 이용해 동적으로 HTML을 생성한다.
http://localhost:8080/hello-mvc?name=spring<html xmlns:th="http://www.thymeleaf.org">
<body>
<p th:text="'hello ' + ${name}">hello empty</p>
</body>
</html>위와 같은 URL에 따라 요청을 Controller가 받아 처리하는데, 이 과정에서 데이터를 Model에서 가져와 비즈니스 로직을 수행한 후, 결과가 반영된 HTML 페이지(View)를 반환한다.
Controller는 아래와 같이 작성할 수 있다.
@GetMapping("hello-mvc")
public String helloMvc(@RequestParam(value = "name", required = false) String name, Model model) {
model.addAttribute("name", name);
return "hello-mvc";
}Controller는 논리적 뷰 이름(템플릿 파일 이름)을 반환하는데, 이때 ViewResolver가 반환된 이름으로 실제 뷰 템플릿 파일을 찾아 매핑하고 템플릿 엔진에 위치 정보를 전달한다. 템플릿 엔진은 해당 파일을 읽어 동적 데이터를 채워넣고 HTML 결과를 생성해낸다.
API

MVC + 템플릿 엔진 방식은 HTML를 전달해 화면을 그리는 역할을 수행하지만, 이것만으로 내부적인 비즈니스 로직을 처리하는 데에는 한계가 있다.
이때, API를 사용하면, 클라이언트와 서버 간의 데이터 전송을 독립적으로 처리할 수 있다.
@GetMapping("hello-api")
@ResponseBody
public Hello helloApi(@RequestParam("name") String name) {
Hello hello = new Hello();
hello.setName(name);
return hello;
}http://localhost:8080/hello-api?name=spring{
"name": "John"
}위와 같이 Controller에서 @ResponseBody 애노테이션을 이용하면 결과값을 HTML 스크립트가 아닌 Json으로 반환하여, 클라이언트는 반환값을 이용해 필요한 UI만 갱신하면 된다.
참고로, @ResponseBody 를 사용하면 viewResolver 대신 HttpMessageConverter가 동작한다.
참고 자료
- [1] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (김영한)↗