이전에 들었던 김영한님의 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 강의에 대해 복습을 하기 위해 요약을 해보았다.
라이브러리
Apache 클라이언트에서 요청하는 HTTP 요청을 처리하는 웹서버 정적타입(HTML, CSS, 이미지 등)의 데이터만을 처리하기 때문에 톰캣이 등장하게 되었다.
Tomcat(톰캣) WAS
Java EE 기반으로 만들어져, JSP와 Servlet을 구동하기 위한 서블릿 컨테이너 역할을 수행한다.
- 컨테이너란?
- 동적인 데이터들을 가공하여 정적인 파일로 만들어주는 모듈
- 서블릿(servlet)이란?
- 클라이언트의 요청을 받고 요청을 처리하여 결과를 클라이언트에게 제공하는 자바 인터페이스.
- java.servlet.package에 정의된 인터페이스로서 서블릿의 라이프 사이클을 위한 세 가지 필수적인 메소드들을 정의한다.
- init()
- service()
- destory()
서블릿 컨테이너
- 서블릿들을 모아 관리
- 새로운 요청이 들어올 때마다 새로운 스레드를 생성
- 작업이 끝난 서블릿 스레드 자동 제거
→ 톰캣: 데이터 처리와 같은 동적인 기능들을 가공하여 HTML파일(정적인 파일로) 만들어 클라이언트에게 제공(8080 포트)
기본 동작원리
빌드하기
macOS:
- ./gradlew build
- cd build/libs
- java -jar hello-spring-0.0.1-SNAPSHOT.jar
window:
./gradlew build →./gradlew.bat build 로 바꾸어 실행
정적 컨텐츠
해당 요청에 대한 controller 부재 시 resources에서 정적 파일을 찾아 반환하게 됨
MVC와 템플릿 엔진
MVC 패턴
MVC: Model-View-Contoller
사용자가 Controller를 조작하면 Controller는 Model을 통해 데이터를 가져오고 그 데이터를 바탕으로 View를 통해 클라이언트에 시각적 표현 전달
- 사용자가 웹사이트에 접속 (Users)
- Controller는 사용자가 요청한 웹페이지를 서비스하기 위해서 모델을 호출 (Manipulates)
- Model은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후 그 결과를 Return
- Controller는 Model이 리턴한 결과를 View에 반영 (Updates)
- 데이터가 반영된 View는 사용자에게 보여짐 (Sees)
API
@ResponseBody: http의 body부에 이 데이터를 직접 넣어주겠다는 의미 → 객체를 View에 반환
html 파일을 거치지 않고 데이터를 그대로 내려준다.
string을 넘겨주면 그대로 string을 보여주게 되지만, 객체를 반환할 경우에는 json으로 보여주게 된다.
API 방식의 핵심은 데이터를 넘겨주는 것 → json 형식으로 변환되어 전송되어진다.
회원 관리 예제 - 백엔드 개발
테스트 코드의 중요성
- 개발단계 초기에 문제를 발견하게 도와준다.
- 나중에 코드를 리팩토링하거나 라이브러리 업데이트 등의 변화가 있을 때 기존 기능에 영향이 있는지 없는지 쉽게 판단할 수있다. (예: 회귀테스트)
- 기능에 대한 불확실성을 감소시킬 수 있다.
- 단위 테스트 자체가 문서로 사용될 수 있다.
TDD(Test-Driven-Development)
테스트 주도개발.
실패하는 테스트 케이스를 먼저 작성한 후에 개발을 진행하고, 일단 테스트를 통과하는 코드를 작성하고 상황에 맞게 리팩토링하는 방식
BDD(Behavior-Driven-Development)
행동 주도 개발.
TDD와 유사하지만, TDD가 테스트 자체에 집중해 개발하는 반면, BDD는 테스트보다는 비즈니스 요구사항에 집중하여 테스트 케이스를 개발
DDD(Domain-Driven-Development)
도메인 주도 개발.
일반적인 방식 → 순수 도메인의 모델과 로직에 집중하여 개발하는 것
스프링 빈과 의존관계
스프링 빈이란?
Spring IoC 컨테이너가 관리하는 자바 객체로, Spring에 의해 생성되고 관리되는 자바 객체
IoC(Inversion Of Control): 객체의 생성을 특별한 관리 위임 주체에게 맡깁니다. 이 경우 사용자는 객체를 직접 생성하지 않고, 객체의 생명주기를 컨트롤하는 주체는 다른 주체 가 됩니다. 즉, 사용자의 제어권을 다른 주체에게 넘기는 것을 IOC(제어의 역전) 라고 합니다.
컴포넌트 스캔과 자동 의존관계 설정
@Controller // 자바 코드로 직접 스프링 빈을 등록할 때에도 controller는 그대로 둔다.
public class MemberController {
private final MemberService memberService;
@Autowired // 스프링 컨테이너에서 멤버서비스를 가져옴, 생성자로 호출
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
이후 @Service, @Repository 어노테이션으로 컴포넌트 스캔을 해주면, 스프링이 이를 인지하고 관계를 설정한다.
정형화된 패턴 → Controller를 통해서 외부 요청을 받고, Service에서 비즈니스 로직을 만들고, Repository에서 데이터를 저장
이후 생성자에 @Autowired 를 통해 의존성 주입(DI)을 해주면 객체 의존관계가 성립된다.
이때 만약 생성자가 1개만 있으면, @Autowired 는 생략이 가능하다.
스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 공유한다.)
아무 파일에다가 @Component, @Contoller, @Service, @Repository 어노테이션을 붙인다고 되는 것이 아니라, 정해진 패키지 폴더 하위 디렉토리에서만 스프링이 컴포넌트 스캔을 진행한다.
자바 코드로 직접 스프링 빈 등록하기
@Controller 어노테이션 만을 사용하고, Bean Configuration File을 만들어 직접 Bean을 등록한다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
장점: 구현체에 변경사항이 생길 경우 configuration 파일에서 return 하는 객체만 변경해주면 된다.
(컴포넌트 스캔을 이용하는 경우 직접 다 바꿔 주어야 한다.)
DI(의존성 주입)의 3가지 방법
- 필드 주입
- 단점: 초기 값 설정 이후 값 변경 불가
- setter 주입
- 단점: 유지보수 단계에서 값 변경에 취약함
- 생성자 주입
스프링 DB 접근 기술
SOLID 원칙
- SRP(Single Responsibility Principle): 단일 책임 원칙
- 클래스는 단 하나의 책임을 가져야 함 → 클래스를 변경하는 이유는 하나여야 함
- 유지보수의 효율성을 위한 원칙
- OCP(Open Closed Priciple): 개방 폐쇄 원칙
- 확장에는 열려있고, 변경에는 닫혀있어야 함
- 기존의 코드를 변경하지 않고 수정하거나 추가할 수 있도록 설계하기 위함
- LSP(Listov Substitution Priciple): 리스코프 치환 원칙
- 하위 타입 객체는 상위 타입 객체에서 가능한 행위를 수행할 수 있어야 함
- 상속 관계에서 IS-A 가 성립해야 함
- ISP(Interface Segregation Principle): 인터페이스 분리 원칙
- 클라이언트는 자신이 사용하는 메소드에만 의존해야 한다는 원칙
- • 인터페이스는 해당 인터페이스를 사용하는 클라이언트를 기준으로 잘게 분리되어야 함
- DIP(Dependency Inversion Principle): 의존 역전 원칙
- 의존 관계를 맺을 때, 변하기 쉬운 것(구체적인 것)보다는 변하기 어려운 것(추상적인 것)에 의존해야 함
→ SRP 와 ISP는 객체가 커지는 것을 막고, LSP와 DIP는 OCP를 서포트 한다고 할 수 있다.
스프링 통합 테스트
@SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행
@Transactional : 테스트 코드 실행 후 롤백한다. → DB에 데이터가 남아있지 않아 다음 테스트에 영향을 주지 않는다.
가급적 기능 별 단위테스트로 잘게 쪼개서 구성을 해놓는 것이 좋다.
JPA
- 자바 ORM(Object Relational Mapping) 표준에 따른다.
- SQL을 직접 작성할 필요가 없어 생산성이 높다.
dependency: implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
@Entity : JPA가 관리하는 엔티티
EntityManager 객체를 주입받아 사용한다.
private final EntityManager em;
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
스프링 데이터 JPA
JpaRepository 를 상속받아 내장되어 있는 메소드들을 이용할 수 있다.
스프링 데이터 JPA 제공 기능
- 인터페이스를 통한 기본적인 CRUD 제공
- 페이징 기능 자동 제공
- findByName() 등의 메소드 이름만으로 조회(read) 가능
Reference
'Server > Spring' 카테고리의 다른 글
[Spring Cloud] SCG 서버가 Netty가 아닌 Tomcat으로 실행될 때 문제 해결 (2) | 2024.01.22 |
---|---|
[Spring] 스프링부트에서 출력되는 로그 레벨 변경하기 (0) | 2023.07.26 |
[Spring] return "redirect:/"과 return view 의 차이점 (0) | 2022.07.18 |