Web Programming

백엔드 개발자 기술 질문 리스트 - Spring Framework

놋수저 2023. 3. 1. 19:47
반응형

스프링 프레임워크는 왜 생긴 것인가?

이전에는 서버사이드 처리를 직접 쓰레드, 소켓연결 등을 개발자들이 직접 처리했고, 개발자 마다 구현하는 방법이 달라 협업에 불편함이 많았다.
이러한 상황에서 개발 표준을 잡은 것이 Java Enterpricse Edition이다. 이 안에는 많은 스펙들을 담았고 개발자들은 그 스펙들을 구현하는 방법을 사용하기 시작했다. 그러나 구현하는 과정도 개발자 마다 여러 방법으로 나뉘게 되고, 개발자들은 정형화, 표준화된 방법을 찾기 시작했는데 이러한 배경에서 등장한 것이 Framework이다.
많은 종류의 Framework이 등장하고 자바 진영에서는 대표적으로 EJB가 나왔지만 분산환경 처리에 특화된 EJB는 너무 무겁고 불편한점이 많아 경량화된 Java Enterprise용 Framework가 Spring이다.

왜 스프링을 사용하는가?

스프링은 Framework이고 Framework은 개발자들이 좀 더 쉽고 편리하게 애플리케이션을 개발할 수 있도록 미리 갖춰진 구조를 말한다.
Framework이 없었다면 개발자들은 처음부터 끝까지 모든 구조를 만들어내야하는데 이렇게 만들어진 프로그램의 성능은 개발자의 역량에 따라 극명히 갈리게 된다.
스프링은 Application 개발에 필요한 하부 구조를 포괄적으로 제공함에 따라 개발자들의 실력의 간극을 메꿔줄 수 있는 데다가 올바른 형태의 코드만 넣어준다면 성능과 안정성을 보장할 수 있다.
스프링의 틀과 구조 위에서 개발자들은 핵심 비즈니스 로직에만 집중할 수 있어서 생산성 또한 향상된다.

Spring DI(Dependency Injection)

제어의 역행으로 특정 객체에 필요한 다른 객체를 외부에서 결정해서 연결시키는 것이다. 설정만 해주면 스프링은 그 설정 정보를 참고해서 객체를 생성, 관리하고 그 관계를 맺어준다.
DI의 핵심은 개발자가 new 연산자 등을 통해 객체를 생성할 필요가 없다는 것이다.
개발자 입장에서는 스프링 컨테이너에게 @Autowired나 setter주입 등으로 참조변수만 알려준다면 스프링이 알아서 객체를 생성해주고 관계를 맺어준다. 이를 DI라고 하며, 개발자는 자신의 코드에 필요한 객체를 스프링을 통해 주입받는 구조로 코드를 작성한다.

객체 주입 방식

  • Autowired
  • setter 주입
  • 생성자
    • 생성자를 통한 의존성 주입은 객체 생성 시점에서 순환참조가 일어나기 때문에 스프링 애플리케이션에서 실행되지 않아 앱 구동단계에서 오류를 찾을 수 있다.

@Autowired, @Resource, @Inject 차이점

3가지 모두 의존관계를 자동으로 연결해주는 어노테이션이다.

  • @Autowired
    • 스프링에서 지원하며 타입에 맞춰 연결한다.
    • @Qualifier를 이용하면, 타입이외의 방법으로 연결할 수 있다.
  • @Inject
    • 자바에서 지원하며 타입에 맞춰 연결한다.
    • @Qualifier를 이용하면, 타입이외의 방법으로 연결할 수 있다.
  • @Resource
    • 자바에서 지원하며 이름에 맞춰 연결한다.

Spring MVC Request Lifecycle

출처: https://all-record.tistory.com/164
  • Filter
    • Web Application의 전역적인 로직을 담당하며 전체적인 필터링(설정)을 하는 곳이다.
    • DispatcherServlet에 들어가기 전인 Web Application 단에서 실행된다.
  • DispatcherServlet
    • 들어오는 모든 Request를 우선적으로 받아 처리해주는 서블릿이다.
    • HandlingMapping에게 Request에 대해 매핑할 Controller 검색을 요청한다.
    • HandlerMapping으로 부터 Controller 정보를 반환받아 해당 Controller를 매핑시칸다.
    • 말 그대로 Request에 대해 어느 컨트롤러로 매핑시킬 것인지 배치하는 역할을 한다.
  • HandlerMapping
    • DispatcherServlet으로 부터 검색을 요청받은 Controller를 찾아 정보를 리턴해준다.
  • Interceptor
    • Request가 Controller에 매핑되기 직전 부가적인 로직을 끼워넣는다. 
    • 주로 세션, 쿠키, 권한 인증 로직에 많이 사용된다.
  • Controller
    • Request가 매핑되는 곳이다.
    • Request에 대해 어떤 로직으로 처리할 것인지를 결정하고, 그에 맞는 Service를 호출하고 처리한다.
    • Service Bean을 스프링 컨테이너로부터 주입받아, Serivce Bean의 메소드를 호출한다.
  • ViewResolver
    • Controller에서 리턴한 View의 이름을 DispatchServlet으로 부터 넘겨받고, 해당 View를 렌더링한다.
    • 렌더링한 View는 DispatchServlet으로 리턴하고, DispatchServlet에서는 해당 View 화면을 Response 한다.

Filter, Interceptor

출처: https://mangkyu.tistory.com/173
  • Filter
    • DispatcherServlet에 들어가기 전인 Web Application단에서 실행된다.
    • Web Application 단의 기능만 사용할 수 있다.
  • Interceptor
    • Spring Application 단에서 실행된다.
    • AOP가 적용되기 이전 시점에서 실행된다.
    • Spring Framework의 요소들에 접근이 가능하고 기능들을 사용할 수 있다.
대상 Filter Interceptor
관리 위치 Web Application Spring Application
Reuqest, Response 조작 가능 여부 가능 불가능
용도 - 공통된 보안 및 인증/인가 관련 작업
- 모든 요청에 대한 로깅 또는 감사
- 이미지/데이터 압축 및 문자열 하드코딩
- Spring과 분리되어야 하는 기능
- 세부적인 보안 및 인증/인가 공통 작업
- API 호출에 대한 로깅 또는 감사
- Controller로 넘겨주는 데이터 가공

필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없다. 여기서 조작한다는 것은 내부 상태를 변경한다는 것이 아니라 다른 객체로 바꿔친다는 의미이다. 이는 필터와 인터셉터의 코드를 보면 바로 알 수 있다.
필터가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 한다. 그리고 이때 Request/Response 객체를 넘겨주므로 우리가 원하는 Request/Response 객체를 넣어줄 수 있다. NPE가 나겠지만 null로도 넣어줄 수 있는 것이다.

public MyFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 개발자가 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(request, response);       
    }
    
}

 
하지만 인터셉터는 처리 과정이 필터와 다르다. 디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, for문으로 순차적으로 실행시킨다. 그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다. 그러므로 우리가 다른 Request/Response 객체를 넘겨줄 수 없다. 그리고 이러한 부분이 필터와 확실히 다른 점이다.

public class MyInterceptor implements HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Request/Response를 교체할 수 없고 boolean 값만 반환할 수 있다.
        return true;
    }

}

필터(Filter)의 용도 및 예시

  • 공통된 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 감사
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능
  • 인코딩 처리, XSS 방어 등의 요청에 대한 처리

필터에서는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
대표적으로 보안 공통 작업이 있다. 필터는 인터셉터보다 앞단에서 동작하므로 전역적으로 해야하는 보안 검사(XSS 방어 등)를 하여 올바른 요청이 아닐 경우 차단을 할 수 있다. 그러면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 더욱 높일 수 있다.
또한 필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다. Filter는 다음 체인으로 넘기는 ServletRequest/ServletResponse 객체를 조작할 수 있다는 점에서 Interceptor보다 훨씬 강력한 기술이다. 대표적으로 필터(Filter)를 인증과 인가에 사용하는 도구로는 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 Spring MVC에 종속적이지 않다는 것인데, 이러한 이유로는 필터 기반으로 인증/인가 처리를 하기 때문이다.

인터셉터(Interceptor)의 용도 및 예시

  • 세부적인 보안 및 인증/인가 공통 작업
  • API 호출에 대한 로깅 또는 감사
  • Controller로 넘겨주는 정보(데이터)의 가공
  • 로그인 체크, 권한 체크, API 처리 관련 작업 로그 확인

인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
대표적으로 세부적으로 적용해야 하는 인증이나 인가와 같이 클라이언트 요청과 관련된 작업 등이 있다. 예를 들어 특정 그룹의 사용자는 어떤 기능을 사용하지 못하는 경우가 있는데, 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.
또한 인터셉터는 필터와 다르게 HttpServletRequest나 HttpServletResponse 등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없다. 대신 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이하다. 예를 들어 사용자의 ID를 기반으로 조회한 사용자 정보를 HttpServletRequest에 넣어줄 수 있다.
그 외에도 우리는 다양한 목적으로 API 호출에 대한 정보들을 기록해야 할 수 있다. 이러한 경우에 HttpServletRequest나 HttpServletResponse를 제공해주는 인터셉터는 클라이언트의 IP나 요청 정보들을 포함해 기록하기에 용이하다.

AOP

AOP는 관점 지향 프로그래밍을 말하며, 관점을 기준으로 다양한 기능을 분리하여 보는 프로그래밍이다. 부가 기능과 기능을 적용할 곳을 정의하고 합쳐서 모듈로 만든 것이다.
웹 애플리케이션이라면 핵심적인 비즈니스 로직이 있고, 로깅, 보안, 트랜잭션 같은 부가 기능 로직이 있다. 이를 횡단 관심사라고 한다.
횡단 관심사의 코드를 핵심 비즈니스 로직의 코드와 분리하여, 코드의 간결성을 높이고 변경에 유연함과 무한한 확장이 가능하도록 하는 것이 AOP의 목적이다.

  • Aspect
    • 공통 기능
    • 어드바이스 + 포인트컷을 모듈화한 애플리케이션의 횡단 기능
  • Join Point
    • 애플리케이션 실행 흐름에서의 특정 포인트 (ex. 클래스 초기화, 메서드 호출, 예외 발생 등)
    • 한 마디로 AOP를 적용할 수 있는 모든 지점 (스프링에서는 메서드 실행 지점으로 제한)
  • Advice
    • 조인포인트에서 실행되는 코드 즉 부가기능 그 자체
    • 에스팩트를 언제 핵심 코드에 적용할지 정의
  • Pointcut
    • 조인포인트 중 어드바이스가 적용될 지점을 선별하는 기능
    • 주로 AspectJ 표현식으로 지정
      • Target
        • 핵심 기능을 담은 모듈 (=부가 기능 부여 대상)
        • 어드바이스를 받는 객체이고, 포인트컷으로 결정된다
      • Advisor
        • 스프링 AOP에서만 쓰는 용어로, 하나의 어드바이스와 하나의 포인트컷으로 구성된 에스팩트를 특별하게 지칭하는 말이다.

인터셉터(Interceptor)와 AOP의 비교

인터셉터 대신에 컨트롤러들에 적용할 부가기능을 어드바이스로 만들어 AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)를 적용할 수도 있다.
AOP보다 인터셉터가 적합한 예시

  • 컨트롤러는 타입과 실행 메소드가 모두 제각각이라 포인트컷(적용할 메소드 선별)의 작성이 어려움
  • 컨트롤러는 파라미터나 리턴 값이 일정하지 않음
  • AOP에서는 HttpServletRequest/Response를 객체를 얻기 어렵지만 인터셉터에서는 파라미터로 넘어옴
반응형
LIST