블로그

서버 모니터링 툴 Zenius SMS로 서버 터미널 보안관리 하기 IT 인프라 모니터링 시스템의 컨트롤러 개선기, ArgumentResolver를 통한 중복 제거
유성욱 2026.02.06
다음글이 없습니다.

대규모 IT 인프라를 모니터링하는 도메인에서는 서버나 네트워크 장비와 같은 관리 대상을 통칭하여 타겟(Target)이라고 부릅니다. 이에 따라 대다수의 API는 리소스 식별을 위해 URL 경로(Path Variable)나 쿼리 스트링(Query Parameter)을 통해 targetId를 필수적으로 전달받는 구조를 가지고 있습니다.


이 targetId는 단순한 문자열 식별자가 아니라, 실제 비즈니스 로직이 수행되기 전 반드시 선행되어야 하는 일련의 검증 절차를 요구합니다. 구체적으로는 클라이언트 입력값에 대한 유효성 검사, 해당 ID를 기반으로 한 DB 조회 및 도메인 객체(TargetInfoRecord)로의 매핑, 그리고 해당 타겟에 대한 사용자 접근 권한(Authorization) 확인 과정이 포함됩니다.


프로젝트 초기 구현 단계에서는 이러한 전처리 로직을 각 컨트롤러 메서드 바디 상단에 직접 구현하는 방식을 취했습니다.




하지만 API 엔드포인트가 수십 개로 늘어남에 따라, 동일한 검증 코드가 여러 컨트롤러에 산재하게 되는 구조적 문제가 발생했습니다. 이는 단순한 코드 중복(Boilerplate Code)을 넘어, 타겟 검증 정책이 변경될 때마다 관련된 모든 API를 수정해야 하는 유지보수의 취약점으로 이어졌습니다. 


또한 비즈니스 로직과 검증 로직이 한 곳에 혼재됨에 따라 코드의 가독성이 저하되고, 수정 과정에서 누락이 발생할 경우 장애로 직결될 위험이 높습니다.



반복되는 검증 로직과 분산된 수정 포인트(N개의 지점) 문제를 근본적으로 해결하기 위해, 다음과 같은 명확한 엔지니어링 목표를 수립했습니다.


 “타겟 검증, 변환을 메서드 파라미터 주입 시점에 끝낸다.”


Spring MVC는 이미 @PathVariable, @RequestParam, @AuthenticationPrincipal과 같이 요청 데이터를 가공하여 컨트롤러 메서드 파라미터에 바인딩하는 표준화된 메커니즘을 제공하고 있습니다.


이 아키텍처 패턴에 착안하여, [ URL에서 타겟 ID 추출 → 유효성 검증 → 도메인 객체 변환 ]으로 이어지는 일련의 과정을 비즈니스 로직 진입 전인 '파라미터 주입 단계'에서 완결짓도록 HandlerMethodArgumentResolver를 적용했습니다.


이 아키텍처를 실제 코드로 구현하기 위해, 프로세스를 크게 세 가지 단계로 나누어 진행했습니다.


  • 메타데이터 정의 (Annotation): 어떤 파라미터를 검증할지 식별하고 정책을 부여
  • 로직 구현 (Resolver & Helper): 실제 값을 추출하고 도메인 객체로 변환하는 바인딩 로직 작성
  • 설정 등록 (Configuration): Spring MVC가 해당 리졸버를 인식하도록 설정


가장 먼저, 컨트롤러 파라미터에 검증 요구사항을 명시할 커스텀 어노테이션을 정의합니다.




1. 커스텀 어노테이션 정의 - @ToTargetInfoRecords

구현의 첫 단계로, 파라미터에 메타데이터를 부여할 커스텀 어노테이션을 정의합니다. 타겟에 대한 모든 정보를 TargetInfoRecord라는 도메인 객체로 캡슐화하여 관리하고 있습니다. 따라서 '해당 파라미터를 TargetInfoRecord 객체로 변환하라'는 명시적인 의미를 담아 @ToTargetInfoRecords라는 어노테이션을 설계했습니다.


이 어노테이션은 런타임 시점에 Resolver가 식별할 수 있어야 하므로 RUNTIME 정책을 사용하며, 파라미터 레벨에 적용되도록 타겟을 한정했습니다.



- VALUE_PARAMETER로 메서드 파라미터에서만 사용하도록 제한합니다.

- RUNTIME 보존으로 요청 처리 시점에 리졸버가 어노테이션 값을 읽습니다.




2. ArgumentResolver 구현

다음으로 Spring MVC의 HandlerMethodArgumentResolver 인터페이스를 구현하여 실질적인 바인딩 로직을 처리하는 ToTargetInfoRecordResolver를 작성합니다.



HandlerMethodArgumentResolver를 상속한 ToTargetInfoRecordsResolver를 생성합니다.




3. 리졸버 등록 방법

구현한 리졸버가 실제로 동작하기 위해서는 Spring MVC의 Argument Resolver 체인에 등록해야 합니다. WebMvcConfigurer를 구현하여 우리가 만든 리졸버를 추가해주면, 이후 들어오는 요청에 대해 Spring이 자동으로 개입하게 됩니다.



이 리졸버를 등록한 후에 클라이언트로부터 요청이 들어오면, 컨트롤러 메서드 호출 직전에 파라미터 단위로 다음 순서가 진행됩니다.

1. Spring이 컨트롤러 메서드의 각 파라미터에 대해 등록된 리졸버 리스트를 순서대로 확인합니다.

2. supportsParameter(...)가 true인 첫 번째 리졸버를 선택합니다.


3. 선택된 리졸버의 resolveArgument(...)를 호출하여 값을 만들고, 그 반환값을 해당 파라미터에 주입합니다.

자세한 구현은 다음과 같습니다.


1) 어떤 파라미터를 내가 담당하는가 — supportsParameter

파라미터에 @ToTargetInfoRecords가 붙어 있으면  자신의 책임으로 판단합니다.



2) 값을 어떻게 만들고 주입하는가 — resolveArgument


3) URL에서 값은 어떻게 추출하는가 — 쿼리 vs 경로

 

 - 쿼리스트링은 webRequest.getParameterValues()로, 경로 변수 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE로 추출합니다.


 - 메서드 파라미터 타입이 List인지도 구분하고 검증합니다.


이렇게 헬퍼 클래스를 통해 요청 위치나 데이터 타입에 구애받지 않고 무결성이 검증된 데이터가 준비되면, 변환된 객체가 마침내 컨트롤러 메소드의 파라미터에 주입됩니다.


결과적으로 컨트롤러는 HTTP 요청의 복잡한 세부 사항을 전혀 모른 채, 안전하게 가공된 도메인 객체를 즉시 사용할 수 있게 됩니다.




실제  적용 사례


가장 눈에 띄는 변화는 컨트롤러의 간결함입니다. 기존에는 비즈니스 로직과 섞여 있던 '타겟 ID 추출', '유효성 검사', '도메인 변환', '권한 체크' 등의 횡단 관심사(Cross-cutting Concerns)가 완벽하게 분리되었습니다. 덕분에 개발자는 신규 API를 작성할 때 불필요한 반복 코드(Boilerplate)를 작성하는 수고를 덜고, 핵심 비즈니스 로직 구현에만 온전히 집중할 수 있게 되었습니다.


또한, 유지보수 측면에서도 강력한 이점을 가집니다. 만약 타겟 검증 정책이 변경되더라도 수십 개의 컨트롤러를 일일이 수정할 필요 없이, ArgumentResolver의 로직 한 곳만 수정하면 전사적으로 변경 사항이 반영됩니다.


다수의 API에서 [URL로부터 값 추출 → 검증 → 도메인 객체 변환]의 패턴이 반복되는 프로젝트라면, HandlerMethodArgumentResolver를 적극적으로 도입하여 코드의 품질과 생산성을 높여보시는 것을 권장합니다.


유성욱 개발본부 사진
유성욱개발본부

IT 인프라 통합 모니터링 솔루션 Zenius의 개발을 맡고 있습니다.

추천 콘텐츠