이전글에서 이어지는 내용
[이커머스 프로젝트] 주문 로직 - 리팩토링 2 (제네릭과 리플렉션)
[이커머스 프로젝트] 주문 로직 - 리팩토링 2 (제네릭과 리플렉션)
이전글에서 이어지는 내용[이커머스 프로젝트] 주문 로직 - 전략 패턴 적용(리팩토링) [이커머스 프로젝트] 주문 로직 - 전략 패턴 적용(리팩토링)초기 코드현재 주문로직은 상품을 직접 주문하
mrxx.tistory.com
문제 발생
Caused by: java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap')
at ecommerce.coupang.service.order.strategy.OrderStrategyProvider.getGenericType(OrderStrategyProvider.java:34) ~[main/:na]
at ecommerce.coupang.service.order.strategy.OrderStrategyProvider.<init>(OrderStrategyProvider.java:27) ~[main/:na]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[na:na]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:209) ~[spring-beans-6.2.0.jar:6.2.0]
... 49 common frames omitted
리팩토링을 완료한 후 프로젝트를 실행해보니 ClassCastException이 발생하였다OrderStrategyProvider
에서 발생한 오류인데
잘못된 타입으로 캐스팅을 시도해서 발생한 문제란다
리플렉션을 잘 모른채로 사용해서 발생한것같다
한번 디버거로 문제를 찾아보아야겠다
디버깅
여기 부분에 브레이크포인트를 걸어 보았다
문제를 바로 발견할 수 있었다
일단 각각의 Strategy를 가져오는것엔 문제가없지만
Strategy들을 가져올때 CartOrderStrategy$$SpringCGLIB$$... 이렇게 적혀있는 걸 보았다
내가 알기론 CGLIB는 스프링에서 프록시객체를 생성할때 사용하는 라이브러리로 알고있다
그럼 원본 객체가 아닌 프록시 객체인 것이다
이 부분도 확안해보았다
원래 예상대로면 OrderStrategy가 있어야하는데 프록시들이 보여진다
GPT에게 물어보니 AopUtils.getTargetClass()를 사용하여 원본 클래스를 추출해낼수있다고한다
해결
public OrderStrategyProvider(List<OrderStrategy<?>> orderStrategies) {
for (OrderStrategy<?> strategy : orderStrategies) {
Class<?> targetClass = AopUtils.getTargetClass(strategy); // 프록시에서 원본 클래스 추출
Class<?> genericType = getGenericType(targetClass);
if (genericType != null)
strategyMap.put(genericType, strategy);
}
}
private Class<?> getGenericType(Class<?> strategy) {
return (Class<?>) ((ParameterizedType) strategy.getGenericInterfaces()[0])
.getActualTypeArguments()[0];
}
AopUtils.getTargetClass(strategy); 를 추가하여 원본 클래스를 추출하고
getGenericType() 메서드로 넘겨주었다
다시한번 디버거를 통해서 확인해보겠다
targetClass에 원본 클래스가 추출되어 잘 동작한다
근데 왜 프록시 객체가 주입되었나 궁금해졌다
또 GPT에게 물어보니 여러가지 조건이있다고한다
1. AOP기능 적용 ( @Transactional, @Async, 커스텀 AOP....)
2. 인터페이스 기반 프록시 생성 (인터페이스를 구현한 빈을 주입받을경우)
3. 순환 참조 방지
4. 지연 초기화 ( @Lazy )
이번엔 OrderStrategy 인터페이스를 구현한 Strategy들을 주입 받았기 때문에 프록시 객체가 생성된 것 같다
아직 완벽하게 이해하지 못해 추후에 좀더 공부를 해야할 것 같다
그리고 이번에 디버거를 사용해보았는데 아직 디버거 사용하는데 익숙하지않아서
꾸준히 디버거를 사용해봐야겠다