토이 프로젝트를 진행하다 Spring Security 없이 토큰을 통한 인가를 해야 했다.
이때, 음악(Music)과 회원(User)이라는 엔티티가 다대일(양방향)이고, 회원에서 굳이 음악을 가져올 일이 없는 경우가
종종 있어 지연로딩으로 가져오려 하는 도중 LazyInitializationException 이 발생하여 이에 대해 기록하고자 한다.
Interceptor란?
Spring MVC에서 요청이 컨트롤러로 위임되기 전, 위임된 후, 뷰 처리 단계에서 특정 로직을 할 수 있는 스프링에서
제공하는 장치
쉽게 설명하자면, "요청에 대한 작업 전/후로 가로채어 특정 로직을 수행하는 역할" 정도로 설명할 수 있다.
HandlerInterceptor 인터페이스를 직접 구현하여, 인터셉터를 직접 구현할 수 있다.
LazyInitializationException이란?
JPA에서 관리하는 세션(정확히는 persistence context)이 종료된 후, 관계가 설정된 엔티티를 참조하려고 할 때 발생한다.
Lazy(지연로딩)으로 엔티티를 가져올 때, persistence context가 종료되었다면 발생하는 예외이다.
대표적인 해결 방법으로는 @Transactional, fetch-join, @EntityGraph 가 있다.
문제 해결 시도
우선 Spring Security가 없는 관계로 Interceptor를 사용해야 한다. (물론 dependency를 추가해 주면 가능하지만, Filter 외의 인터셉터 방식으로 시도해 보고자 시도했다.)
Spring Boot 설정 중 OSIV가 기본적으로 켜져 있으므로, 영속성 컨텍스트가 레이어를 넘어 동일하다고 생각하여,
코드를 작성했으나, 안타깝게도 다음과 같은 이유로 실패했다.
LazyInitializationException 이 인터페이스에서 발생한 이유
Spring Boot에서 OSIV가 켜져 있는 경우, OpenSessionInViewInterceptor라는 클래스가 자동으로 등록된다.
하지만, 커스텀 인터셉터가 선 작업 후, OpenSessionInViewInterceptor가 영속성 컨텍스트를 공유하게 된다.
따라서 영속성 컨텍스트가 공유되지 않아 예외가 발생한 것이었다.
문제 해결
OpenSessionInViewInterceptor를 직접 빈으로 등록한다.
기존 방식은 HandlerInterceptor -> OpenEntityManagerInViewInterceptor -> Controller -> ...
에서 OpenSessionInViewFilter -> HandlerInterceptor -> OpenEntityManagerInViewInterceptor -> Controller -> ...
으로 변경된다. 위와 같이 변경될 경우, OpenSessionInViewFilter에서 영속성 컨텍스트가 열려 문제가 해결된다.
(물론 위 경우에는 OSIV를 켜져 있기에 동작한다.)
@Bean
public FilterRegistrationBean<OpenEntityManagerInViewFilter> registrationBean() {
FilterRegistrationBean<OpenEntityManagerInViewFilter> registrationBean = new FilterRegistrationBean<OpenEntityManagerInViewFilter>();
OpenEntityManagerInViewFilter filter = new OpenEntityManagerInViewFilter();
registrationBean.setFilter(filter);
registrationBean.setOrder(5);
return registrationBean;
}
이상입니다.
참고
'Spring > 공부' 카테고리의 다른 글
[Spring Security] 스프링 시큐리티란? (0) | 2023.01.16 |
---|---|
[Spring Core] 스프링 빈 생명주기와 스코프 (0) | 2023.01.14 |
[Spring Core] 컴포넌트 스캔과 의존성 주입 (0) | 2023.01.14 |
[Spring Core] 스프링 컨테이너와 스프링 빈 (0) | 2023.01.11 |