@Service, @Repository 사용 이유에 대한 고찰 + PSA
학습 과정에서 작성한 글로, 잘못된 내용에 대한 지적 또는 피드백 환영합니다!
@Controller, @Service, @Repository
Spring 프레임워크에서 제공하는 어노테이션 중
@Controller, @Service, @Repository 는
@Component를 상속하는, 웹MVC 계층을 명시하기 위한 어노테이션이다.
@Controller 어노테이션은, 다른 어노테이션과 함께 사용하여 요청과 메서드를 매핑할 수 있다.
이는 직접 사용해보면서 금방 알 수 있었다.
그런데 나머지 두 어노테이션은?
@Component와 다를 바 없지만 그저 명시만을 위해 다른 이름을 가지는 것인지, 다른 특별한 기능이 있는지 궁금했다.
@Repository 어노테이션이 지원하는 기능
@Repository 어노테이션을 사용하면
영속 계층에서 발생한 예외(예를 들면 JPA에서 제공하는 Exception)를 Spring 전용 Exception으로 전환해준다.
아래는 java docs에서 확인할 수 있는 내용이다.
A class thus annotated is eligible for Spring DataAccessException translation when used in conjunction with a PersistenceExceptionTranslationPostProcessor. The annotated class is also clarified as to its role in the overall application architecture for the purpose of tooling, aspects, etc.
As of Spring 2.5, this annotation also serves as a specialization of @Component, allowing for implementation classes to be autodetected through classpath scanning
하지만 차이는 그 뿐이다.
@Service 어노테이션은 왜 붙여야 하나?
그러면 아예 기능적 차이가 없는 @Service 어노테이션 대신 @Component를 써도 되는 것 아닌가?
물론 @Component를 써도 당장 발생하는 문제는 없다. 똑같이 정상적으로 빈 등록이 가능할 것이다.
물론 각 계층에 이름을 붙여 명시하는 것만으로도 중요한 의미가 될 수 있다.
하지만 클래스명으로도 충분하지 않나? (ex. XXXService.class)
공식 문서에서는 이 어노테이션을 왜 만들었는지, 어떻게 쓰라고 권장하는지 궁금해서 찾아보았다.
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
1.10.1. @Component and Further Stereotype Annotations
The @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions, as described in Exception Translation.
Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases (in the persistence, service, and presentation layers, respectively). Therefore, you can annotate your component classes with @Component, but, by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. @Repository, @Service, and @Controller can also carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice. Similarly, as stated earlier, @Repository is already supported as a marker for automatic exception translation in your persistence layer.
볼드 표시한 부분에 주목하자.
but, by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects.
보다 적절한 도구를 사용할 수도 있고, 적절한 관점과 연관지을 수 있으므로
@Component 보다는 각 스테레오타입에 맞는 어노테이션을 사용하기를 권장하고 있다.
여기서 말하는 관점(aspect)과 포인트컷은 AOP에 대한 내용인데 이 포스팅에서는 넘어가도록 하겠다.
@Repository, @Service, and @Controller can also carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice.
또, 해당 어노테이션들은 지금은 큰 차이가 없더라도 향후 버전에서 새로운 기능을 추가할 수 있음을 염두에 두고 만들어졌다.
예를 들어 만약 @Component 대신 @Service를 붙여두었다면,
향후 버전 업데이트에서 별도 코드의 변경 없이 바로 새로운 기능/관점을 사용할 수 있는 것이다.
때문에 공식문서에서도 @Component 대신 @Service 를 사용하는 것이 분명히 더 좋은 선택이라고 말한다.
PSA(Portable Service Abstraction)
이 부분에 대해 학습하는 과정에서, 리뷰어(우테코 미션 코드리뷰)님이 Spring PSA 라는 키워드를 던져주셨다.
(참고 링크 : https://sabarada.tistory.com/127)
PSA는 Spring의 3대 핵심 가치 중 하나로, 하나의 추상화로 여러 개의 서비스를 묶어둔 것이다.
서비스를 추상화한다는 것은, 추상화 계층을 사용하여 어떤 기술을 내부에 숨기고 개발자에게 편의성을 제공해주는 것이다.
잘 추상화된 인터페이스이다.
사실상 Spring에서 제공하는 대부분의 기능이 PSA라고 할 수 있다.
이번 포스트에서 살펴본 웹 MVC 계층을 위한 어노테이션들도 PSA를 지향하고 있다고 볼 수 있겠다.
@Controller와 @Repository를 통해서는 이미 우리가 추상화된 서비스들을 잘 사용하고 있다.
@Service 어노테이션에는 지금은 제공되는 서비스가 없더라도
버전 업데이트에서 추상화 계층 내부에 새로운 내용이 추가되었을 때 우리는 코드 변경을 할 필요가 없다.
이를 통해 얻은 결론
나만의 기준을 가지고 코드를 작성하는 것은 중요하다.
하지만 프레임워크를 사용할 때에는, 그 프레임워크에서 어떤 의도를 가지고 있는지도 확인해보는 것이 좋은 것 같다.
당장 제공되는 기능 뿐만 아니라 해당 프레임워크의 디자인 철학, 원칙과 관용적인 사용법 또한 중요하다는 것을 깨달았다.