인프런 커뮤니티 질문&답변

영한노게임님의 프로필 이미지

작성한 질문수

스프링 핵심 원리 - 고급편

프록시 팩토리 - 적용2

proxyFactory cglib 자동적용 관련 질문

작성

·

16

0


@Bean
public Advisor logTraceAdvisor(LogTrace logTrace) {
    LogTraceAdvice logTraceAdvice = new LogTraceAdvice(logTrace);
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut(), logTraceAdvice);
    return advisor;
}

@Bean
public Pointcut pointcut() {
    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    pointcut.setMappedNames("request*", "order*", "save*");
    return pointcut;
}

@Bean
public OrderControllerV2 orderControllerV2(LogTrace logTrace) {
    OrderControllerV2 target = new OrderControllerV2(orderServiceV2(logTrace));

    ProxyFactory proxyFactory = new ProxyFactory(target);
// 이걸 넣었더니 되네요
    proxyFactory.setProxyTargetClass(true);
//
    proxyFactory.addAdvisor(logTraceAdvisor(logTrace));
    return (OrderControllerV2) proxyFactory.getProxy();
}

@Bean
public OrderServiceV2 orderServiceV2(LogTrace logTrace) {
    OrderServiceV2 target = new OrderServiceV2(orderRepositoryV2(logTrace));

    ProxyFactory proxyFactory = new ProxyFactory(target);
    proxyFactory.addAdvisor(logTraceAdvisor(logTrace));
    return (OrderServiceV2) proxyFactory.getProxy();
}

@Bean
public OrderRepositoryV2 orderRepositoryV2(LogTrace logTrace) {
    OrderRepositoryV2 target = new OrderRepositoryV2();

    ProxyFactory proxyFactory = new ProxyFactory(target);
    proxyFactory.addAdvisor(logTraceAdvisor(logTrace));
    return (OrderRepositoryV2) proxyFactory.getProxy();
}

proxyFactory.setProxyTargetClass(true); 이 없더라도 자동으로 ProxyFactory가 인터페이스 기반이 아닐경우 cglib으로 프록시를 생성해야하는데 위의 주석사이의 코드가 없을 경우 다음과 같은 에러가 뜹니다.(jdk로 하려다가 실패하는 모양인데 이 말은 자동으로 cglib으로 proxyfactory가 돌리지 못했다...

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [hello.proxy.app.v2.OrderControllerV2]: Factory method 'orderControllerV2' threw exception; nested exception is java.lang.ClassCastException: class jdk.proxy2.$Proxy50 cannot be cast to class hello.proxy.app.v2.OrderControllerV2 (jdk.proxy2.$Proxy50 is in module jdk.proxy2 of loader 'app'; hello.proxy.app.v2.OrderControllerV2 is in unnamed module of loader 'app')

강제로 setProxyTargetClass(true)로 하여금 설정해준다면 자동 설정기능을 사용하지 않은 것이라.. 왜 이런지 궁금하네요.

제 코드가 실습 실제 코드와 약간 달라 실습 코드를 복사해서 쳐봐도 동일한 증상이 나타났어요.

또한 setPorxyTargetClass를 지정해줘야 한다면 왜 컨트롤러에서만 해도 다 되는지도 의문입니다.

 

답변 2

0

import hello.proxy.app.v2.OrderControllerV2;
import hello.proxy.app.v2.OrderRepositoryV2;
import hello.proxy.app.v2.OrderServiceV2;
import hello.proxy.config.v3_proxyfactory.advice.LogTraceAdvice;
import hello.proxy.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
plugins {
	id 'org.springframework.boot' version '2.5.5'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//테스트에서 lombok 사용
	testCompileOnly 'org.projectlombok:lombok'
	testAnnotationProcessor 'org.projectlombok:lombok'
}

test {
	useJUnitPlatform()
}

0

안녕하세요, 인프런 AI 인턴입니다.

ProxyFactorysetProxyTargetClass(true) 메서드는 CGLIB 기반의 프록시 생성 여부를 명시적으로 설정하는 부분입니다. 일반적으로 스프링은 인터페이스가 존재하면 JDK 동적 프록시를 사용하고, 그렇지 않으면 CGLIB을 활용하여 프록시를 만듭니다. 그러나, 프록시 생성에 실패하고 ClassCastException이 발생하는 경우, 이 설정이 필요할 수 있습니다.

이유와 해결 방법:

  1. JDK 동적 프록시: JDK 동적 프록시는 인터페이스 기반으로만 프록시를 생성할 수 있습니다. 인터페이스가 명시되지 않았거나, 잘못된 경우 ClassCastException이 발생할 수 있습니다.

  2. CGLIB 프록시: 이를 해결하기 위해 setProxyTargetClass(true)를 설정하여 강제로 CGLIB 프록시를 사용하게 합니다. 이는 인터페이스 없이도 프록시를 생성할 수 있고 클래스 기반의 메서드를 프록시로 사용할 수 있도록 해줍니다.

  3. 컨트롤러에서의 동작: 다른 컴포넌트(NS: Bean)들과 다르게 Spring의 Controller 계층은 View와의 상호작용 때문에, 프록시 구성 방식에 차이가 있을 수 있습니다. 이는 Spring의 DispatcherServlet이 기본적으로 CGLIB 프록시를 추천합니다.

참고 링크

강사님이 직접 유사한 문제에 대한 해결 방안을 커뮤니티에 남긴 적이 있습니다. 참고하시어 Proxy 설정 문제를 해결하는 데 도움을 받을 수 있습니다.

문제가 해결되지 않거나 추가적인 질문이 있으시면, 추가로 질문 남겨주세요. 지식공유자님이 빠르게 도움을 드릴 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

아 죄송합니다. OrderControllerV2가 V1컨트롤러 인터페이스 구현으로 코드가 짜져있었네요 복붙의 최후입니다....