작성
·
497
·
수정됨
1
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예
[질문 내용]
안녕하세요. 강의 잘 듣고 있습니다.
질문은 "단순 데코레이터를 만들고 싶을 때 SpringAOP를 사용해도 되는가?"입니다.
질문 매뉴얼의 답이 없는 질문에 포함되는 것 같아 부가설명을 적어보겠습니다.
개인적으로 이전부터 관심사와 의존성을 분리하고 싶어 데코레이터 패턴을 한번씩 쓸 때가 있었습니다.
예를 들면 다음과 같습니다.
게시글이 작성되면 특정 유저들에게 알림 메세지를 전송해야 한다.
게시글이 수정되면 읽기 전용 모델의 캐시를 갱신해야 한다.
그럼 [컨트롤러 - 알림데코레이터 - 캐시데코레이터 - 서비스 - 리포지토리 ]가 되는 거죠.
이 때 데코레이터-서비스 체인을 구성해야 하는데 2가지 방법이 있었습니다.
@Configuration에서 매뉴얼하게 체인 구성한 뒤 빈 생성
가장 앞단의 데코레이터에 Primary를 달고 이후 순서에 따라 생성자 파라미터 주입시 @Qualifier로 구현체 주입
1번 같은 경우에는 각 데코레이터마다 의존성이 많아질 수록 작성해야 하는 코드가 많아져서 제외를 했습니다.
그래서 2번 방법을 사용하고 있고 다음과 같은 문제를 대면했습니다.
특정 구현체가 뒷 순서 구현체를 알아야 한다. (의존성 발생) 그것도 컴파일 에러가 나지 않는 문자열(빈 이름)의 형태로.
public class PostServiceMessageDecorator implements PostService {
private final PostService postService;
public PostServiceMessageDecorator(
@Qualifier("postServiceCacheDecorator") PostService postService
) {
this.postService = postService;
}
}
체인 순서를 구성하는 것이 다소 번거롭고, 순서가 변경되거나 추가, 제거되면 코드를 바꿔야 한다. (다시 한 번 컴파일 에러가 나지 않는 문자열의 형태로)
서비스 내에서 데코레이터가 붙지 않는 메소드도 구현을 해줘야 한다.
그런데 SpringAOP를 사용하면 3가지 문제를 모두 해결할 수 있는 것이 아닌가 하는 생각이 듭니다.
포인트컷도 잡는 것만 잡으면 되니까 데코레이터가 굳이 안붙어도 되는 메소드를 구현할 필요도 없구요.
Order로 순서도 간편하게 변경이 가능하니까요.
앞서 강의에서 패턴은 의도가 중요하지 실제 구현체는 다양한 방법으로 구현될 수 있다고 하신 말씀이 머릿속에 맴도는데...
Aspect를 만들고 네이밍만 EntityServiceSomethingDecorator 라고 이름만 붙이면 되는게 아닌가 하는 생각이 듭니다.
그러나 이 방법을 사용하는데 약간의 거부감이 있는데 AOP가 태생적으로 횡단 관심사를 해결하기 위한 기술이라는 사실 때문입니다.
저는 흩어져 있는 공통 관심사 코드를 여기 저기 작성하지 않고 한 군데에서 작성하도록 한 게 개발 의도라고 생각했거든요.
하지만 예시의 경우는 흩어져 있는 관심사가 아니라 특정 로직에 부가 로직을 몇 개 붙였다 뗐다 하고 싶을 뿐입니다.
그렇다면 단순 데코레이터를 만들기 위해 SpringAOP를 사용하는 것은 SpringAOP의 개발 의도와는 약간 다른 사용법이 될 수 있고,
보통 특정 기능을 개발 의도와 다른 방향으로 사용하면 예상하지 못한 부작용이 발생하더라구요.
이 지점에서 혹시 인사이트를 얻을 수 있을지 질문을 올려봅니다.
질문을 조금 다르게 얘기하면 "특정 메서드 혹은 클래스만을 위한 Aspect를 만들어도 되는가?"가 되겠네요.
만약 이 경우에 AOP사용은 지양하는 것이 좋다고 생각하신다면, 매뉴얼하게 데코레이터 클래스를 작성하는 것 외에 권장하실만한 방법이 있을까요?
답변 2
1
자답입니다...
몇 가지 테스트 해보고 나니 개인적으로는 다음과 같은 측면에서 인터페이스 기반으로 직접 구현하는게 낫다고 판단됩니다.
횡단 관심사가 아닌 특정 메소드를 타겟으로 할 경우 포인트 컷을 잡는게 생각보다 귀찮습니다. 문자열이라는 문제도 있구요... IDE가 반환 클래스명이나 메소드명이 바뀌면 함께 바꿔주지만 반환 타입 자체가 바뀌거나 파라미터가 추가되면 따로 보정 안해주는 것 같습니다.
파라미터의 순서나 타입의 변경에 취약합니다. 1번이랑 유사한데 컴파일 시점에서 알 수 있는 방법이 없네요. 파라미터에 의존적이지 않은 로직에만 적용하는 편이 좋은 것 같습니다.
인터페이스로 구현할 경우 트랜잭션 처리를 세밀하게 할 수 있습니다.
변경사항에 취약하지 않고 몇 개 정도의 메서드는 공통으로 처리할 수 있어야 가성비가 맞을 것 같습니다.
질문하기 전에 실험해보라는 말을 다시 새기고 갑니다....ㅎㅎ....................
감사합니다.