gimmickbutreal

[Spring Boot] 서비스(Service)가 필요한 이유 본문

Programming/Spring Boot

[Spring Boot] 서비스(Service)가 필요한 이유

isshosng 2022. 9. 1. 11:42

대부분의 규모있는 Spring Boot 프로젝트에서는 컨트롤러에서 리포지터리를 직접 호출하지 않고 중간에 서비스(Service)를 두어 데이터를 처리합니다. 서비스는 Spring Boot에서 데이터 처리를 위해 작성하는 클래스인데, 서비스를 쓰는 이유는 무엇일까요?

 

크게 모듈화, 보안, Entity 클래스 3가지 이유가 있습니다.

 

모듈화

예를 들어 어떤 컨트롤러가 여러개의 리포지터리를 사용하여 데이터를 조회한 후 가공하여 리턴한다고 가정했을 때, 이러한 기능을 서비스로 만들어두면 컨트롤러에서는 해당 서비스를 호출하여 사용하면 된다. 하지만 서비스로 만들지 않고 컨트롤러에서 구현하려 하면 해당 기능을 필요로 하는 모든 컨트롤러가 동일한 기능을 중복으로 구현해야 하므로 서비스는 모듈화를 위해서 꼭 필요합니다.

 

 

보안

컨트롤러는 리포지터리 없이 서비스를 통해서만 데이터베이스에 접근하도록 구현하는 것이 보안상 안전합니다. 서비스를 따로 구축하면 해커가 만일 해킹을 통해 컨트롤러를 제어할 수 있게 되더라도 리포지터리에 직접 접근할 수는 없게 됩니다.

 

 

엔티티 객체와 DTO 객체의 변환

wikidocs spring boot에서 예제로 만드는 질문 게시판의 경우, Question과 Answer 클래스는 엔티티 클래스이다. 엔티티 클래스는 데이터베이스와 직접 맞닿아 있는 클래스이기 때문에 컨트롤러나 타임리프와 같은 템플릿 엔진에 전달하여 사용하는 것은 좋지 않습니다. 컨트롤러나 타임리프에서 사용하는 데이터 객체는 속성을 변경하여 비즈니스적인 요구를 처리해야 하는 경우가 많은데 엔티티를 직접 사용하여 속성을 변경한다면 테이블 컬럼이 변경돼 엉망이 될 수도 있기 때문입니다.

 

이러한 이유로 Question, Answer처럼 엔티티 클래스는 컨트롤러에서 사용할 수 없게끔 설계하는 것이 좋습니다. 그렇게 하기 위해서 DTO(Data Transfer Object) 클래스가 필요합니다. 

 

 

 

Spring Boot의 서비스로 만들려면

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
 
import java.util.List;
 
@RequiredArgsConstructor
@Service
public class QuestionService {
 
    private final QuestionRepository questionRepository;
 
    public List<Question> getList() {
        return this.questionRepository.findAll();
    }
}
cs

위와 같이 클래스명 위에 @Service 애너테이션을 붙이면 됩니다. @Controller, @Entity 등과 마찬가지로 Spring Boot는 @Service 애너테이션이 붙은 클래스는 서비스로 인식합니다.

 

questionRepository : 해당 객체는 생성자 방식으로 DI 규칙에 의해 주입됩니다. (DI : 외부에서 의존성을 주입하는 것)

getList() : 해당 메서드는 질문 목록ㅇ글 조회하여 리턴하는 역할을 합니다. 이전 컨트롤러에서 리포지터리를 사용했던 부분을 그대로 옮긴 것입니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
public class QuestionController {
 
    private final QuestionRepository questionRepository;
    @RequestMapping("/question/list")
 
    public String list(Model model){
        List<Question> questionList = this.questionRepository.findAll();
        model.addAttribute("questionList",questionList);
        return "question_list";
    }
}
cs

위와 같이 컨트롤러 내에 Repository로 되어 있었던 부분들을

 

1
2
3
4
5
6
7
8
9
10
11
public class QuestionController {
 
    private final QuestionService questionService;
    @RequestMapping("/question/list")
 
    public String list(Model model){
        List<Question> questionList = this.questionService.getList();
        model.addAttribute("questionList",questionList);
        return "question_list";
    }
}
cs

이처럼 Service로 바꾸어주고 findAll에서 getList로도 바꾸어줍니다.

여기서도 questionService 객체는 생성자 방식으로 DI 규칙에 의해 주입되었습니다.

 

 

wikidocs.net/161220