[Spring] AOP 내부 메서드 호출 문제 해결기 (feat.cache)

yeonjoo913·2023년 12월 5일
0

Spring

목록 보기
18/19

API 캐싱 적용 중 겪은 문제를 해결하는 과정을 정리해보았다.

문제

대시보드 조회 API에도 캐싱을 적용할 필요가 있어서 보던 중 해당 메소드에는 파라미터가 존재하지 않아 구분이 힘들다는 것을 알았다.
해당 API는 랜덤값으로 바뀌는 데이터로 "프로젝트 이름:메소드이름:키워드No." 형식으로 구분이 필요했다.

public DashboardResponse getDashBoard() {
    Keyword keyword = getRandomKeyword();
    랜덤 키워드기준 대시보드 로직...
}

해결 시도1(실패) - 메소드 분리

파라미터가 존재하는 메소드로 분리하여 해당 메소드에 AOP 어노테이션을 추가하면 가능할 것이라고 생각하였다.

public DashboardResponse getDashBoard() {
    Keyword keyword = getRandomKeyword();
	return getDashBoardByKeyword(keyword);
}

@RedisCacheable(value = "ProjectName:getDashBoardByKeyword",key = "#keyword.id")
public DashboardResponse getDashBoardByKeyword(Keyword keyword) {
		랜덤 키워드기준 대시보드 데이터 로직...
}

실패 이유
-> AOP는 프록시 기반이다. 프록시 기반일 경우 외부 메소드에서 호출하는 경우만 프록시를 타고 동작한다. 즉, 위와 같은 경우는 내부 메소드를 타고 있는 상황이라 캐싱 적용이 불가능했다.

이전에 겪고 정리했던 이슈라 빠르게 파악했다. 애초에 시도안해야 했지만 그래도 빨리 발견한데 의의를 둔다..ㅎ
[Spring 시리즈 13번]Spring-동일한-Bean에서-Transactional-처리

해결 시도2(실패) - Aspect 로직 변경

파라미터가 없는 getDashBoard()에 어노테이션을 적용하고, joinPoint.proceed() 후 조회해온 값에서 keywordId 값을 조회하면 된다고 생각했다.

service.java

@RedisCacheable(value = "ProjectName:getDashBoard")
public DashboardResponse getDashBoard() {
    Keyword keyword = getRandomKeyword();
    랜덤 키워드기준 대시보드 데이터 로직...
}

aspect.java

final Object methodReturnValue = joinPoint.proceed();

switch (redisCacheable.cacheName()){
  case "ProjectName:getDashBoard" -> {
      ((DashBoardResponse) methodReturnValue).getId();
			...
	}
...
}

실패 이유
-> 현재 프로젝트는 멀티 모듈로, Core모듈과 Redis 모듈은 서로 분리되어있는 구조이다.

DashBoardResponse는 core 모듈에 존재하고, aspect는 redis 모듈에 존재한다.

redis에서 core에 있는 클래스를 사용할 수 없어서 위와 같은 방법으로 진행하게 되면 기존 모듈 구성을 많이 변경하게 되므로 해당 방법을 사용하지 않았다.

해결 시도3(성공) - 직접 등록된 Bean 조회 후 사용(지연 조회)

ObjectProvider 를 이용해서 스프링 컨테이너에 등록된 Bean을 조회하고, 조회된 Bean을 통해 메서드를 호출하는 것으로 내부 메서드 호출 문제를 해결하는 방식이다.

@Service
@RequiredArgsConstructor
public class AdditionService {
	private final ObjectProvider<AdditionService> objectProvider;

	public DashboardResponse getDashBoardData() {
    	Keyword keyword = getRandomKeyword();
    	AdditionService service = objectProvider.getObject();
    	return service.getDashBoardByKeyword(keyword.getId(),keyword.getKeywordName());
  	}

  	@RedisCacheable(value = "ProjectName:getDashBoardByKeyword",key = "#keywordId")
  	public DashboardResponse getDashBoardByKeyword(Long keywordId,String keywordName) {
		...
  	}
}

이 방식은 getDashBoardData()메소드가 호출되는 시점에 Bean을 조회하게 된다(지연조회)

Reference.

profile
주니어 백엔드 개발자. 까먹는다 기록하자!

0개의 댓글