카테고리 없음

spring-boot(3)

rjqnrdl83 2025. 2. 11. 14:17

3. 스프링 부트3 구조 이해하기

 

3.1 스프링 부트3 구조 살펴보기

스프링 부트는 각 계층이 양 옆의 계층과 통신하는 구조입니다. 계층은 각자의 역할과 책임이 있는 소프트웨어의 구성 요소를 의미합니다. 각 계층은 소통할 수는 있지만 다른 계층에 직접 간섭하거나 영향을 미치지는 않습니다.

 

컨트롤러                         서비스                       리포지터리

프레젠테이션 계층  <-->  비즈니스 계층  <-->  퍼시스턴스 <-->  데이터베이스

 

프레젠테이션 계층

HTTP 요청을 받고 이 요청을 비즈니스 계층으로 전송하는 역할을 합니다. 컨트롤러가 프레젠테이션 계층 역할을 합니다.

 

비즈니스 계층

모든 비즈니스 로직(서비스를 만들기 위한 로직)을 처리합니다. 서비스가 비즈니스 계층의 역할을 합니다.

 

퍼시스턴스 계층

모든 데이터베이스 관련 로직을 처리합니다. 이 과정에서 데이터베이스에 접근하는 DAO 객체를 사용할 수도 있습니다. 리포지터리가 퍼시스턴스 계층의 역할을 합니다.

DAO: 데이터베이스 계층과 상호작용하기 위한 객체

 

스프링 부트3 프로젝트 발전시키기

  • implementation: 프로젝트 코드가 컴파일 시점과 런타임에 모두 해당 라이브러리를 필요로 할 때 사용
  • testImplementation: 프로젝트의 테스트 코드를 컴파일하고 실행할 때만 필요한 의존성을 설정, 테스트 코드에서만 사용, 메인 애플리케이션 코드에서는 사용하지 않음
  • runtimeOnly: 런타임에만 필요한 의존성을 지정, 컴파일 시에는 필요하지 않지만, 애플리케이션을 실핼할 때 필요한 라이브러리 설정
  • compileOnly: 컴파일시에만 필요, 런타임에는 포함되지 않아야 하는 의존성 지정
  • annotationProcessor: 컴파일 시에 애너테이션을 처리할 때 사용하는 도구의 의존성 지정

프레젠테이션, 서비스, 퍼시스턴스 계층 만들기

@RestController
public class TestController {
    @Autowired // TestService 주입
    TestService testService;

    @GetMapping("/test")
    public List<Member> getAllMembers(){
        List<Member> members=testService.getAllMembers();
        return members;
    }
}

 

@Service
public class TestService {
    @Autowired
    MemberRepository memberRepository; // (1) 빈 주입
    public List<Member> getAllMembers(){
        return memberRepository.findAll(); // (2) 멤버 목록 얻기
    }
}

(1) MemberRepository라는 빈을 주입받은 후에 (2) findAll() 메서드를 호출해 멤버 테이블에 저장된 멤버 목록을 모두 가져옵니다.

 

HTTP 요청   ->   TestConroller.java    ->    TestService.java

url:/test               프레젠테이션 계층           비즈니스 계층

 

이번에는 퍼시스턴트 계층을 작성하겠습니다. DB에 접근할 때 사용할 객체인 Member DAO를 생성하고 실제 DB에 접근하는 코드를 작성합니다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="id", updatable=false)
    private Long id;

    @Column (name="name", nullable=false)
    private String name;
}

 

이제 실제로member 테이블과 Member클래스를 매핑하는 코드를 작성하겠습니다. 매핑 작업에는 인터페이스 파일이 필요하니 MemberRepository인터페이스를 생성하겠습니다.

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
}

이 인터페이스는 DB에서 데이터를 가져오는 퍼시스턴트 계층 역할을 할 겁니다.

 

작동 확인하기

각 계층 코드를 완성했으니 스프링 부트 애플리케이션을 실행해보겠습니다. 데이터베이스에 결과를 볼 수 있는 데이터가 입력되지 않은 상태입니다. 보통 실행 테스트를 하기 위해 SQL문을 실행해 데이터베이스에 직접 데이터를 넣습니다.

INSERT INTO member (id, name) VALUES (1, 'name 1')
INSERT INTO member (id, name) VALUES (2, 'name 2')
INSERT INTO member (id, name) VALUES (3, 'name 3')
spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true

    defer-datasource-initialization: true

show-sql, format_sql 옵션은 애플리케이션 실행 과정에 데이터베이스에 쿼리할 일이 있으면 실행 구문을 모두 보여주는 옵션이고 defer-datasource-initialization은 애플리케이션을 실행할 때 테이블을 생성하고 data.sql 파일에 있는 쿼리를 실행하도록 하는 옵션입니다.

 

요약

1. 프레젠테이션 계층HTTP 요청을 받고 비즈니스 계층으로 전송합니다.

2. 비즈니스 계층은 모든 비즈니스 로직을 처리합니다. 퍼시스턴스 계층에서 제공하는 서비스를 사용할 수도 있고 권한을 부여하거나 유효성 검사를 하기도 합니다.

3. 퍼시스턴스 계층은 모든 스토리지 관련 로직을 처리합니다. 이 과정에서 데이터베이스에 접근하기 위한 객체인 DAO를 사용할 수도 있습니다.