Releases

Aspectran 9.8 릴리즈 노트

이번 릴리즈는 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 ALPN h2)
    • 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 설정 옵션을 추가하여 만료 인덱스 키를 사용자 정의할 수 있습니다.
  • 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 설정만으로 일관되고 락 경합 없는 고성능 커넥션 풀링을 제공합니다.
  • SimplifiedEndpoint 웹소켓 브로드캐스트 및 동기/직렬화 비동기 전송 API 확장
    • SimplifiedEndpoint에 다중 세션을 대상으로 메시지를 일괄 전송할 수 있는 broadcast(String) 및 broadcast(ByteBuffer) 메서드를 추가했습니다.
    • 동기식 메시지 송신(sendText, sendBinary) 및 큐 기반 직렬화 비동기 송신(sendTextAsync, sendBinaryAsync) API를 확충하여 웹소켓 세션 내 동시 쓰기 충돌을 방지하고 전송 안전성을 강화했습니다.
  • HTTP HEAD 요청 레거시 처리 지원 및 NoBodyResponse 도입
    • Servlet, Netty, Undertow 웹 서비스 전반에서 본문 없이 응답 헤더와 콘텐츠 길이(Content-Length)만을 반환하는 HTTP HEAD 요청 처리 메커니즘을 정립했습니다.
    • NoBodyResponse를 도입하여 불필요한 바디 직렬화를 건너뛰고 정확한 헤더 메타데이터만을 생성하여 전송 효율을 향상했습니다.

🚀 개선 사항

  • 액션(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진수 토큰 문자열을 직접 조합함으로써 임시 문자열 객체 생성을 최소화했습니다.
  • 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이 호출될 수 있는 잠재적 오류를 차단하고 리터럴 경로 및 불일치 패턴에서의 불필요한 맵 할당을 제거했습니다.
  • 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 제거)
  • 핵심 유틸리티 및 표현식
    • 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

NEWS
Release

Archive