해당 게시글은 스프링부트 핵심 가이드 교재를 공부하며 작성한 글입니다.
01. 스프링 부트란?
스프링 프레임워크
- 자바에서 가장 많이 사용하는 프레임워크
- 자바 언어를 이용해 *엔터프라이즈급 개발을 편리하게 만들어주는 '오픈소스 경량급 어플리케이션 프레임워크'
- *엔터프라이즈급 개발 : 기업 환경을 대상으로 하는 개발
- 스프링의 핵심 가치 : 애플리케이션 개발에 필요한 기반을 제공해서 개발자가 비즈니스 로직 구현에만 집중할 수 있게끔 하는 것
제어 역전(IoC)
- Inversion of Control의 약자
- 일반적인 자바 개발의 경우 사용하려는 객체를 선언하고 해당 객체의 의존성을 생성한 후 객체에서 제공하는 기능을 사용한다.
- IoC를 적용한 환경에서는 사용할 객체를 직접 생성하지 않고 객체의 생명주기 관리를 *외부에 위임한다.
- *외부 : 스프링 컨테이너 혹은 IoC 컨테이너
- 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것 → 개발자는 비즈니스 로직을 작성하는 데 더 집중할 수 있음
의존성 주입(DI)
- Dependency Injection의 약자
- 제어 역전의 방법 중 하나
- 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식
스프링에서 의존성을 주입받는 방법 3가지
1. 생성자를 통한 의존성 주입
@RestController
public class DIController {
// ---
MyService myService;
@Autowired
public DIController(MyService myService) {
this.myService = myService;
}
// ---
@GetMapping("/di/hello")
public String getHello() {
return myService.getHello();
}
}
2. 필드 객체 선언을 통한 의존성 주입
@RestController
public class FieldInjectionController {
// ---
@Autowired
private MyService myService;
// ---
}
3. setter 메서드를 통한 의존성 주입
@RestController
public class SetterInjectionController {
// ---
MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
// ---
}
생성자를 통해 의존성을 주입받는 방식을 권장. 레퍼런스 객체 없이는 객체를 초기화할 수 없게 설계할 수 있기 때문
관점 지향 프로그래밍(AOP)
- Aspect-Oriented Programming
- OOP를 더욱 잘 사용하도록 돕는 개념
- *관점을 기준으로 묶어 개발하는 방식
- *관점 : 어떤 기능을 구현할 때, '핵심 기능'과 '부가 기능'으로 구분해 각각을 하나의 관점으로 보는 것을 의미
- 로깅이나 트랜잭션 같은 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화해 삽입하는 방식
AOP를 구현하는 방법 3가지
- 컴파일 과정에 삽입하는 방식
- 바이트코드를 메모리에 로드하는 과정에 삽입하는 방식
- 프락시 패턴을 이용한 방식
스프링 AOP의 목적 : 모듈화해서 재사용 가능한 구성을 만드는 것이고, 모듈화된 객체를 편하게 적용할 수 있게 함으로써 개발자가 비즈니스 로직을 구현하는 데만 집중할 수 있게 도와주는 것
스프링 프레임워크 vs 스프링 부트
- 스프링 프레임워크는 기존 개발 방식의 문제와 한계를 극복하기 위해 다양한 기능을 제공하지만 기능이 많은 만큼 설정이 복잡한 편
- 필요한 모듈들을 추가하다 보면 설정이 복잡해지는 문제를 해결하기 위해 등장한 것이 스프링 부트
스프링 부트를 이용하면 단독으로 실행 가능한 상용 수준의 스프링 기반 애플리케이션을 손쉽게 만들 수 있습니다.
의존성 관리
- 스프링 프레임워크에서는 개발에 필요한 각 모듈의 의존성을 직접 설정
- 스프링 부트에서는 이러한 불편함을 해소하기 위해 'spring-boot-starter'라는 의존성을 제공
spring-boot-starter 라이브러리
- spring-boot-starter-web: 스프링 MVC를 사용하는 RESTful 애플리케이션을 만들기 위한 의존성. 기본으로 내장 톰캣(Tomcat)이 포함돼 있어 jar 형식으로 실행 가능합니다.
- spring-boot-starter-test: JUnit, Jupiter, Mockito 등의 테스트용 라이브러리를 포함합니다.
- spring-boot-starter-jdbc: HikariCP 커넥션 풀을 활용한 JDBC 기능을 제공합니다.
- spring-boot-starter-security: 스프링 시큐리티(인증, 권한, 인가 등) 기능을 제공합니다.
- spring-boot-starter-data-jpa: 하이버네이트를 활용한 JPA 기능을 제공합니다.
- spring-boot-starter-cache: 스프링 프레임워크의 캐시 기능을 지원합니다.
자동 설정
@SpringBootApplication 어노테이션은 다음 3개의 어노테이션을 합쳐놓은 구성
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
02. 개발에 앞서 알면 좋은 기초 지식
서버 간 통신
- 한 서버가 다른 서버에 통신을 요청하는 것을 의미
- 가장 많이 사용되는 방식은 HTTP/HTTPS방식
스프링 부트의 동작 방식
spring-boot-starter-web 모듈을 사용하면 기본적으로 톰캣(Tomcat)을 사용하는 스프링 MVC 구조를 기반으로 동작
- 서블릿(Servlet)은 클라이언트의 요청을 처리하고 결과를 반환하는 자바 웹 프로그래밍 기술
- 서블릿은 서블릿 컨테이너에서 관리한다.
- 서블릿 컨테이너는 서블릿 인스턴스를 생성하고 관리하는 역할을 수행하는 주체
- 톰캣은 WAS의 역할과 서블릿 컨테이너의 역할을 수행하는 대표적인 컨테이너
- 스프링에서는 DispatcherServlet이 서블릿의 역할을 수행
서블릿 컨테이너의 특징
- 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리합니다.
- 서블릿 객체는 싱글톤 패턴으로 관리됩니다.
- 멀티 스레딩을 지원합니다.
DispatcherServlet의 동작 과정
- DispatcherServlet으로 요청(HttpServletRequest)이 들어오면 핸들러 매핑을 통해 요청 URI에 매핑된 핸들러를 탐색
- 핸들러 어탭터로 컨트롤러를 호출
- 핸들러 어댑터에 컨트롤러의 응답이 돌아오면 ModelAndView로 응답을 가공해 반환
- 뷰 형식으로 리턴하는 컨트롤러를 사용할 때는 View Resolver를 통해 뷰를 받아 리턴
View Resolver는 뷰의 렌더링 역할을 담당하는 뷰 객체를 반환
뷰가 없는 REST 형식의 @ResponseBody는 View Resolver를 호출하지 않고 MessageConverter를 거쳐 JSON 형식으로 변환해서 응답
레이어드 아키텍처
- 애플리케이션의 컴포넌트를 유사 관심사를 기준으로 레이어로 묶어 수평적으로 구성한 구조를 의미
- 3계층 또는 4계층 구성 - 차이는 인프라(데이터 베이스) 레이어의 추가 여부로 결정
프레젠테이션 계층
- 애플리케이션의 최상단 계층으로, 클라이언트의 요청을 해석하고 응답하는 역할
- UI나 API를 제공
- 프레젠테이션 계층은 별도의 비즈니스 로직을 포함하고 있지 않으므로 비즈니스 계층으로 요청을 위임하고 받은 걸 응답하는 역할만 수행
비즈니스 계층
- 애플리케이션이 제공하는 기능을 정의하고 세부 작업을 수행하는 도메인 객체를 통해 업무를 위임하는 역할을 수행
- DDD(Domain-Driven Design) 기반의 아키텍처에서는 비즈니스 로직에 도메인이 포함되기도 하고, 별도로 도메인 계층을 두기도함
데이터 접근 계층
- 데이터베이스에 접근하는 일련의 작업을 수행
레이어드 아키텍처 기반 설계의 특징
- 각 레이어는 가장 가까운 하위 레이어의 의존성을 주입받는다.
- 각 레이어는 관심사에 따라 묶여있으며, 다른 레이어의 역할을 침범하지 않는다.
- 각 컴포넌트의 역할이 명확하므로 코드의 가독성과 기능 구현에 유리하다.
- 코드의 확장성도 좋아진다.
- 각 레이어가 독립적으로 작성되면 다른 레이어와의 의존성을 낮춰 단위테스트에 용이하다.
스프링의 레이어드 아키텍처
- Spring MVC는 Model-View-Controller의 구조로 View와 Controller는 프레젠테이션 계층 영역, Model은 비즈니스와 데이터 접근 계층의 영역으로 구분
- 비즈니스 계층에 서비스를 배치해 엔티티와 같은 도메인 객체의 비즈니스 로직을 조합
- 데이터 접근 계층에서는 DAO(Spring Data JPA에서는 Repository)를 배치해 도메인을 관리
프레젠테이션 계층
- 상황에 따라 유저 인터페이스 계층이라고도 함
- 클라이언트와의 접점이 됨
- 클라이언트로부터 데이터와 함께 요청을 받고 처리 결과를 응답으로 전달하는 역할
비즈니스 계층
- 상황에 따라 서비스 계층이라고도 함
- 핵심 비즈니스 로직을 구현하는 영역
- 트랜잭션 처리나 유효성 검사 등의 작업을 수행하기도 함
데이터 접근 계층
- 상황에 따라 영속 계층이라고도 함
- 데이터베이스에 접근해야하는 작업을 수행
- DAO 역할을 Spring Data JPA에서는 리포지토리로 대체할 수 있음
디자인 패턴
디자인 *패턴은 소프트웨어를 설계할 때 자주 발생하는 문제들을 해결하기 위해 고안된 해결책
*패턴은 애플리케이션 개발에서 발생하는 문제는 유사한 경우가 많고 해결책도 동일하게 적용할 수 있다는 의미를 내포함
디자인 패턴의 종류
생성 패턴 : 객체 생성에 사용되는 패턴으로, 객체를 수정해도 호출부가 영향을 받지 않게 합니다.
- 추상 팩토리 : 구체적인 클래스를 지정하지 않고 상황에 맞는 객체를 생성하기 위한 인터페이스를 제공하는 패턴입니다.
- 빌더 : 객체의 생성과 표현을 분리해 객체를 생성하는 패턴입니다.
- 팩토리 메서드 : 객체 생성을 서브 클래스로 분리해서 위임하는 패턴입니다.
- 프로토타입 : 원본 객체를 복사해 객체를 생성하는 패턴입니다.
- 싱글톤 : 한 클래스마다 인스턴스를 하나만 생성해서 인스턴스가 하나임을 보장하고 어느 곳에서도 접근할 수 있게 제공하는 패턴입니다.
구조 패턴 : 객체를 조합해서 더 큰 구조를 만드는 패턴입니다.
- 어댑터 : 클래스의 인터페이스를 의도하는 인터페이스로 변환하는 패턴입니다.
- 브리지 : 추상화와 구현을 분리해서 각각 독립적으로 변형케 하는 패턴입니다.
- 컴포지트 : 여러 객체로 구성된 복합 객체와 단일 객체를 클라이언트에서 구별 없이 다루는 패턴입니다.
- 데코레이터 : 객체를 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 하는 패턴입니다.
- 퍼사드 : 서브 시스템의 인터페이스 집합들에 하나의 통합된 인터페이스를 제공하는 패턴입니다.
- 플라이웨이트 : 특정 클래스의 인스턴스 한 개를 가지고 여러 개의 '가상 인스턴스'를 제공할 때 사용하는 패턴입니다.
- 프락시 : 특정 객체를 직접 참조하지 않고 해당 객체를 대행하는 객체를 통해 접근하는 패턴입니다.
행위 패턴 : 객체 간의 알고리즘이나 책임 분배에 관한 패턴입니다. 객체 하나로는 수행할 수 없는 작업을 여러 객체를 이용해 작업을 분배합니다. 결합도 최소화를 고려할 필요가 있습니다.
- 책임 연쇄 : 요청 처리 객체를 집합으로 만들어 결합을 느슨하게 만드는 패턴입니다.
- 커맨드 : 실행될 기능을 캡슐화해서 주어진 여러 기능을 실행하도록 클래스를 설계하는 패턴입니다.
- 인터프리터 : 주어진 언어의 문법을 위한 표현 수단을 정의하고 해당 언어로 구성된 문장을 해석하는 패턴입니다.
- 이터레이터 : 내부 구조를 노출하지 않으면서 해당 객체의 집합 원소에 순차적으로 접근하는 방법을 제공하는 패턴입니다.
- 미디에이터 : 한 집합에 속한 객체들의 상호작용을 캡슐화하는 객체를 정의한 패턴입니다.
- 메멘토 : 객체의 상태 정보를 저장하고 필요에 따라 상태를 복원하는 패턴입니다.
- 옵저버 : 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버 목록을 객체에 등록해 상태가 변할 때마다 메서드 등을 통해 객체가 직접 옵저버에게 통지하게 하는 디자인 패턴입니다.
- 스테이트 : 상태에 따라 객체가 행동을 변경하게 하는 패턴입니다.
- 스트래티지 : 행동을 클래스로 캡슐화 해서 동적으로 행동을 바꿀 수 있게 하는 패턴입니다.
- 템플릿 메서드 : 일정 작업을 처리하는 부분을 서브 클래스로 캡슐화해서 전체 수행 구조는 바꾸지 않으면서 특정 단계만 변경해서 수행하는 패턴입니다.
- 비지터 : 실제 로직을 가지고 있는 객체가 로직을 적용할 객체를 방문하며 실행하는 패턴입니다.
REST API
대중적으로 가장 많이 사용되는 애플리케이션 인터페이스
REST 란?
- Representational State Transfer
- 분산 하이퍼미디어 시스템 아키텍처의 한 형식
- HTTP 메서드(GET, POST, PUT, DELETE)를 통해 해당 자원의 상태를 주고받는 것을 의미
REST API란?
- API는 Application Programming Interface의 약자
- 애플리케이션에서 제공하는 인터페이스를 의미
- 서버 또는 프로그램 사이를 연결
- REST 아키텍처를 따르는 시스템/애플리케이션 인터페이스라고 볼 수 있음
- 'RESTful 하다'라고 표현
REST의 특징
유니폼 인터페이스
- 일관된 인터페이스를 의미
- 어떤 프로그래밍 언어로 만들어졌느냐와 상관없이 종속되지 않고 타 언어, 플랫폼, 기술 등과 호환해 사용 가능
무상태성
- 서버에 상태 정보를 따로 보관하거나 관리하지 않는다는 의미
- 세션이나 쿠키 정보를 별도로 보관하지 않는다
- 불필요한 정보를 관리하지 않으므로 비즈니스 로직의 자유도가 높고 설계가 단순
캐시 가능성
- HTTP의 캐싱 기능을 적용할 수 있음
- 캐싱이 가능한 경우 클라이언트에서 캐시에 저장해두고 같은 요청에 대해서는 해당 데이터를 가져다 사용
- 서버의 트랜잭션 부하가 줄어 효율적이며 사용자 입장에서 성능이 개선
레이어 시스템
- 네트워크 상의 여러 계층으로 구성될 수 있습니다.
클라이언트-서버 아키텍처
- REST 서버는 API를 제공하고 클라이언트는 사용자 정보를 관리하는 구조로 분리해 설계합니다.
- 서로에 대한 의존성을 낮추는 기능을 함
REST의 URI 설계 규칙
URI의 마지막에는 '/'를 포함하지 않습니다.
- 옳은 예) http://localhost.com/product
- 잘못된 예) http://localhost.com/product/
언더바(_)는 사용하지 않습니다. 대신 하이픈(-)을 이용합니다.
- 옳은 예) http://localhost.com/provider-company-name
- 잘못된 예) http://localhost.com/provider_company_name
URL에는 행위(동사)가 아닌 결과(명사)를 포함합니다.
- 옳은 예) http://localhost.com/product/123
- 잘못된 예) http://localhost.com/delete-product/123
URI는 소문자로 작성해야 합니다.
파일의 확장자는 URI에 포함하지 않습니다.
'Spring' 카테고리의 다른 글
| 스프링 부트 핵심 가이드(6장) (1) | 2024.09.29 |
|---|---|
| 스프링 부트 핵심 가이드(3~5장) (1) | 2024.09.29 |