[Spring] Service Impl, 왜 쓰는건데? (feat. AOP)
백엔드 개발자의 길을 걷기로 한 이상 다음과 같은 설계 방식을 한번쯤은 겪어봤을 것이다.
1
2
3
4
public class HelloServiceImpl implements HelloService {
@Override
// 무언가를 처리하는 로직
}
그냥 Service 클래스 하나만 만들면 끝 아니야? 라고 생각한 당신. 잘 들어보십쇼.
Impl 클래스를 사용해온 관습적인 이유
1. 객체지향 프로그래밍의 원칙을 지키기 위해
다형성
과 개방-폐쇄의 원칙
인터페이스를 사용하면 특정 기능에 대한 변경사항이 있어도 쉽게 수정이 가능하다.
구현체(Impl)를 수정하더라도 다른 코드에 영향을 주지 않기 때문이다.
즉, 이 설계 방식의 목적은 하나의 역할을 여러 방식으로 구현하는 자유로운 확장을 보장하기 위함이다.
2. 객체에 대한 설계와 이를 구현한 코드의 변경 가능성
인터페이스를 만드는 이유는 코드의 확장성과 재활용성
을 높이기 위함이다.
대부분의 프로젝트는 인터페이스와 구현체가 1:1로 만들어져 사용되고 있다.
그렇다면 우리는 이 설계 방식을 계속해서 사용해도 되는 것일까?
현재 사용중인 인터페이스와 구현체는 지금은 1:1 관계를 맺고 있을지도 모르지만 추후에 서비스가 커지고 변화하면 구현체 클래스는 확장될 가능성을 가지고 있다. 따라서
객체 지향적인 관점
에서는 인터페이스를 사용하는 것이 바람직하다.또한 이러한 구조는 협업에서 이점으로 작용될 수 있다.
프로젝트를 시작할 때 설계자가 큰 뼈대를 구성하고, 나머지 작업자들은 그에 맞는 실제 구현을 하게 되는 경우가 있는데, 이때 함수명, 반환값, 파라미터 등을 설계자가 만들어놓은 인터페이스에 맞춰 코딩할 수 있다.
AOP란?
AOP는 핵심적인 기능에서 부가적인 기능을 분리하여 Aspect
라는 모듈 형태로 만들어서 설계하고 개발하는 방법
Aspect란?
Aspect
는 부가기능을 정의한 코드인 Advice
와 Advice
를 어디에 적용할 지 결정하는 PointCut
을 합친 개념
AOP 용어 정리
Target
- 핵심 기능을 담고 있는 모듈로 부가 기능을 부여할 대상
Advice
- 타겟에게 제공할 부가 기능을 담고 있는 모듈
Join Point
Advice
가 적용될 수 있는 위치를 의미Target
객체가 구현한 인터페이스의 모든 Method는Join Point
Point Cut
Advice
를 적용할Target
의 Method를 선별하는 정규표현식Point Cut
표현식은 execution으로 시작하고 Method의 Signature를 비교하는 방법을 주로 이용
Aspect
- AOP의 기본 모듈
Advice
+Point Cut
- 싱글톤 형태의 객체로 존재
Advisor
Advice
+Point Cut
- Spring AOP에서만 사용되는 특별한 용어
Weaving
Point Cut
에 의해서 결정된Target
의Join Point
에Advice
를 삽입하는 과정- AOP가
Target
의 코드에 영향을 주지 않으면서 필요한Advice
를 추가할 수 있도록 해주는 핵심적인 처리과정.
지금은?
과거에는 Spring에서 AOP를 구현할 때 JDK Dynamic Proxy를 사용했다. (프록시 객체 생성을 위한 인터페이스 생성 필수) 👉 AOP를 사용하여 구현되는 어노테이션들이 동작하기 위해서는 반드시 인터페이스 - 구현체
관계로 작성되어 있어야 함.
그러나 시간이 지나면서 CGLIB
를 기본적으로 포함하여 클래스를 기반
으로 프록시 객체를 생성할 수 있게 되었다.
그럼 Impl 설계를 꼭 해야할까…?
결론부터 말하자면, 현 시점에 와서는 관습적
인 이유로 사용하는 개발자들이 많다고 생각된다.
거의 모든 프로젝트에 적용되는 1:1 구성의 Impl 설계는 불필요한 클래스만 만드는 행동이라고 보인다.