돌고 돌아 SpringBoot 진영 항상 논쟁거리인 SecurityContext & Persistence 이다.
거의 정답은 정해져있다고 생각하는 바이지만, 언제나 그렇듯 개발에는 정답이 없다.
그러므로 관련 주제에 대해 딥다이브를 하게되었다면 면밀히 살펴보길 바란다.
만약 SpringContext 에 Persistence 를 처리하게끔 하기로했다면, 해당 포스트의 성능 섹션으로 넘어가라
사내 논의 중 SecurityContext 에 대해 두 가지 의견으로 나뉘었다.
SecurityContext 에 사용자 엔티티의 메타데이터만을 넣을 것인가 — meIdx, meName 등등
SecurityContext 에 사용자 엔티티 자체를 넣어둘 것인가
1번을 사용한다면 트랜잭션 시작과 함께 사용자를 영속화하기 위해 조회를 한 번 해야할 것이고,
2번을 사용한다면 FilterChain 에서 SecurityContext 에 사용자를 넣을 때 영속화를 유지해야할 것이다.
이와 관련하여 공부한 내용을 공유해보고자 한다.
https://velog.io/@ldg031/Spring-MVC-Request-life-cycle
https://dev-coco.tistory.com/173
https://escapefromcoding.tistory.com/352
https://tecoble.techcourse.co.kr/post/2020-09-20-entity-lifecycle-2/
https://jaykaybaek.tistory.com/27
결론부터 말하자면 그냥 사용하면 스프링의 OSIV 의 기본값으로 인해 에러가 발생한다.
이를 방지하기 위해 추가설정을 해줘야한다.
OSIV 까지 설명하면 너무 길어지니 아래 포스트들을 참고해보자.
요컨대 Spring Security 가 동작하는 Filter Chain 에서 처리한 사용자의 영속화가
Filter 이후에 처리되는 Interceptor 기반의 OSIV 까지 전달이 되지 않는다는 것이다.
따라서 Filter-Interceptor-Controller 순으로 처리되는 스프링의 구조 상,
Controller 에서 꺼낸 사용자는 영속화가 되지 않은 사용자이다.
즉 아래와 같이 처리된다.
이를 위해 아래와 같이 OSIV 에 대한 Filter 를 구현하여 영속성을 Filter 단부터 유지하게 할 수 있다.
— 다행히 Spring 에서 OSIV Filter 구현을 할 수 있는 OpenEntityManagerInViewFilter 이라는 클래스를 지원 중이다.
이에 대한 코드는 아래 결론 이후에 Apply 섹션을 참고해보자.
제대로 논하자면 OSIV 의 패턴과 동작과정을 다뤄야한다.
다만 우리의 관심사는 그게 아니다.
우리의 관심사는
영속화된 사용자 엔티티를 Spring Security Filter Chain 에서부터 가지고 있어도 되는가
이다.
즉, OSIV 와 Filter 조작을 했을 때의 후폭풍이 있는가?
이다.
따라서 이에 따른 장단점을 정리하면서 해당 포스트를 마치고자 한다.
💡장점
단점
@Override
// @Transactional ❌
public Optional<User> findOne(String username) {
Optional<User> user = userRepository.findByUsername(username);
if (user.isPresent()) {
// remote call
}
return user;
}
가장 단점이라고 여겨지는 건 스레드 고갈과 데이터베이스의 과부하였다.
데이터베이스 스레드 풀인 HickariCP 와 Tomcat 의 요청에 대한 스레드 풀을 고려해보아야한다.
관련해서 아래 포스트들을 참고해보자.
https://www.baeldung.com/java-web-thread-pool-config
https://www.baeldung.com/hikaricp
기본조건이라고 가정하고, OSIV 를 켰을 때 얼만큼의 요청을 처리할 수 있는지 연산해보았다.
아래 컴퓨팅파워에서 다음과 같았다. (GPT 돌림 주의,,)
컴퓨팅파워
메모리 사용
Tomcat 요청 가능수
HickariCP 데이터베이스 스레드 부하
이에 따라 위 조건의 이하의 요구사항인 경우
Spring Security Filter Chain 에 사용자 엔티티를 넣고 맘 편히 쓰는 게 속 편할 것 같다.
— 최근버전인 Spring 3.4.x OSIV 는 기본으로 켜져있다.
하지만 만약 위 조건 그 이상의 요구사항인 경우,
OSIV 를 무조건 끄고, Spring Security Filter Chain 에서는 사용자 메타데이터를 넣는 게
효율적인 방안 아닐까 싶다.
아래는 OpenSessionInViewFilter 을 등록하는 코드이다.
만약 Filter 부터 영속화된 사용자를 유지하고 싶다면 아래 설정을 해주어야 한다.
@Component
@Configuration
public class OpenEntityManagerConfig {
@Bean
public FilterRegistrationBean<OpenEntityManagerInViewFilter> openEntityManagerInViewFilter() {
FilterRegistrationBean<OpenEntityManagerInViewFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new OpenEntityManagerInViewFilter());
filterFilterRegistrationBean.setOrder(Integer.MIN_VALUE); // 예시를 위해 최우선 순위로 Filter 등록
return filterFilterRegistrationBean;
}
}
Spring MVC
https://velog.io/@zooyeop/Spring-Dispatcher-ServletFilterInterceptor-1
https://escapefromcoding.tistory.com/352
Spring Security
https://jaykaybaek.tistory.com/27
OSIV
https://www.baeldung.com/spring-open-session-in-view
https://tecoble.techcourse.co.kr/post/2020-09-20-entity-lifecycle-2/
https://tecoble.techcourse.co.kr/post/2020-11-03-osiv_with_interceptor/
https://brunch.co.kr/@anonymdevoo/58
https://perfectacle.github.io/2021/05/24/entity-manager-lifecycle/
https://github.com/spring-projects/spring-boot/issues/7107
https://github.com/spring-projects/spring-boot/issues/42607
https://docs.spring.io/spring-boot/appendix/application-properties/index.html
Tomcat Thread Pool
https://www.baeldung.com/java-web-thread-pool-config
HikariCP