[데브코스] Spring Boot 인증·인가(Auth) (31강) - Rq 클래스와 @RequestScope로 요청 단위 공통 로직 관리하기

zuno·2026년 1월 13일

이번 강의에서는
대부분의 컨트롤러에서 반복되던 공통 기능(특히 인증 관련 로직)을 모으기 위해
Rq라는 클래스를 만들고, 이를 @RequestScope으로 등록했다.

이번 강의의 핵심은 단 하나다.

👉 “요청 하나당 하나의 Rq 객체”를 만들어서
👉 현재 요청에 대한 공통 정보(예: 로그인한 사용자)를 관리하자


1️⃣ 왜 Rq 클래스가 필요했을까?

이전 코드들을 보면 컨트롤러마다 계속 이런 코드가 반복되었다.

  • Authorization 헤더 꺼내기
  • Bearer 제거
  • apiKey 추출
  • apiKey로 Member 조회
  • 인증 / 인가 처리

예를 들면 이런 코드다.

String apiKey = authorization.replace("Bearer ", "");
Member actor = memberService.findByApiKey(apiKey)
    .orElseThrow(() -> new ServiceException("401-1", "존재하지 않는 apiKey 입니다."));

👉 이 코드는

  • 글 작성
  • 글 수정
  • 글 삭제
  • 댓글 작성
  • 댓글 수정
  • 댓글 삭제

모든 컨트롤러에 거의 똑같이 등장했다.

그래서 강의에서는 이렇게 생각한 것이다.

“이걸 컨트롤러마다 쓰지 말고
요청 단위로 공통 관리하는 객체로 빼자”

그 결과가 바로 Rq 클래스다.


2️⃣ Rq 클래스 코드 구조

@Component
@RequestScope
public class Rq {

    public Member getActor() {
        return null;
    }
}

아직 메서드 내용은 비어 있지만,
이 클래스의 역할과 스코프 자체가 핵심이다.

Rq는 앞으로 다음 역할을 맡게 된다.

  • 현재 요청의 Authorization 헤더 접근
  • apiKey 추출
  • apiKey로 로그인한 사용자(Member) 조회
  • 컨트롤러 어디서든 “현재 요청의 사용자”를 동일하게 제공

3️⃣ @Component는 뭐야?

@Component

👉 “이 클래스는 스프링 빈이다”라고 알려주는 어노테이션이다.

  • 스프링이 객체를 자동으로 생성
  • 필요한 곳에서 주입(@Autowired / 생성자 주입) 가능
  • 개발자가 new Rq()를 직접 호출하지 않아도 됨

📌 쉽게 말하면:

“스프링 컨테이너가 관리하는 객체”


4️⃣ @RequestScope는 뭐야?

@RequestScope

👉 HTTP 요청 하나당 새로운 객체를 만든다는 의미다.

동작 흐름은 이렇다.

  • 요청 시작 → Rq 객체 생성
  • 요청 처리 중 → 같은 Rq 객체 계속 사용
  • 요청 종료 → Rq 객체 소멸

📌 즉,

  • 요청 A → Rq 인스턴스 A
  • 요청 B → Rq 인스턴스 B

👉 완전히 다른 객체이며 절대 공유되지 않는다.


5️⃣ @Component + @RequestScope 조합의 정확한 의미

이 부분이 가장 헷갈리기 쉬운 포인트다.

❌ 오해하기 쉬운 생각

  • “Component면 객체 하나만 만들어지는 거 아니야?”
  • “RequestScope면 객체가 막 여러 개 생기는 거야?”

✅ 정확한 해석

어노테이션역할
@Component스프링 빈으로 등록
@RequestScope생성 시점을 요청 단위로 제한

즉,

“스프링이 관리하되, 요청마다 새로 만든다”

이 조합 덕분에
Rq는 전역처럼 쓰이지만, 실제로는 요청마다 분리된 객체가 된다.


6️⃣ 왜 그냥 함수로 빼지 않았을까?

처음에는 이런 생각이 든다.

“중복 코드면 그냥 함수로 빼면 되지 않나?”

이 생각은 아주 정상적인 초보자 관점이다.

하지만 함수에는 한계가 있다.

함수의 특징

  • 호출될 때마다 처음부터 실행
  • 이전 실행 결과를 기억하지 못함
  • 같은 요청에서 여러 번 호출해도 매번 다시 계산

즉, 같은 요청인데도
getActor()를 여러 번 호출하면
매번 apiKey 파싱 + DB 조회가 반복된다.

👉 함수는 상태를 저장할 공간이 없다.


7️⃣ 그럼 클래스로 만들면 되지 않나?

다음으로 자연스럽게 드는 생각은 이거다.

“그럼 함수 말고 클래스로 만들면 되는 거 아닌가?”

이 질문도 정확하다.
실제로 방법은 있다.

방법 1️⃣ 컨트롤러에서 매번 new로 생성

Rq rq = new Rq(...);
Member actor = rq.getActor();

이 방식은 동작은 한다.

하지만:

  • 모든 컨트롤러에서 매번 new Rq() 필요
  • 스프링 DI와 생명주기 관리에서 벗어남
  • 공통 구조로 확장하기 어려움

👉 자바 코드로는 맞지만, 스프링스러운 구조는 아니다.


방법 2️⃣ 전역 변수나 Singleton으로 저장 ❌

이 방식은 절대 하면 안 된다.

웹 서버는 여러 요청을 동시에 처리한다.

  • 요청 A(user1)가 값 저장
  • 요청 B(user2)가 값 덮어씀
  • 요청 A가 다시 접근 → user2가 나올 수 있음

👉 이는 치명적인 보안 사고다.


방법 3️⃣ 스프링 빈 + @RequestScope (강의에서 선택)

@Component
@RequestScope
public class Rq {
    private Member actor;
}

이 구조의 핵심은:

  • Rq는 스프링이 관리
  • 요청마다 새로운 인스턴스
  • 요청이 끝나면 객체와 데이터는 완전히 제거

8️⃣ “RequestScope가 기억한다”는 말의 정확한 의미

여기서 말하는 “기억”이란:

요청 하나가 처리되는 동안만 값을 필드에 저장해두고 재사용한다는 뜻이다.

  • 첫 호출 → actor 계산 후 저장
  • 같은 요청 중 다시 호출 → 저장된 actor 반환
  • 요청 종료 → Rq 객체 자체가 소멸

👉 다음 요청으로 넘어가지 않는다.
👉 서버에 남아 있지 않는다.


9️⃣ Singleton 빈 vs RequestScope 빈 비교

구분Singleton (기본)RequestScope
생성 시점애플리케이션 시작 시 1번HTTP 요청마다
인스턴스 수딱 1개요청 수만큼
상태 공유모든 요청이 공유요청별 독립
스레드 안전직접 관리 필요기본적으로 안전
사용 예설정, 서비스로그인 사용자, 요청 컨텍스트

📌 Rq는 무조건 RequestScope여야 한다.


🔟 앞으로 Rq는 이렇게 쓰이게 된다 (개념)

컨트롤러에서는 더 이상 이런 걸 직접 하지 않는다.

String apiKey = ...
Member actor = ...

대신 이렇게 된다.

Member actor = rq.getActor();

👉 인증 로직이 한 곳으로 모인다
👉 컨트롤러는 “요청 처리”에만 집중
👉 코드 중복 제거 + 가독성 상승


🔥 핵심 요약 (진짜 중요)

  • @Component
    → 스프링이 관리하는 빈

  • @RequestScope
    → HTTP 요청마다 새 객체 생성

  • Rq 클래스의 목적
    → 요청 단위 공통 정보 저장소

  • 왜 필요한가?
    → 인증/인가 로직 중복 제거 + 요청별 안전한 상태 관리

이번 글에서는
👉 “왜 Rq가 필요하고, 왜 RequestScope인지”
이 부분만 이해하면 충분하다.

0개의 댓글