처음에 @PostConstruct를 사용해서 DB 내의 통화 데이터에
환율이 0 이하인 경우를 찾아내어 있다면 log로 error 메시지를 출력하는 기능을 구현할 때
새로운 클래스를 만들었다.
@Slf4j
@Component
@RequiredArgsConstructor
public class CurrencyRateValidator {
private final CurrencyRepository currencyRepository;
@PostConstruct
public void validateCurrencyRate(){
List<Currency> currencies = currencyRepository.findAll();
currencies.forEach(currency -> {
BigDecimal exchangeRate = currency.getExchangeRate();
if (exchangeRate.compareTo(BigDecimal.ZERO) <= 0 ) {
log.error("Currency exchange rate is less than zero");
}
});
}
}
잘 구동되었고 넘어가려던 찰나
굳이 새로운 클래스를 만들어야하나? 라는 생각이 들었다.
구동될 때 검증되는 부분이니 단순히 생각해 common 패키지 내부에 이 클래스를 만들었었는데
코드를 자세히 보면 CurrencyRepository
를 사용하는 모습이 보인다.
내가 이해한 @PostConstruct
의 동작 순서는
빈 생성: Spring 컨테이너가 빈을 생성한다.
의존성 주입: 생성된 빈에 필요한 의존성이 주입된다. (생성자, 필드 등등..)
초기화 메서드 호출: 모든 의존성이 주입된 후, @PostConstruct
가 붙은 메서드가 호출된다.
빈 사용: 초기화가 완료된 후, 빈은 애플리케이션에서 사용될 수 있다.
이런 식으로 진행되는 것이었고
빈으로 등록하기 위해 @Component
를 사용하는 것이었는데
이것과 구조가 유사한 계층이 이미 존재했다.
바로 서비스 계층이었다.
이미 CurrencyService
계층에는 @Service
내부에 @Component
가 존재했고
CurrencyRepository
로 서비스 계층에서 이미 사용하고 있었기에
새로운 클래스를 만들기보다 서비스 클래스 내부에 @PostConstruct
를 사용한 초기화 메서드를
위치시키는게 더 맞다는 판단이 들었다.
따라서 서비스 계층으로 해당 메서드를 옮겼고 잘 동작되는 모습도 보았다.
이 판단이 맞는 판단인지는 피드백 때 알아보아야겠다.
원래 왼쪽의 형태로 구성되어있던 프로젝트 구조를 조금 더 깔끔하게 만들어보고자
도메인 별로 쪼개어 내부에 service, repository, controller, dto, entity 패키지를
만들어서 쉽게 원하는 곳으로 찾아갈 수 있게 만들었다.
그리고 실행을 해봤는데...
갑자기 냅다 이런 오류가 발생하는 것이었다.
뭐지??
creating bean 에서 문제가 생기는데..
내가 만든 exchange 하위 패키지에 있는 모든 곳에서 bean 주입 관련 에러가 발생하는 듯 보였다.
수많은 웹서핑, ai의 도움을 받아도 전혀 해결할 수 없었고..
결국에 튜터님께 찾아가 자문을 구했다
이런 저런 폴더들을 뒤져보던 중
평소 맨 윗줄에서 파랗게 파일 명을 보여주는 에러만 즐겨보던 나에게
튜터님이 맨 아랫줄 에러를 한번 보죠. 라고 하셨고
Caused by: org.hibernate.query.SemanticException: Could not resolve
class 'com.sparta.currency_user.exchange.ExchangeGroupResponseDto'
named for instantiation [select new com.sparta. .. 이하 생략
이 줄을 보자마자 나는 바로 알아차릴 수 있었다...
바로 ExchangeRepository에서 사용하고 있는
@Query(
"select new com.sparta.currency_user.exchange.dto.ExchangeGroupResponseDto(count(u), sum(u.amountInKrw))"
+ " from UserCurrency u where u.user.id = :id and u.status = :status")
ExchangeGroupResponseDto findGroupExchangeRequestByUserId(Long id, UserCurrencyStatus status);
jpql에서 발생하는 문제였다..
나는 jpql을 사용해서 entity가 아닌 dto로 바로 변환을 받는 기술을 사용하고 있었고
당연히 패키지 구조를 바꿨기에 select new 뒤에 오는 DTO 경로도 바꿔줬어야했다.
파일을 옮길 때 대부분은 인텔리제이에서 알아서 리팩터링을 해주니
내가 직접 적은 sql문에 영향을 끼칠거라고 생각조차 못한 것이었다..!!!
바로 패키지 경로를 고치니 모든 것이 해결되었고
이를 통해 한가지의 교훈을 얻을 수 있었다.