Spring

Filter, Interceptor, AOP

개요


공통 프로세스

웹 개발을 하다보면 하나의 핸들러에만 적용되는 것이 아니라 서비스 단위로 공통적 으로 처리해야하는 작업들이 있다.
로그인 체크, 세션 체크, 권한 체크, XSS 방어, PC와 모바일웹의 분기처리, 로그, 페이지 인코딩 등등

 

공통적으로 처리해야 하는 작업들을 모든 서비스 마다 작성한다면 중복된 코드가 많아지게되어 프로젝트 단위가 커질수록 서버에 부하를 줄 수 있으며, 유지보수에 어려움을 줄 수 있다. 그렇기 때문에 공통된 작업은 따로 빼서 관리하는게 좋다.

 

공통된 작업을 프로그램의 흐름 앞, 중간, 뒤에 추가하여 자동으로 처리할 수 있는 방법을 알아보자

Filter, Interceptor, AOP


Spring Flow[출처 : https://goddaehee.tistory.com/154]

 

 

Spring Flow

Request(요청) -> Filter(필터) -> Dispatcher Servlet -> Interceptor(인터셉터) -> AOP ->Controller(컨트롤러) -> AOP -> Interceptor(인터셉터) -> Dispatcher Servlet -> Filter(필터) -> Response(응답)

 

Filter (Servlet Filter)


필터는 Java 웹 애플리케이션에서 HTTP 요청과 응답을 가로채어 조작하는데 사용되는 컴포넌트이다.

필터는 서블릿 컨테이너 수준에서 동작하고 스프링 컨테이너 외부에 존재한다.

필터는 DispatcherServlet 이전에 실행이 되는데 필터가 동작하도록 지정된 자원의 앞단에서 요청 내용을 변경하거나, 여러가지 체크 로직을 수행할 수 있다. 또한 자원의 처리가 끝난 후 응답내용에 대해서도 변경하는 처리를 할 수 있다.

ex) 인증 및 권한부여, 로깅 및 검사, 인코딩 변환 처리, 캐싱, 전역 설정 및 초기화, XSS 방어 등의 처리를 할 수 있다.

 

필터의 구현

Filter는 javax.servlet.Filter 인터페이스를 구현하여 작성된다.

 

필터의 실행 메서드

- init(FilterConfig config) : 필터 인스턴스 초기화, 서블릿 컨테이너가 생성될 때 호출된다.

- doFilter(ServletRequest request, ServletResponse response) : 실제 필터링 작업을 수행하는 메서드. 메서드 내에서 체인(FilterChain)을 이용하여 다음 필터로 제어를 전달하거나 최종적으로 서블릿을 전달할 수 있다.

- destory() : 필터 인스턴스 종료. 서블릿 컨테이너가 종료될 때 호출된다. 리소스를 정리하거나 마무리 작업을 수행한다.

 

서블릿 필터는 `web.xml` 또는 자바 기반의 어노테이션을 통해 사용할 필터를 등록해야 한다.

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
@Configuration
public class FilterConfig {
	@Bean
    public FilterRegisrationBean<Filter> myFilter() {
    	FilterRegisrationBean<Filter> bean = new FilterRegisrationBean();
        
        bean.setFilter(new MyFilter());
        baen.setOrder(1);
        bean.addUrlPatterns("/*");
        return bean;
    }
}

 

Interceptor


인터셉터는 Spring이 제공하는 기능으로 Spring MVC에서 사용된다.

인터셉터는 DispathcerServlet이 컨트롤러의 메서드 호출 전(preHandle), 호출 후(postHandle), 뷰의 렌더링 후(afterCompletion)와 같은 시점에서 HTTP 요청과 응답을 가로채어 특정 동작을 수행할 수 있다.

인터셉터는 스프링의 모든 Bean 객체에 접근할 수 있다.

인터셉터는 여러개의 인터셉터를 구현할 수 있다.

인터셉터는 주로 로깅, 보안 체크, 권한 체크, 성능 측정, 트랜잭션 처리 등과 같은 전체 애플리케이션에서 공통으로 수행하는 작업을 구현할 때 사용된다.

 

인터셉터의 구현

Interceptor는 HandlerInterceptor 인터페이스를 구현하여 사용한다.

 

인터셉터의 실행 메서드

preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)

- 실행 시점 : 컨트롤러 호출 전

- 조건에 맞는지 boolean 값을 반환해 true면 실행하고, false면 실행하지 않도록 한다. 

postHandler( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

- 실행 시점 : 컨트롤러 호출 후 view 페이지 렌더링 되기 전

- 컨트롤러 실행 후 추가적으로 공통된 처리를 하고 싶을때 사용(afterComplition()도 동일)

afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler , Exception e)

- 실행 시점 : view 페이지가 렌더링 되고 난 후 (요청 완료 이후)

 

인터셉터 등록

@Configuration
public class WebMvcConfig implements WebMvcConfiguration {
	@Override
   	public void addInterceptors(InterceptorRegitry registry) {
    	registry.addInterceptor(new MyInterceptor())
        		.addPathPatterns("/source/**") // 특정 패턴에 대해서만 Interceptor 적용
                .excludePathPatterns("/public/**"); // Interceptor를 적용하지 않을 패턴
    }
 }

Interceptor 적용 범위 설정

- `addPathPatterns`를 사용하여 어떤 URL 패넡에 Interceptor를 적용할지,

- `excludePathPatterns`를 사용하여 예외 처리할 URL 패턴을 설정한다.

 

인터셉터의 정상적 흐름

인터셉터의 예외처리 흐름

preHandle이 예외를 발생시키면 postHandle은 호출되지 않는다.

하지만 afterCompletion은 항상 호출되기 때문에 주의해야한다. (try-catch의 finally와 비슷하다.)

 

 

AOP


AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)

 

AOP는 Spring의 핵심 구성요소 중 하나이고, OOP(객체 지향 프로그래밍)을 보완하기 위해 나온 개념이다.

OOP에서 모듈화의 핵심 단위는 클래스이지만, AOP에서의 모듈화의 단위는 "관점(Accept)"이다.

"관점"은 type과 object와는 무관하게 "관심사항" 모듈화를 가능하게 한다.

 

 

AOP는 횡단 관심사(Corss-cuttin Concerns)를 모듈화하고 재사용하기위한 프로그래밍 패러다임이다. 횡단 관심사란 애플리케이션의 여러 부분에 걸쳐있는, 중복되는 코드나 기능을 말한다. 예를 들어 로깅, 트랜잭션, 에러 처리 등이 횡단 관심사에 해당한다.

 

"AOP는 횡단 관심사(반복적인 코드)를 사용 목적(공통 관심 사항)에 따라서 공통된 통합 위임 코드를 작성하여 코드의 유지보수성을 향상 시키며, 애플리케이션의 모듈성을 강화하는 것을 목표로한다."


AOP는 스프링 IoC를 보완하며 뛰어난 미들웨어 솔루션을 제공한다.

AOP는 Filter나 Interceptor와는 달리 메서드 전후 지점에 자유롭게 설정이 가능하다. Filter와 Interceptor는 주소로 대상을 지정해야되지만, AOP는 주소, 파라미터, 어노테이션 등 다양한 방법으로 대상을 지정할 수 있다.

 

AOP의 개념과 용어

Aspect (관점) 여러 객체를 관통하는 ‘공통 관심 사항’을 구현한것을 의미합니다. Spring 에서는 설정을 통해 일반 클래스에 넣는 방식(schema-based approach) 혹은 어노테이션을 활용한 방식으로 클래스에 aspect를 줄수 있습니다.
Join point 특정 작업이 시작되는 시점을 나타내는 포인트로, 메서드 호출이나 예외발생 등의 시점들을 의미합니다.
Advice 특정 join point에서 실행되는 action을 뜻하며, 실행 시점에따라 ‘around’, ‘before’, ‘after’의 타입들을 가지고 있습니다.
Pointcut Join point의 부분집합으로써, 실제 Advice가 실행되는 Join point들의 집합을 의미합니다.
weaving Aspect를 Target object에 적용하는것. 컴파일시, 로드타입시, 런타임시 적용시킬수 있으나 Spring에서는 런타임때 적용시킵니다.
Target object advise가 적용되어질 타깃 객체를 의미합니다.
AOP proxy Aspect를 구현하기위해 AOP 프레임워크에서 만들어낸 객체를 의미합니다.
Introduction proxy 객체에 메소드나 필드를 추가한것을 의미합니다.

 

AOP의 Pointcut

@Before : 대상 메서드(조인 포인트)의 수행 전

@After : 대상 메서드의 수행 후

@After-returning : 대상 메서드의 정상적인 수행 후

@After-throwing : 예외 발생 후

@Around : 대상 메서드의 수행 전/후

 

Spring은 AOP를 지원하기 위해 자체 AOP프레임워크를 제공한다.

@Aspect 어노테이션으로 Aspect를 정의하고, @Before, @After, @Around 등의 어노테이션을 사용하여 Advice를 구현한다.

 

Spring AOP는 Proxy 기반으로 작동된다.