회원 관리 예제 - 백엔드 개발
🎯비즈니스 요구사항 정리
- 데이터: 회원 ID, 이름
- 기능: 회원 등록, 조회
- 아직 데이터 저장소가 선정되지 않았다고 가정
일반적인 웹 애플리케이션 계층 구조

- 컨트롤러: 웹 MVC의 컨트롤러 역할
- 서비스: 핵심 비지니스 로직 구현
- 리포지토리: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리
- 도메인: 비즈니스 도메인 객체(회원, 주문, 쿠폰 등)로, 주로 데이터베이스에 저장하고 관리됨
클래스 의존관계

- 아직 데이터 저장소가 선정되지 않은 상태(가정), 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계
- 데이터 저장소는 RDB, NoSQL 등 다양한 저장소를 고민중인 상황으로 가정
- 개발을 진행하기 위해 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용
🎯코드 구현 중 필요한 기능
- @AfterEach: 한 번에 여러 테스트를 실행하면 메모리 DB에 직전 테스트의 결과가 남아, 다음 테스트를 실행할 때 오류 발생의 원인이 될 수 있음. 이런 상황에서 @AfterEach를 사용하면 각 테스트가 종료될 때마다 메모리 DB에 저장된 데이터를 삭제하여 오류 방지 가능
- 테스트는 각각 독립적으로 실행되어야 하며, 테스트 순서에 의존관계가 있다면 이는 좋은 테스트가 아님
- @BeforeEach: 각 테스트 실행 전에 호출됨. 테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하고, 의존관계를 새로 맺어줌
스프링 빈과 의존관계
🎯컴포넌트 스캔과 자동 의존관계 설정
회원 컨트롤러에 의존 관계 추가 - 회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있도록 함
- DI(Dependency Injection): 의존성 주입
- @Autowired: 생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어줌. 이렇게 객체 의존관계를 외부에서 넣어주는 것이 바로 DI.
- 생성자에 @Autowired를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아 주입함. 생성자가 1개만 있다먼 @Autowired는 생략 가능
- DI는 개발자가 직접 주입할 수 있고, @Autowired에 의해 주입하는 것도 가능
스프링 빈을 등록하는 방법
- @Controller가 있으면 자동 등록(스프링이 제공하는 컨트롤러)
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록
컴포넌트 스캔 원리
- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록
- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문
- @Component를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록됨
- @Controller
- @Service
- @Repository
+) 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록함(유일하게 하나만 등록해서 공유). 따라서 같은 스프링 빈이면 모두 같은 인스턴스. 설정으로 싱글톤이 아니도록 할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용함
자바 코드로 직접 스프링 빈 등록하기
예시 코드
package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
- @Service, @Repository, @Autowired 애노테이션 없이 직접 스프링 빈 등록
- @Bean: 스프링 빈에 등록할 것이라는 신호
참고 사항
- XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않음
- DI에는 필드 주입, setter 주입, 생성자 주입으로 3가지 방법이 존재. 의존관계가 실행 도중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장함(위 예제도 생성자 주입)
- 실무에서 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용함. 그리고 정형화되지 않거나, 상화에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록함
- @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작함. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않음
스프링 DB 접근 기술
🎯H2 데이터베이스 설치, 순수 Jdbc
구현 클래스 추가

스프링 설정

- 개방-폐쇄 원칙(OCP, Open-Closed Principle)
- 확장에는 열려있고, 수정, 변경에는 닫혀있음
- 스프링의 DI(Dependencies Injection)을 사용하면 기존 코드를 전혀 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있음
- 회원을 등록하고 DB에 결과가 잘 입력되는지 확인
- 데이터를 DB에 저장하므로 스프링 서버를 다시 실행해도 데이터가 안전하게 저장됨
🎯스프링 통합 테스트
- @SpringBootTest: 스프링 컨테이너와 테스트를 함께 실행
- @Transactional: 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜직션을 시작하고, 테스트 완료 후에 항상 롤백함. 이렇게 하면 DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않음
🎯스프링 JdbcTemplate
- 순수 Jdbc와 동일한 환경설정
- 스프링 JdbcTemplate과 MyBatis같은 라이브러리는 JDBC API에서 본 반복 코드를 대부분 제거해줌, 하지만 SQL은 직접 작성해야 함
🎯JPA
- JPA는 기존의 반복 코드에 더하여, 기본적인 SQL도 JPA가 직접 만들어서 실행함
- JPA를 사용하면 SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환할 수 있음
- JPA를 사용하면 개발 생산성을 크게 높일 수 있음
코드 구현 중 알아야 할 것
- spring-boot-starter-data-jpa: 내부에 jdbc 관련 라이브러리 포함, jdbc는 제거해도 됨
- show-sql: JPA가 생성하는 SQL을 출력
- ddl-auto: JPA는 테이블을 자동으로 생성하는 기능을 제공하는데 none를 사용하면 해당 기능을 끔.
- create: 엔티티 정보를 바탕으로 테이블 직접 생성
- 스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋함. 만약 런타임 예외가 발생하면 롤백
- JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 함.
🎯스프링 데이터 JPA
- 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발 완료 가능
- 반복 개발해온 CRUD 기능 제공
- 실무에서 관계형 데이터베이스를 사용할 때 유용
스프링 데이터 JPQ 제공 클래스

스프링 데이터 JPA 제공 기능
- 인터페이스를 통한 기본저긴 CRUD
- findByName(), findByEmail()처럼 메서드 이름만으로 조회 기능 제공
- 페이징 기능 자동 제공
AOP
🎯AOP가 필요한 상황
- 모든 메소드의 호출 시간을 측정
- 공통 관심사항(cross-cutting concern) vs 핵심 관심사항(core concern)
- 회원 가입 시간, 회원 조회 시간 측정

위 상황에서의 문제점
- 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심사항이 아님
- 시간을 측정하는 로직은 공통 관심사항
- 시간을 측정하는 로직과 핵심 비지니스의 로직이 섞여 유지보수가 어려움
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어려움
- 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 함
🎯AOP 적용
- AOP: Aspect Oriented Programming(관점 지향 프로그래밍)
- 공통 관심사항과 핵심 관심사항을 분리

AOP를 적용함으로써 문제 해결
- 회원가입, 회원조회 등 핵심 관심사항과 시간을 측정하는 공통 관심사항을 분리
- 시간 측정 로직을 별도의 공통 로직으로 설정
- 핵심 관심사항을 깔끔하게 유지
- 변경이 필요하면 시간 측정 로직만 변경할 수 있음
- 원하는 적용 대상 선택 가능
🎯AOP 동작 방식 설명
AOP 적용 전 의존관계

AOP 적용 후 의존관계

AOP 적용 전 전체 그림

AOP 적용 후 전체 그림

'Project > Backend 프로젝트' 카테고리의 다른 글
| 백엔드 프로젝트 13주차 - 스프링부트3 자바 백엔드 개발 입문 3장~6장 (1) | 2024.01.06 |
|---|---|
| 백엔드 프로젝트 12주차 - 스프링부트3 자바 백엔드 개발 입문 1장~2장 (2) | 2023.12.23 |
| 백엔드 프로젝트 7주차 스프링 입문 (1) (0) | 2023.11.04 |
| 백엔드 프로젝트 5주차 (SQL 첫걸음) - 5장 (1) | 2023.10.07 |
| 백엔드 프로젝트 4주차 (SQL 첫걸음) - 4장 (0) | 2023.10.07 |