공유해도 되는 데이터(불변/읽기 위주)냐, 공유하면 안 되는 데이터(요청마다 달라짐)냐
이 차이가 안전/위험을 갈라버린다.
실습의 RequestMapping은 이런 성격이다
대부분의 간단한 웹서버 실습에서 RequestMapping은 이런 구조다(예시).
public class RequestMapping {
private static final Map<String, Controller> map = new HashMap<>();
static {
map.put("/user/create", new UserCreateController());
map.put("/user/login", new LoginController());
}
public static Controller getController(String path) {
return map.get(path);
}
}
여기서 map을 static으로 둔 이유는 보통 이거다.
- 서버 시작할 때 한 번 만들어 둔다
- 요청이 올 때마다 “매핑 조회”만 한다
- 계속 재사용한다
즉, map은 요청마다 바뀌는 값이 아니라, “서버 설정/라우팅 테이블” 같은 공유해도 되는 데이터다.
그럼 공유해도 되는 데이터란 무엇인가?
대부분 아래 중 하나면 공유해도 안전해진다.
(A) 불변(Immutable) 또는 사실상 불변
- 시작할 때 채워두고 이후엔 안 바꿈
- 바꾸더라도 규칙이 명확하고 동시성 제어가 있음
(B) 읽기(Read) 위주
- 요청 처리 중 “조회”만 한다
- 쓰기(put/remove)가 거의 없다
(C) 쓰기가 있어도 동시성 제어가 확실
- ConcurrentHashMap, synchronized, Atomic* 같은 안전장치가 있음
RequestMapping은 보통 (A)+(B)다.
그래서 static으로 둬도 괜찮은 대표 케이스가 된다.
반대로 “요청 데이터”는 왜 공유하면 안 되나?
요청 데이터는 이런 성격이다.
- 사용자마다 다름
- 요청마다 다름
- 동시에 여러 요청이 들어오면 값이 서로 경쟁함
예를 들어 이런 값들:
- userId, name, password
- req.getParameter(...)로 읽은 값
- 이번 요청에서만 쓰는 임시 계산 결과
- 응답으로 내려줄 문자열/HTML 조각
이런 걸 static이나 인스턴스 필드에 넣는 순간 문제가 생긴다.
“값이 섞이는 사고”를 실습 코드로 그대로 연결해보면
❌ 잘못된 예: 요청별 값을 인스턴스 필드에 저장
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private String user; // 인스턴스 필드(공유)
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
user = req.getParameter("user");
resp.getWriter().println("Hello " + user);
}
}
- T1: user = "alice"
- T2: user = "bob" (덮어씀)
- T1: 출력 → "Hello bob" (alice 요청이 bob으로 바뀜)
즉, “요청 전용이어야 할 값”을 “공유 저장소”에 넣어서 섞인 것이다.
❌ static이면 더 넓게 공유됨
private static String user;
이건 “서블릿 인스턴스 1개 공유”보다 더 강한 전역 공유라서 더 위험해진다.
결국 안전/위험을 가르는 기준은 “공유 상태의 종류”다
✅ RequestMapping static Map이 안전한 이유
- “서버 전체가 공통으로 알아야 하는 설정/라우팅 정보”
- 서버 시작 시 1회 초기화 → 이후 읽기 위주
- 요청마다 값이 달라지는 데이터가 아니다
❌ 요청 데이터(static/필드)가 위험한 이유
- “요청마다 달라지는 값”인데
- 서블릿은 멀티스레드로 동시에 실행되고
- 필드/static은 공유 메모리라서
- 값이 덮어써지고 섞인다
그럼 RequestMapping Map도 무조건 안전한가?
대부분 실습에서는 안전하지만, “완전히” 안전하려면 조건이 있다.
안전한 케이스
- 서버 시작 시 static { ... }로 한 번만 채우고 끝
- 이후에는 get()만 함
위험해질 수 있는 케이스
- 요청 처리 중에 map.put(...) 같은 쓰기를 한다
- 동시에 여러 스레드가 put/remove를 한다
- 이때 HashMap이면 동시성 문제가 생길 수 있음
즉, RequestMapping도 “불변/읽기 위주” 설계를 유지해야 한다.
최종 결론: “static은 나쁜 게 아니라, 잘못된 데이터를 담으면 위험한 것”이다
- static 자체가 악은 아니다.
- 서버 전체가 공유해도 되는 데이터(설정, 매핑, 불변 상수) 는 static이 오히려 자연스럽다.
- 하지만 요청마다 달라지는 데이터를 static/필드에 담으면 멀티스레드에서 거의 반드시 터진다.
'Backend > Servlet' 카테고리의 다른 글
| forward와 JSP 실행 흐름 (0) | 2026.02.06 |
|---|---|
| 멀티스레드 환경에서 Servlet 사용 (0) | 2026.02.06 |
| Servlet Container와 Servlet의 관계 (0) | 2026.02.05 |
| 서블릿에서의 static (0) | 2026.02.05 |
| 서블릿 요청 흐름 : Request가 채워지는 시점과 service() 호출 위치 (0) | 2026.02.05 |