[TIL] 23.04.08 에러노트 . because it is a JDK dynamic proxy that implements

hyewon jeong·2023년 4월 7일
0

TIL

목록 보기
114/138

1 발생

모든 AWS Service와 mySql 연동을 종료 한 후 프로젝트를 연동했을때 발생한 에러를 해결한 후 생긴 또다른 에러였다.


2 시도

2-1 1차 시도

https://github.com/javamelody/javamelody/issues/666
위의 블로그를 보고

application.yml
aop:
auto: true
proxy-target-class: true

proxy-target-class에 대해 알아봤다.

2-2 2차 시도


3 원인

근본 원인 : 스케줄러와 이메일인증시 비동기처리를 같이 적용했을때 발생했다.
스케줄러와 비동기처리를 동시에 사용하면 충돌이 발생할 우려로 주의해서 사용해야한다.

The bean 'emailServiceImpl' could not be injected because it is a JDK dynamic proxy 

Action:

Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.

chatGPT 에게 물어봤다.

위의 에러는 스프링에서 기본적으로 JDK dynamic proxy를 사용하는 경우 발생할 수 있습니다. 이 에러는 'emailServiceImpl' 빈이 인터페이스를 구현하는 JDK dynamic proxy임을 알리며, 이 경우 해당 빈을 구현한 클래스로 주입할 수 없음을 나타냅니다.

1) 이 문제를 해결하는 방법 중

하나는 해당 빈을 해당하는 인터페이스로 주입하는 것입니다. 즉, @Autowired 대신 @Autowired(required=false)를 사용하고, 구체적인 구현 대신 해당 인터페이스로 필드를 선언하면 됩니다.

2) 다른 해결책은 @EnableAsync(proxyTargetClass = true)와 @EnableCaching(proxyTargetClass = true)

와 같은 애노테이션을 사용하여 CGLIB 프록시를 강제로 사용하도록 설정하는 것입니다. 이를 통해 JDK dynamic proxy 대신 CGLIB proxy를 사용하여 해당 빈을 주입할 수 있습니다.

4) @EnableAsync(proxyTargetClass = true) 로 해결 되는 이유

@EnableAsync(proxyTargetClass = true) 애노테이션을 사용하면, CGLIB 프록시를 사용하여 동일한 스레드에서 비동기 메서드를 호출하도록 할 수 있습니다. 이를 통해 동일한 스레드를 사용하면서 스케줄러와의 충돌을 방지할 수 있습니다.

보통 스프링에서 @Async 애노테이션을 사용하여 비동기 메서드를 호출하면, 새로운 스레드가 생성되어 비동기 처리를 수행합니다. 이때 스레드 풀을 사용하여 스레드를 관리하며, 작업이 완료되면 스레드 풀에 스레드를 반환합니다.

그러나 스케줄러와 같이 동일한 스레드에서 작업을 수행해야 할 때는, 스레드 풀에서 새로운 스레드를 생성하는 것이 아니라 기존에 사용 중인 스레드를 재사용해야 합니다. 이때 CGLIB 프록시를 사용하여 기존 스레드를 재사용하도록 할 수 있습니다.

CGLIB 프록시는 클래스를 상속하여 새로운 클래스를 생성하는 방식으로 프록시를 생성합니다. 이때 프록시 객체는 원본 객체와 같은 클래스를 상속하므로, 동일한 스레드에서 메서드를 호출할 수 있습니다. 따라서 proxyTargetClass 속성을 true로 설정하여 CGLIB 프록시를 사용하면, 동일한 스레드에서 비동기 메서드를 호출할 수 있습니다.

즉, @EnableAsync(proxyTargetClass = true) 애노테이션을 사용하면, 스프링은 CGLIB 프록시를 생성하여 비동기 메서드 호출을 처리하고, 이때 기존에 사용 중인 스레드를 재사용하여 동일한 스레드에서 비동기 처리를 수행합니다. 이를 통해 스케줄러와의 충돌을 방지할 수 있습니다.


4 해결

@EnableAsync(proxyTargetClass = true)

으로 설정하면 해결~~~

@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
@EnableAsync(proxyTargetClass = true)
public class Final8TeamProjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(Final8TeamProjectApplication.class, args);

    }
}

https://huisam.tistory.com/entry/springAOP

profile
개발자꿈나무

0개의 댓글