서버 살인사건 .. 범인은 @Resource ...

두별·2022년 11월 12일
0

TIL

목록 보기
29/46
post-thumbnail

JWT 관련 Filter 로직을 변경하여 서버에 반영했더니 404에러가 발생.. 서버가 죽어버렸다..

Local 환경에서는 잘 동작해서 원인이 무엇인지 차이점을 찾아봤는데 개발서버에는 아래와 같은 Log를 발견

Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) 
throws javax.servlet.ServletException,java.io.IOException] 
because it is marked as final: Consider using interface-based JDK proxies instead!

스택오버플로우에 찾아보니 AOP 관련된 에러인 것 같은데 내가 최대한 파악해볼 수 있는 건 다음과 같다.

AOP를 구현하는 두가지 방식

1. JDK 다이나믹 Proxy 방식
Java에서 제공하며 인터페이스 기반으로 Proxy를 생성해주는 방식이기 때문에 인터페이스의 존재가 필수적이다.

2. Spring이 사용하는 CGLIB 라이브러리 방식
인터페이스의 유무를 판단하여 Proxy 생성

[참고] JDK Dynamic Proxy와 CGLIB의 차이점은 무엇일까?

  1. https://gmoon92.github.io/spring/aop/2019/04/20/jdk-dynamic-proxy-and-cglib.html
  2. https://velog.io/@suhongkim98/JDK-Dynamic-Proxy%EC%99%80-CGLib

에러가 발생한 Filter 코드

@Component
public class AccessTokenFilter extends OncePerRequestFilter {

	@Resource(name="roleService")
    private RoleService roleService;
    
    ...
}

여기서 서비스 의존성 주입을 @Resource로 하고 있는데 이 것이 원인이였다.

@Resource와 @Autowired의 차이점

@Resource 어노테이션은 DI를 하기 위해 자바에서 지원 -> JDK 다이나믹 프록시 방식을 사용 → 인터페이스가 필요 → 서비스를 인터페이스로 구현하지 않아 오류가 발생한 것으로 추측

@Autowired는 Spring CGLIB 방식을 사용하기 때문에 인터페이스로 구현하지 않았어도 의존성 주입이 가능하다.

해결 !

@Resource를 @Autowired 로 바꿔서 해결!

AOP 관련 설정으로 인해 스프링이 빈을 만들때 proxy를 생성한다면, @Resource 어노테이션은 interface가 필요한데 Service는 현재 인터페이스로 구현되어있지 않아 에러가 발생한 것으로 추측 ( 뇌피셜이라 정확한 정보는 아님 )

기존 서비스를 인터페이스로 바꾸는 것은 무리가 있으므로 간단히 어노테이션 변경만 해서 문제를 해결했다.

1개의 댓글

comment-user-thumbnail
2022년 11월 20일

대단해요

답글 달기