1. 설계 목표 및 주요 역할
com.aspectran.netty.activity 패키지는 Netty 임베디드 웹 서버 환경에서 유입된 HTTP 요청을 서블릿 API 없이 네이티브 ChannelHandlerContext 및 FullHttpRequest 기반으로 직접 처리하는 전용 Activity 구현체 및 어댑터 계층을 제공합니다.
이 패키지의 핵심 설계 목표는 다음과 같습니다.
- Netty 비동기 채널 실행 컨텍스트의 구체화: 표준
CoreActivity를 상속받아, Netty의ChannelHandlerContext와FullHttpRequest를 직접 감싸서 처리하는NettyActivity를 제공합니다. - 고급 HTTP 웹 명세의 완벽한 수용: HTTP 메서드 오버라이드(
X-HTTP-Method-Override,X-Method-Override), 프록시 포워딩 헤더(X-Forwarded-For), 최대 요청 크기 제한(maxRequestSize), 인코딩 처리를 Netty 채널 레벨에서 지원합니다. - Netty 전용 세션 매니저 연계:
NettySessionAdapter를 통해 쿠키 기반 세션 ID 추적, 만료 시간 관리 및 세션 에이전트 수명주기(access(),complete())를 보장합니다. - 웹 요청 본문(Body) 및 멀티파트 폼 파싱:
WebRequestBodyParser와 연계하여 Netty의ByteBuf버퍼로부터 대용량 파일 업로드(multipart/form-data)와 URL 인코딩 폼(application/x-www-form-urlencoded) 데이터를 효율적으로 파싱합니다.
2. 주요 클래스 상세 분석
classDiagram
class CoreActivity {
<<abstract>>
#adapt()
#parseRequest()
#saveCurrentActivity()
#removeCurrentActivity()
}
class NettyActivity {
-NettyService nettyService
-ChannelHandlerContext ctx
-FullHttpRequest request
-String effectiveContextPath
-String requestName
-MethodType requestMethod
+getMode() Mode
+prepare()
#adapt()
#parseRequest()
#saveCurrentActivity()
#removeCurrentActivity()
}
class NettyRequestAdapter {
-FullHttpRequest request
-ChannelHandlerContext ctx
+getMaxRequestSize() long
+setMaxRequestSize(long)
}
class NettyResponseAdapter {
-ChannelHandlerContext ctx
-FullHttpRequest request
+getWriter() Writer
+getOutputStream() OutputStream
}
class NettySessionAdapter {
-ChannelHandlerContext ctx
-FullHttpRequest request
+access()
+complete()
}
CoreActivity <|-- NettyActivity
NettyActivity ..> NettyRequestAdapter : instantiates
NettyActivity ..> NettyResponseAdapter : instantiates
NettyActivity ..> NettySessionAdapter : instantiates
NettyActivity (구현 클래스)
Netty 환경을 위한 Activity의 최종 구현체입니다. DefaultNettyService.service()가 호출될 때마다 유입된 ChannelHandlerContext 및 FullHttpRequest 단위로 인스턴스화됩니다.
- 주요 책임 및 속성:
nettyService: 상위NettyService인스턴스를 유지하여 세션 매니저, 플래시맵, 로케일 리졸버를 인출합니다.ctx: Netty의 채널 핸들러 컨텍스트로, 네트워크 소켓 채널과 파이프라인 제어 권한을 소유합니다.request: Netty 네이티브FullHttpRequest객체로, HTTP 메서드, URI, 헤더,ByteBuf본문 데이터를 보관합니다.effectiveContextPath: 리버스 프록시 환경에서 절대 경로를 조립하기 위한 유효 컨텍스트 경로입니다.getMode(): 항상Mode.WEB을 반환하여 웹 전용 어드바이스 및 뷰 디스패처가 활성화되도록 합니다.
- 핵심 메서드 심층 분석:
prepare()및 히든 메서드 오버라이드:@Override public void prepare(@NonNull String requestName, MethodType requestMethod) throws TransletNotFoundException, ActivityPrepareException { if (requestMethod == MethodType.POST) { String method = request.headers().get(HttpHeaders.X_HTTP_METHOD_OVERRIDE); if (method == null) { method = request.headers().get(HttpHeaders.X_METHOD_OVERRIDE); } if (method != null) { MethodType hiddenRequestMethod = MethodType.resolve(method); if (hiddenRequestMethod != null) { requestMethod = hiddenRequestMethod; } } } super.prepare(requestName, requestMethod); }POST요청에X-HTTP-Method-Override헤더가 포함된 경우 이를 감지하여PUT,DELETE등으로 가상 메서드를 동적 승격시킵니다.adapt(): Netty 어댑테이션의 핵심 구현부입니다.@Override protected void adapt() throws AdapterException { NettyResponseAdapter responseAdapter = new NettyResponseAdapter(ctx, request, this); setResponseAdapter(responseAdapter); if (nettyService.isSessionAdaptable()) { if (getPendingActivity() == null) { NettySessionAdapter sessionAdapter = new NettySessionAdapter(ctx, request, responseAdapter, this); setSessionAdapter(sessionAdapter); } else if (getPendingActivity().hasSessionAdapter()) { setSessionAdapter(getPendingActivity().getSessionAdapter()); } } NettyRequestAdapter requestAdapter = new NettyRequestAdapter( getTranslet().getRequestMethod(), request, ctx, getContextPath(), nettyService.isProxyAddressForwarding()); setRequestAdapter(requestAdapter); setFlashMapManager(nettyService.getFlashMapManager()); setLocaleResolver(nettyService.getLocaleResolver()); super.adapt(); }NettyResponseAdapter를 먼저 생성하여 응답 버퍼 및 헤더를 준비합니다.NettySessionAdapter를 결속하여 Netty 환경에서의 세션 어댑테이션을 활성화합니다.NettyRequestAdapter를 결속하여 파라미터, 헤더, 프록시 포워딩, 최대 요청 크기 제한을 적용합니다.- 플래시맵 매니저 및 로케일 리졸버를 결합합니다.
parseRequest():WebRequestBodyParser를 구동하여 Netty의ByteBuf본문으로부터 멀티파트 폼(multipart/form-data) 및 폼 파라미터를 파싱합니다.saveCurrentActivity()/removeCurrentActivity(): 활동 시작 시sessionAdapter.access()를 호출하여 세션 최종 접근 시각을 갱신하고, 활동 종료 시sessionAdapter.complete()를 호출하여 변경된 세션 속성을 커밋하고 쿠키 헤더를 갱신합니다.
3. 다른 패키지와의 상호작용
com.aspectran.netty.service:DefaultNettyService는 유입된 모든 HTTP 요청에 대해NettyActivity를 생성하고,prepare()및perform()을 호출하여 실행을 위임합니다.com.aspectran.netty.adapter:NettyActivity는 내부적으로NettyRequestAdapter,NettyResponseAdapter,NettySessionAdapter를 직접 인스턴스화하여 Netty 객체와의 통신을 추상화합니다.com.aspectran.web.activity.request:WebRequestBodyParser를 통해 대용량 멀티파트 파일 업로드와 폼 데이터를 처리합니다.com.aspectran.core.activity:NettyActivity는CoreActivity를 상속받아 그 안에 구현된 AOP 어드바이스 체인(BEFORE,AFTER,THROWN,FINALLY), 액션 디스패치(dispatchContent), 응답 변환 로직을 일체 변경 없이 100% 재사용합니다.
4. 패키지 요약 및 아키텍처적 의미
com.aspectran.netty.activity 패키지와 NettyActivity는 Aspectran의 어댑터 아키텍처가 고성능 비동기 이벤트 기반 네트워킹과 얼마나 자연스럽게 융합될 수 있는가를 보여주는 대표적인 결실입니다.
- 네트워크 소켓 채널 직접 결속:
ChannelHandlerContext와 직접 결합되어 응답 데이터를 즉시 플러시(writeAndFlush)하거나 HTTP 청크 스트리밍을 수행할 수 있습니다. - 완전한 웹 기능의 재현: 서블릿이 없는 환경임에도 불구하고 멀티파트 업로드, 세션 관리, Method Override, 콘텐츠 협상 등 엔터프라이즈 웹에 필요한 모든 기능을 완벽하게 지원합니다.
- 다중 환경과의 일관성: 서블릿(
ServletWebActivity), Undertow(TowActivity)와 완벽하게 대칭되는 어댑터 계약을 이행하므로, 개발자는 실행 환경이 바뀌어도 동일한 코드베이스를 유지할 수 있습니다.