Backend/Spring+Boot

RequestContextHolder

findmypiece 2021. 4. 23. 14:32
728x90

RequestContextHolder 는 Spring 컨텍스트에서 HttpServletRequest 에 직접 접근할 수 있도록 도와주는 역할을 한다. Spring 2.x 부터 제공되던 기능으로 이를 활용하면 HttpServletRequest 사용하기 위해 이를 메소드 파라미터로 연이어 넘겨받을 필요가 없다.

 

예를 들어 RequestContextHolder 를 사용하지 않고 Service 단에서 HttpServletRequest 를 참조해야 한다고 하면 아래와 같이 해야 한다.

@RestController
@RequiredArgsConstructor
@Log4j2
public class TestController {

    private final TestService testService;

    @GetMapping("hello")
    public void hello(HttpServletRequest request){

        testService.hello(request);

    }    
    
}


@Service
@Log4j2
public class TestService {

    public void hello(HttpServletRequest request){

       log.info(request.getRequestURI());

    }    
    
}

 

하지만 RequestContextHolder 를 사용한다면 파라미터로 넘길 필요없이 필요한 곳에서 직접 참조할 수 있다.

@RestController
@RequiredArgsConstructor
@Log4j2
public class TestController {

    private final TestService testService;

    @GetMapping("hello")
    public void hello(){

        testService.hello(request);

    }    
    
}


@Service
@Log4j2
public class TestService {

    public void hello(){

        HttpServletRequest req = TestUtils.getCurrReq();

        log.info(req.getRequestURI());

    }    
    
}

public class TestUtils {

    public static HttpServletRequest getCurrReq(){

        return ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
    }
}

 

참고로 RequestContextHolder 에서 RequestAttribute 를 구해오는 메소드는 위에서 사용한 currentRequestAttributes() 외에 getRequestAttributes() 도 있다. 둘의 차이는 구해오려는 RequestAttributes 가 없을 경우 전자는 예외를 발생시키고 후자는 그냥 null 을 리턴한다. 나는 http 프로토콜을 이용하는 프로젝트라면 request 정보가 없다는 거 자체가 정상적인 상황이 아니기 때문에 currentRequestAttributes() 를 사용했다.

 

이와 비슷한 역할 해줬던 것이 과거 ThreadLocal 이었는데 RequestContextHolder 도 기본적으로 이를 활용하고 동작방식은 아래와 같다.

  1. ThreadLocal을 사용해서 servlet이 호출되면 key,value (thread,HttpservletRequest)를 보관한다.
  2. 호출된 servlet과 동일한 thread내에서는 어느 곳에서든 같은 HttpServletRequest를 꺼내서 쓸수 있다.
  3. servlet이 종료 될 때 해당 thread를 key로 갖는 쌍을 제거한다.

 

자동으로 제거까지 해주니 더이상 Thread 내에서 데이터를 공유하기 위해 ThreadLocal를 사용하며 명시적으로 제거하는 작업을 해주지 않아도 된다.

 

 

http://dveamer.github.io/backend/SpringRequestContextHolder.html
https://syundev.tistory.com/244
https://welchsy.tistory.com/269

 

728x90