티스토리 뷰

1. intercepter란 뭘까?

인터셉터는 Spring MVC의 핵심 기능 중 하나로, 웹 애플리케이션에서 공통적인 처리를 재사용할 수 있게 해주는 강력한 도구입니다.

 

인터셉터(Interceptor)는 들어오는 요청과 나가는 응답을 가로채어 특정 로직을 수행할 수 있게 해주는 매커니즘을 제공합니다. 이는 AOP(Aspect-Oriented Programming)의 일종으로 볼 수 있으며, 컨트롤러(Controller)로 요청이 도달하기 전, 후 또는 완료된 후에 추가적인 처리를 하기 위해 사용됩니다.

 

 

대표적인 활용 사례

  1. 인증 및 권한 부여: 사용자의 인증 정보를 검사하여 요청이 유효한 사용자로부터 온 것인지 확인하고, 특정 자원에 대한 접근 권한을 확인합니다.
  2. 로깅 및 감사: 요청의 처리 과정에 대한 로깅을 수행하거나 감사 로그를 생성하여 시스템의 보안과 무결성을 유지하는 데 도움을 줍니다.
  3. 성능 모니터링: 요청 처리 시간을 측정하고 성능 문제를 식별하기 위한 메트릭을 수집합니다.
  4. 공통적인 응답 데이터 추가: 모든 응답에 공통적으로 포함되어야 하는 헤더나 데이터를 추가합니다.

 

 

인터셉터 구현 방법

먼저 딱 2가지만 기억해 봅시다.

1. 동작 시키고자 하는 인터셉터 기능을 클래스로 만들어 준다.

단, 만들고 자 하는 해당 클래스에 HandlerInterceptor 인터페이스를 구현하거나 HandlerInterceptorAdapter 클래스를 상속받아야 합니다.

 

2. 내가 만든 인터셉터를 Spring Boot 애플리케이션에 등록을 해주어야 동작 한다.

등록시에는 WebMvcConfigurer 인터페이스를 구현하는 설정 클래스에서 addInterceptors 메서드를 오버라이드하여 인터셉터를 등록합니다.

당연히 필요하다면 인터셉터를 구현한 사용자 정의 클래스를 여러개 정의해서 프로젝트에 활용 할 수 있습니다.

 

 

2. 인터셉터 구현 클래스 만드는 방법과 인터셉트를 등록 처리

 

handler 패키지에 AuthIntercepter class 생성

 

AuthIntercepter
package com.tenco.bank.handler;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.tenco.bank.handler.exception.UnAuthorizedException;
import com.tenco.bank.repository.model.User;
import com.tenco.bank.utils.Define;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

// 1개의 class 단위로 등록할 때 사용
@Component // (하나의 클래스를 ) IoC 대상(싱글톤 패턴)
public class AuthIntercepter implements HandlerInterceptor {

	// preHandle 동작 흐름 (단, 스프링부트 설정 파일, 설정 클래스에 등록이 되어야 함 : 특정 URL)
	// 컨트롤러 들어 오기 전에 동작함
	// true --> 컨트롤러 안으로 들여보냄
	// false --> 컨트롤러 안 으로 못 들어감
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		HttpSession session = request.getSession();
		User principal = (User) session.getAttribute(Define.PRINCIPAL);
		if(principal == null) {
			throw new UnAuthorizedException("로그인 먼저 해주세요", HttpStatus.UNAUTHORIZED);
		}
		return true; // controller로 들여보내줌
	}
	
	
	// postHandle
	// 뷰가 렌더링 되기 바로 전에 콜백되는 메서드
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}
	
	// afterCompletion
	// 요청 처리가 완료된 후, 즉 뷰가 완전 렌더링이 된 후에 호출된다.
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}
}
  • 컨트롤러 호출 전 : preHandle
  • 컨트롤러 호출 후 : postHandle
  • 요청 완료 이후 : afterCompletion, 뷰가 렌더링 된 이후에 호출된다.

 

3. config/WebMvcConfig.java 파일 생성 - 인터셉터 등록 하기

 

config 패키지를 생성하여 WebMvcConfig 클래스 생성

 

WebMvcConfig
package com.tenco.bank.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.tenco.bank.handler.AuthIntercepter;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor // 생성자 대신 사용
@Configuration  // 1 개 이상의 bean을 등록할 때 설정
public class WebMvcConfig implements WebMvcConfigurer {

	@Autowired
	private final AuthIntercepter authIntercepter;
    
// 생성자 => @RequiredArgsConstructor (생성자 대신 사용 가능)
//	public WebMvcConfig(AuthIntercepter authIntercepter) {
//		this.authIntercepter = authIntercepter;
//	}
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(authIntercepter)
		.addPathPatterns("/account/**")
		.addPathPatterns("/auth/**");
	}
}

 

AuthInterceptor 인터셉터를 Spring의 인터셉터 체인에 등록하여 특정 URL 패턴에 대해 인증 로직을 실행하는 것입니다. 

 

@RequiredArgsConstructor는 final 필드로 인자를 받는 생성자를 자동으로 생성해줍니다. 

@configuration는 이 클래스가 Spring 설정 클래스를 의미하며, 하나 이상의 Bean을 등록하는 데 사용됩니다. 

 

@Autowired
private final AuthIntercepter authIntercepter;

=> 위 코드에서 AuthIntercepter 는 @Autowired을 통해 의존성 주입(DI)이 되고,

final로 선언되어 있어 해당 객체가 변경되지 않음을 의미합니다. (불변)

 

  • addInterceptors 메서드는 Spring MVC의 인터셉터 체인에 인터셉터를 등록하는 역할을 합니다. 
  • registry.addInterceptor(authIntercepter)를 통해 authIntercepter가 인터셉터 체인에 추가됩니다. 
  • addPathPatterns("/account/**")와 addPathPatterns("/auth/**")는 특정  URL 패턴에 대해 authIntercepter가 동작하도록 설정합니다. ( /account/** 와 /auth/** 로 시작하는 모든 요청에 대해 인터셉터가 적용됩니다. 

즉, Spring Boot 애플리케이션에서 웹 요청이 /account/**나 /auth/** 패턴에 해당할 때 AuthIntercepter 를 통해 가로채고, 필요한 인증 작업을 수행할 수 있도록 설정하는 역할을 합니다. 

 

 

AccountController에서 모든 메서드마다 인증검사했던 코드를 지울 수 있습니다. 


추가 개념 설명

Spring 애플리케이션 컨텍스트

spring 프레임워크에서 객체(Bean)의 생성, 관리, 의존성 주입 등을 담당하고, 애플리케이션 전반에 걸쳐 필요한 곳에  Bean을 주입하는 역할을 합니다. 

 

주요 기능

Bean 정의 : xml 파일, Java 클래스, 어노테이션 등을 통해 정의된 Bean들을 관리합니다. 

의존성 주입: 필요한 Bean을 자동으로 주입하여 객체 간의 의존성을 관리합니다. 

라이프사이클 관리: Bean의 생성, 초기화, 소멸 등 라이프 사이클을 관리합니다. 

스코프 관리: Bean의 스코프를 설정하여 싱글톤, 프로토타입 등의 Bean을 생성하고 관리합니다.

( 해당 Bean의 인스턴스가 애플리케이션 컨텍스트 내에서 단 하나만 생성되어 모든 요청에서 동일한 인스턴스를 사용함을 의미합니다.)

 

 

의존성 주입(DI)

객체 간의 의존성을 Spring 프레임워크가 자동으로 관리해주는 디자인 패턴

이 패턴을 사용하면 객체가 직접 다른 객체를 생성하기 않고 필요한 객체를 외부에서 주입 받아 사용할 수 있습니다. 

 

@Autowired 어노테이션

Spring이 해당하는 필드에 적절한 객체를 자동으로 주입하도록 지시하고 Spring 은 해당 타입의 Bean을 찾아 주입합니다. 

private final AuthIntercepter authIntercepter;는 AuthIntercepter 객체를 주입 받을 필드이고, final 키워드를 사용했기 때문에 이 필드는 반드시 생성자에서 초기화되거나, DI를 통해 초기화되어야 합니다.

 

 

@Configuration 어노테이션

해당 클래스가 하나 이상의 Bean을 정의하고 있음을 Spring에게 알려주는 역할을 합니다. 이 클래스는 Spring의 IoC 컨테이너에 의해 관리되며, 여기서 정의된 Bean들은 애플리케이션 내에서 재사용 가능하고, Spring이 자동으로 관리하게 됩니다.

  • @Configuration 애노테이션은 WebMvcConfig 클래스가 Spring의 설정 클래스임을 나타냅니다. 이 클래스는 주로 애플리케이션 컨텍스트에 Bean을 등록하는데 사용됩니다.
  • Spring 애플리케이션이 시작되면 @Configuration이 붙은 클래스를 찾아 해당 클래스를 빈 팩토리로 인식하고, 필요한 Bean들을 생성하고 관리합니다.

 

@Configuration이 사용된 이유

@Configuration 클래스 내에서 Bean을 등록하는 가장 일반적인 방법은 @Bean 애노테이션을 사용하는 것입니다. 하지만 왜 @Configuration이 사용되었을까요?

 

이유는 WebMvcConfig 클래스 자체가 Spring의 구성 요소로 등록되고, 여기에서 설정된 모든 것들이 Spring 컨텍스트에 반영되기 때문입니다. 이 클래스에서 인터셉터와 같은 MVC 구성 요소를 등록할 수 있는 설정을 제공하기 위해 @Configuration을 사용합니다.

 

 

@configuration과 @Bean의 차이

 

  • 역할:
    • @Configuration은 클래스 레벨에서 사용되며, 해당 클래스가 Spring의 설정 파일임을 나타냅니다.
    • @Bean은 메서드 레벨에서 사용되며, 메서드가 반환하는 객체를 Spring 컨테이너에 Bean으로 등록합니다.
  • 위치:
    • @Configuration은 클래스 선언부에 위치하며, 해당 클래스 전체를 Spring 설정 클래스로 만듭니다.
    • @Bean은 메서드 선언부에 위치하며, 해당 메서드가 반환하는 객체를 Spring Bean으로 만듭니다.
  • 싱글톤 보장:
    • @Configuration 클래스에서 정의된 @Bean 메서드는 CGLIB 프록시를 통해 싱글톤을 보장합니다. 동일한 Bean이 여러 번 요청될 때도 동일한 인스턴스를 반환합니다.
    • @Bean 자체는 싱글톤을 보장하는 메커니즘이 없지만, @Configuration 클래스 내에서 사용될 때는 Spring이 싱글톤으로 관리합니다.

* CGLIB 프록시: @Configuration 클래스는 CGLIB 프록시를 사용하여 싱글톤 Bean을 보장합니다. 즉, 동일한 @Bean 메서드가 여러 번 호출되더라도 동일한 인스턴스를 반환합니다.

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함