# Interceptor

## 스프링 인터셉터

스프링 인터셉터(Spring Interceptor)란 요청이 처리되는 시점들을 간섭할 수 있도록 만들어진 AOP 객체를 말한다. 다음 클래스들을 제공한다.

* Interface `HandlerInterceptor`
* Class `HandlerInterceptorAdapter` (비추천)

![](/files/-MdFkD6lIdFaLsDrBAQK)

간섭이란 해당 시점의 진행 상황을 살펴보거나 변조할 수 있도록 가로채는 것을 말한다. 인터셉터를 통해 간섭할 수 있는 시점은 다음과 같다.

* `preHandle` : 요청이 핸들링(연결)되기 전. 즉, 컨트롤러 실행 전
* `postHandle` : 요청이 핸들링(연결)된 후. 즉, 컨트롤러 실행 후
* `afterCompletion` : 요청에 대한 처리가 최종적으로 완료된 후. 즉, View 생성 후
* ~~`afterConcurrentHandlingStarted` : Servlet 3.0부터 가능한 `비동기 요청 처리` 방식의 경우 `postHandle`, `afterCompletion` 대신 실행 (비추천)~~

## 인터셉터 클래스 작성 및 등록

### 인터셉터 클래스 생성

인터셉터는 다음과 같이 생성한다.

```java
@Slf4j
@Component
public class TestInterceptor extends HandlerInterceptorAdapter{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{ 
        log.info("prehandle = {}", handler);
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle = {}, {}", handler, modelAndView);
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
        log.info("afterCompletion = {}, {}", handler, ex);
    }
    
}
```

### 인터셉터 등록

Spring boot에서는 인터셉터를 <mark style="color:blue;">`WebMvcConfigurer`</mark> 클래스를 상속 받은 설정 클래스에 구현한다. <mark style="color:blue;">`WebMvcConfigurer`</mark> 인터페이스를 상속받은 뒤 <mark style="color:red;">`@Configuration`</mark> 으로 설정 클래스임을 명시하면 제공되는 메소드를 통해 운영 설정을 수행할 수 있다.

```java
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry){
    
    }
}
```

생성된 인터셉터에 등록한 인터셉터를 주입한다.

```java
@Autowired
private TestInterceptor testInterceptor;
```

주입된 인터셉터를 재정의한 설정 메소드에 추가한다.

```java
registry.addInterceptors(testInterceptor).addPathPatterns("/**");
```

완성된 코드는 다음과 같다.

<details>

<summary>InterceptorConfiguration</summary>

```java
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
    
    @Autowired
    private TestInterceptor testInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(testInterceptor).addPathPattern("/**");
    }
    
}
```

</details>

제공되는 매개변수 <mark style="color:blue;">`InterceptorRegistry`</mark>에는 인터셉터와 관련된 정보, 기능들이 존재하며 이 중 **addInterceptor** 메소드를 이용하여 인터셉터를 추가한다. 또한 **addPathPattern** 메소드와 **excludePathPattern** 메소드를 통해 간섭할 대상 매핑을 설정하거나 제외시킬 수 있다.

## Mapping url 작성규칙

Interceptor의 Mapping을 작성할 때에는 다음의 내용을 유의해야 한다.

* 와일드카드(\*)를 사용할 수 있다.
* 와일드카드(\*)의 개수가 1개인지 2개인지에 따라 의미가 달라진다.
  * 1개인 경우는 현재 endpoint 내에서 어떤 글자가 와도 상관없다는 의미이다.
  * 2개인 경우는 현재 endpoint와 하위 전체에서 어떤 글자가 와도 상관없다는 의미이다.

### 매핑 작성 예시(1)

```java
registry.addInterceptors(...).addPathPatterns("/member*");
```

위와 같이 path를 `/member*`로 지정하면 엔드포인트(endpoint)는 `/`로 설정된다.\
따라서 다음 주소들이 매핑된다.

* /member
* /member\_info
* /memberlist

하위 엔드포인트 주소는 포함되지 않는다.&#x20;

* /member/info
* /member/regist
* /member/list

### 매핑 작성 예시(2)

```java
registry.addInterceptors(...).addPathPatterns("/member/*");
```

위와 같이 path를 `/member/*`로 지정하면 엔드포인트(endpoint)는 `/member/`로 설정된다.\
따라서 다음 주소들이 매핑된다.

* /member/info
* /member/regist
* /member/list

다음 주소들은 매핑되지 않는다.

* /member
* /member\_info
* /memberlist
* /member/list/1
* /member/search/module

### 매핑 작성 예시(3)

```java
registry.addInterceptors(...).addPathPatterns("/member/*");
```

위와 같이 path를 `/member/**`로 지정하면 엔드포인트(end-point)는 `/member/`로 설정된다.\
`**`는 `/`를 포함할 수 있으므로 다음 주소들이 매핑된다.

* /member/info
* /member/regist
* /member/list
* /member/list/1
* /member/find/id/test

다음 주소들은 매핑되지 않는다.

* /member
* /member\_info
* /memberlist

## 인터셉터 메소드 분석

인터셉터의 각각 메소드를 분석하여 어떠한 행위를 할 수 있는지 파악해본다.

### preHandle

* 반환 형태
  * `boolean` : 요청의 통과(continue) 여부를 반환할 수 있다. `true` 반환 시 통과 , `false` 반환 시 차단된다.
* 매개 변수
  * `HttpServletRequest` : 요청 정보를 가지고 있는 객체이다.
  * `HttpServletResponse` : 응답 정보를 가지고 있는 객체이다.
  * `Object` : 실행될 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)

### postHandle

* 반환 형태
  * `void` : 이 메소드는 어떠한 결과도 전달할 수 없다.
* 매개 변수
  * `HttpServletRequest` : 요청 정보를 가지고 있는 객체이다.
  * `HttpServletResponse` : 응답 정보를 가지고 있는 객체이다.
  * `Object` : 실행된 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)
  * `ModelAndView` : 처리 완료 후의 `Model`과 `View`의 정보를 가진 객체이다.

### afterCompletion

* 반환 형태
  * `void` : 이 메소드는 어떠한 결과도 전달할 수 없다.
* 매개 변수
  * `HttpServletRequest` : 요청 정보를 가지고 있는 객체이다.
  * `HttpServletResponse` : 응답 정보를 가지고 있는 객체이다.
  * `Object` : 실행된 대상의 정보를 가지고 있는 객체이다.(일반적으로 컨트롤러의 매핑 메소드)
  * `Exception` : 페이지 렌더링 시 발생한 예외 정보를 가진 객체이다.

### afterConcurrentHandlingStarted

<mark style="color:blue;">`AsyncHandlerInterceptor`</mark>를 이용하여 사용할 것을 권장한다.

## Object Handler의 활용

Handler를 이용하면 다음 작업들을 처리할 수 있다.

* 실행될(또는 실행된) 대상의 `유형` 확인
* 실행될(또는 실행된) 대상의 `Annotation Type` 확인
* 그 외 해당 대상의 정보 분석(매개변수, 반환형, 이름, 등...)

> Object Handler를 이용하여 대상의 Annotation 정보 읽어오는 코드

```java
if(handler instanceof HandlerMethod){
    HandlerMethod hm = (HandlerMethod) handler;
    log.info("method name = {}", hm.getMethod().getName());
    log.info("method annotation = {}", hm.getMethodAnnotation(RequestMapping.class));
    //...(이후 원하는 조건 등을 구현)
}
```

이를 응용하면 `Custom Annotation`을 만들어두고 이를 검사하여 원하는 작업을 처리하도록 하는 등의 작업을 구현할 수 있다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sysout.co.kr/web/back-end/spring-boot/spring-aop/interceptor.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
