이번 릴리즈는 Netty 및 Undertow 기반의 차세대 HTTP/2 프로토콜 지원, 대규모 분산 클러스터 환경을 위한 Redis Sorted Set 기반 고성능 세션 만료 인덱스 및 락프리(Lock-Free) 스트라이프 커넥션 풀 도입, 웹소켓 브로드캐스트 및 직렬화 비동기 전송 강화, 액션 실행 예외 처리 및 파라미터 바인딩 간소화, 그리고 코어 유틸리티 전반의 현대화 및 널 안전성(JSpecify) 표준화를 단행한 메이저급 기능 및 아키텍처 고도화 릴리즈입니다.
서블릿리스 Netty 및 Undertow 웹 서비스에서 Cleartext(h2c) 및 TLS ALPN(h2)을 통한 고효율 다중화 HTTP/2 통신을 기본 지원하며, Lettuce 기반 분산 세션 스토어의 기존 $O(N)$ 전체 SCAN 폴링을 $O(\log N + M)$ ZSET 만료 인덱스 구조로 혁신하여 세션 스캐빈징 부하를 극적으로 낮추었습니다. 또한 액션 실행 파이프라인의 불필요한 예외 래핑 제거, ETag 및 HTTP 조건부 처리 최적화, REST 요청/응답 API 강화, 유틸리티 계층 전반의 단위 테스트 확장 및 견고성 향상 등 프레임워크 전 영역에 걸친 개선이 이루어졌습니다.
🚀 새로운 기능
- Netty 및 Undertow 서비스의 HTTP/2 프로토콜 지원 (Cleartext
h2c및 TLS ALPNh2)aspectran-with-netty및aspectran-with-undertow모듈에서 최신 HTTP/2 표준 프로토콜을 공식 지원합니다.- 비암호화 HTTP/2 (
h2c): 직접 연결(Direct) 및 HTTP/1.1 업그레이드 핸드셰이크를 통한 h2c 통신을 지원하여 내부 마이크로서비스 간 초고속 저지연 네트워킹을 제공합니다. - 보안 TLS ALPN (
h2): Application-Layer Protocol Negotiation(ALPN) 협상을 지원하여 단일 TLS 포트에서 HTTP/1.1 및 HTTP/2 클라이언트를 자동 식별하고 멀티플렉싱 스트림을 처리합니다. Http2Config설정을 통해 헤더 테이블 크기, 최대 동시 스트림 수, 초기 윈도우 크기, 최대 프레임 크기, 최대 헤더 목록 크기 등을 세밀하게 구성할 수 있습니다.- Netty 및 Undertow 웹 서버 기동 시 HTTP/2 활성화 상태 및 프로토콜 협상 단계가 명확히 로깅됩니다.
- Redis Sorted Set 기반 고성능 만료 인덱스(
aspectran:session:expiry) 및 경량 코덱 도입- 기존 $O(N)$ Redis SCAN 방식의 만료 세션 폴링을 $O(\log N + M)$ 시간 복잡도를 갖는 Redis Sorted Set(ZSET) 인덱스(
aspectran:session:expiry)로 전면 개편했습니다. - 만료 타임스탬프를 ZSET score로 관리하여 수백만 개의 분산 세션이 존재하는 환경에서도 만료 대상 세션을 초고속으로 조회(
doGetExpired,getAllSessions)합니다. - 경량
SessionDataCodec최적화: 매직 바이트 태그(MAGIC_ID_ONLY,MAGIC_FULL)를 도입하여 하위 호환성을 유지하면서 인덱스용 세션 ID를 최소한의 바이트로 직렬화/역직렬화합니다. AbstractLettuceSessionStore및 세션 스토어 팩토리에expiryIndexKey설정 옵션을 추가하여 만료 인덱스 키를 사용자 정의할 수 있습니다.
- 기존 $O(N)$ Redis SCAN 방식의 만료 세션 폴링을 $O(\log N + M)$ 시간 복잡도를 갖는 Redis Sorted Set(ZSET) 인덱스(
- Redis 분산 락(
SET NX EX)을 통한 만료 세션 스캐빈징 및 고아 세션 정리- 멀티 노드 클러스터 환경에서 만료 세션 수거(
doGetExpired) 및 고아 세션 정리(doCleanOrphans) 수행 시 Redis 분산 락(SET NX EX)을 획득하도록 보강했습니다. - 복수의 클러스터 노드가 동시에 스캐빈징을 실행하여 발생하는 중복 삭제 및 Redis I/O 경합을 원천 차단하고 단일 노드가 전담 처리하도록 보장합니다.
doCleanOrphans수행 시 인덱스 정리 전 Redis에 남아 있는 고아 세션 데이터 키를 안전하게 물리 삭제하도록 보강했습니다.
- 멀티 노드 클러스터 환경에서 만료 세션 수거(
- Lettuce 세션 스토어 전용 락프리(Lock-Free) 스트라이프 커넥션 풀 도입
- 레거시 Apache Commons Pool2 의존성을 완전히 제거하고, Lettuce의 비동기 멀티플렉싱 특성을 극대화한 자체
StripedConnectionPool을 구축했습니다. - 동적 프록시를 적용하여
try-with-resources구문 사용 시 커넥션 close가 no-op으로 안전하게 동작하도록 지원합니다. - Standalone, Cluster, Primary-Replica 전 토폴로지에 걸쳐 단일
poolSize설정만으로 일관되고 락 경합 없는 고성능 커넥션 풀링을 제공합니다.
- 레거시 Apache Commons Pool2 의존성을 완전히 제거하고, Lettuce의 비동기 멀티플렉싱 특성을 극대화한 자체
SimplifiedEndpoint웹소켓 브로드캐스트 및 동기/직렬화 비동기 전송 API 확장SimplifiedEndpoint에 다중 세션을 대상으로 메시지를 일괄 전송할 수 있는broadcast(String)및broadcast(ByteBuffer)메서드를 추가했습니다.- 동기식 메시지 송신(
sendText,sendBinary) 및 큐 기반 직렬화 비동기 송신(sendTextAsync,sendBinaryAsync) API를 확충하여 웹소켓 세션 내 동시 쓰기 충돌을 방지하고 전송 안전성을 강화했습니다.
- HTTP
HEAD요청 레거시 처리 지원 및NoBodyResponse도입- Servlet, Netty, Undertow 웹 서비스 전반에서 본문 없이 응답 헤더와 콘텐츠 길이(
Content-Length)만을 반환하는 HTTP HEAD 요청 처리 메커니즘을 정립했습니다. NoBodyResponse를 도입하여 불필요한 바디 직렬화를 건너뛰고 정확한 헤더 메타데이터만을 생성하여 전송 효율을 향상했습니다.
- Servlet, Netty, Undertow 웹 서비스 전반에서 본문 없이 응답 헤더와 콘텐츠 길이(
🚀 개선 사항
- 액션(Action) 예외 처리 파이프라인 간소화 및 원본 예외 투명 전달
AnnotatedAction,InvokeAction,EchoAction,HeaderAction,IncludeAction,ChooseAction,AdviceAction,AnnotatedAdviceAction등 개별 액션 클래스에서 불필요하게ActionExecutionException으로 예외를 중복 catch/wrapping하던 로직을 제거했습니다.- 상위 실행 엔진인
CoreActivity및AdviceActivity에서 예외 래핑을 일괄 전담하도록 단일화하여 실행 스택 트레이스를 단순화하고 성능을 개선했습니다. AnnotatedMethodInvoker에서InstantTranslet환경을 안전하게 지원하고, 파라미터 매핑 및 빈 주입 로직을 정교화했습니다.
- 비트랜슬릿(Non-Translet) 환경에서의 응답 변환(
TransformResponse) 및 뷰 디스패치 안전성 확보AponTransformResponse,JsonTransformResponse,TextTransformResponse,XmlTransformResponse,XslTransformResponse및 뷰 디스패처 전반에서activity.getTranslet()호출 전activity.hasTranslet()존재 여부를 검증하도록 방어 가드를 추가했습니다.- 독립 인스턴스 또는 데몬 환경 등 트랜슬릿 컨텍스트가 존재하지 않는 실행 경로에서도 문자 인코딩 조회 및 템플릿 변환이 안전하게 수행되도록 보장했습니다.
TransformResponseFactory를 Java 최신 패턴의switch표현식으로 리팩토링했습니다.
- HTTP ETag 및 조건부 요청 처리 최적화 (
ETagInterceptor)- RFC 7232 표준에 맞춰
If-None-Match: *와일드카드 매칭을 공식 지원합니다. - GET/HEAD 메서드 및 2xx 성공 응답 상태에서만 ETag 처리가 적용되도록
isEligibleMethod및isEligibleResponse가드를 보강했습니다. DigestUtils.appendMd5DigestAsHex를 적용하여StringBuilder에 16진수 토큰 문자열을 직접 조합함으로써 임시 문자열 객체 생성을 최소화했습니다.
- RFC 7232 표준에 맞춰
- REST 요청/응답 API 강화 및 콘텐츠 협상(Content Negotiation) 고도화
RestRequest에 헤더, 쿼리 파라미터, 바디 데이터를 체이닝 방식으로 설정할 수 있는 플루언트 API를 개선했습니다.RestResponse에 HTTP 상태 코드 판별 헬퍼 메서드 및 응답 본문 변환 유틸리티를 추가했습니다.WebRequestBodyParser에 구조화된 구문 접미사(Structured Syntax Suffixes, 예:application/vnd.api+json,application/problem+xml)를 자동 인식하는 파싱 기능을 추가했습니다.MediaType및MediaTypeUtils에 표준 미디어 타입 상수 확충, 파싱 캐싱 및 최적화를 적용했습니다.- 오류 응답 시 클라이언트 재시도 간격을 안내하는
Retry-After헤더 설정을 지원합니다.
- 클러스터 세션 수명 주기 및 원자적 삭제 제어 강화
- 로컬 노드 만료 타이머 도래 시 공유 스토어에 활성 상태인 세션이 남아 있는 경우 조용한 축출(
silent eviction,checkActiveInStore)을 수행하도록 개선했습니다. - 공유 스토어에서 세션 삭제를 원자적으로 성공한 단일 노드만
onSessionDestroyed이벤트를 발생시키도록ManagedSession에deletedInStore플래그를 추가하여 중복 알림을 방지했습니다. AbstractSessionCache.delete수행 시 세션 락을 획득하도록 보강하여 동시성 제어 안정성을 극대화했습니다.
- 로컬 노드 만료 타이머 도래 시 공유 스토어에 활성 상태인 세션이 남아 있는 경우 조용한 축출(
- 코어 유틸리티 계층 현대화 및 JSpecify 널 안전성(Null-Safety) 전면 적용
DurationUtils: ISO-8601 지속 시간 문자열(PT1H30M), 일(d/day/days) 단위 파싱 오버로드 추가 및Locale.ROOT기반 포맷팅 보장DataSizeUtils: IEC 이진 접두사(KiB, MiB, GiB, TiB 등) 파싱 지원, 바이트 단위 상수 추가, 64비트 오버플로 가드 및 로케일 독립 포맷팅 적용Assert:CharSequence지원 확장 및state,isTrue,notNull,hasText,noNullElements등에 기본 실패 메시지 오버로드 제공ArrayStack: 다형성 제네릭 조회(peek(Class<T>),pop(Class<T>)), 안전한 조회 편의 메서드(peekOrNull,popOrNull),java.util.Stack호환 메서드(empty) 추가 및 음수 인덱스 검사 일관화DigestUtils: SHA-1/256/512 다이제스트 메서드 추가 및append*DigestAsHex인플레이스 포맷터 제공CopyOnWriteMap: 키 부재 시 NPE 방지,keySet/values/entrySet불변 뷰 래핑 및 원자적compute*연산 오버라이드FileLocker:AutoCloseable구현(try-with-resources지원),ProcessHandle.current().pid()기반 PID 추출 현대화, 부모 디렉터리 자동 생성 보장ClassUtils/TypeUtils: 불필요한 정적 초기화 방지(initialize: false), 원시 타입 및 배열 문자열 파싱 지원, 중첩 CGLIB/Javassist 프록시 클래스 언래핑 개선AutoLock,ShutdownHook,CyclicTimeout,Scheduler,LocaleUtils,FilenameUtils,PathUtils,SystemUtils,ObjectUtils,ExceptionUtils,ConcurrentReferenceHashMap,BeanUtils,LinkedCaseInsensitiveMap전반의 기능 개선 및 널 안전성 어노테이션(@NonNull,@Nullable) 표준화
- i18n 로케일 해석 및 메시지 소스 리팩토링
LocaleResolver계층 구조 및 전략을 정비하고 Javadoc 문서를 보강했습니다.AcceptHeaderLocaleResolver,CookieLocaleResolver,SessionLocaleResolver의 안전성과 일관성을 제고하고 단위 테스트를 확충했습니다.
🐛 버그 수정
WebSocketEndpointTemplate경로 파라미터 추출 시 불변 맵 수정 위험 수정- URL 매칭 및 파라미터 추출 시
params맵을 지연 생성(Lazy Initialization)하도록 수정하여, 불변 객체인Collections.emptyMap()에put이 호출될 수 있는 잠재적 오류를 차단하고 리터럴 경로 및 불일치 패턴에서의 불필요한 맵 할당을 제거했습니다.
- URL 매칭 및 파라미터 추출 시
CopyOnWriteMap키 미존재 시NullPointerException수정- 맵에 존재하지 않는 키를 대상으로
remove(key, value)또는replace(key, oldValue, newValue)호출 시 NPE가 발생하던 문제를 해결했습니다.
- 맵에 존재하지 않는 키를 대상으로
ArrayStack널 요소 포함 시 NPE 및 음수 인덱스 오류 수정- 스택에
null요소가 저장되어 있을 때peek(Class)호출 시 발생하던 NPE를 수정하고, 음수 인덱스 전달 시 일관되게EmptyStackException을 던지도록 경계 검사를 보정했습니다.
- 스택에
DigestUtils.encodeHex고정 버퍼 길이 버그 수정- 고정 크기 문자 버퍼로 인해 특정 길이 이상의 바이트 배열 인코딩 시 버퍼 범위를 초과하던 오류를 수정했습니다.
TransletScanner트랜슬릿 스캔 필터 평가 로직 수정- 스캔 대상 트랜슬릿 규칙 필터 조건 평가 시 일부 와일드카드 패턴 매칭이 누락되던 문제를 해결했습니다.
FlashMap타겟 매칭 및 세션 플래시 속성 관리 누락 방지- 플래시 속성 전달 대상 경로 검증을 정확히 수행하도록 매칭 로직을 보정하고 널 안전성을 강화했습니다.
HeaderAction응답 헤더 덮어쓰기 로직 보정- 헤더 추가(
addHeader) 대신 지정된 설정대로 명확히 헤더를 갱신(setHeader)하도록 수정했습니다.
- 헤더 추가(
🛠️ 의존성 라이브러리 업그레이드
- 네트워킹 및 분산 세션
- Netty: 4.2.18.Final (BOM 관리 도입 및
netty-codec-http2추가) - Lettuce Core: 7.7.0.RELEASE → 7.8.0.RELEASE (Apache Commons Pool2 제거)
- Netty: 4.2.18.Final (BOM 관리 도입 및
- 핵심 유틸리티 및 표현식
- OGNL: 3.4.12 → 3.4.13
- JLine: 4.4.3 → 4.4.6
- 로깅 및 데이터베이스
- SLF4J: 2.0.19 → 2.0.20
- Logback Classic: 1.6.3 → 1.6.4
- H2 Database: 2.5.250 → 2.5.252
- Hibernate ORM: 7.4.7.Final → 7.4.11.Final
- Hibernate Validator: 9.1.3.Final → 9.1.4.Final
- QueryDSL: 7.6 → 7.7
- 빌드 및 플러그인
- Maven Install Plugin: 3.1.4 → 3.2.0
- Maven Deploy Plugin: 3.1.4 → 3.2.0
- Maven Bundle Plugin: 6.1.2 → 6.2.0
- Build Helper Maven Plugin: 3.6.1 → 3.6.2
Juho Jeong NEWS
Release