본 포스팅은 인프런 Dowon Lee님의
Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의를 토대로 작성되었습니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4


예제 프로젝트 - [MicroService1,2]

  • fisrtService
  • secondService

* Netflix Zuul은 Springboot2.4버전부터 지원이 되지 않는 관계로
강의에선 SpringBoot 2.3.8버전을 사용하였지만, 뭔가 버전문제가 계속 발생하여
일단 2.7.17 버전으로 진행하고, 문제발생시 추후 해결하기로 한다.(무진장 애먹었다...)

application.yml

server:
  port: 8081 #firstService는 8081포트, secondService는 8082포트 사용

spring:
  application:
    name: my-first-service

eureka:
  client:
    fetch-registry: false # eurekaClient로 등록하지 않겠다는 설정
    register-with-eureka: false # eurekaClient로 등록하지 않겠다는 설정

간단한 WelcomePage를 작성한다.

@RestController
@RequestMapping("/")
public class FirstServiceController {

    @GetMapping("/welcome")
    public String welcome() {
        return "Welcome to the First Service";
    }
}

--------------------------------------------------

@RestController
@RequestMapping("/")
public class SecondServiceController {

    @GetMapping("/welcome")
    public String welcome() {
        return "Welcome to the Second Service";
    }
}

포트번호를 달리하여 호출했을때
각각 서비스가 응답을 성공적으로 내려주는 모습을 확인할 수 있다.


[RotingService] - NetfilxZuul

* SpringBoot 2.4버전부터 Zuul에 대한 지원이 되지 않는 관계로
SpringBoot 2.3.8.RELEASE 버전을 사용했으며,
SpringBoot 2.3.8버전으로 다운그레이드 하며 발생한 문제는

https://velog.io/@hana0627/SpringBoot-SpringBoot-%EB%B2%84%EC%A0%84-%EB%8B%A4%EC%9A%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EB%93%9C-%EB%B0%8F-Nexfilx-Zuul-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

여기에 공유해두었다.
훗날 같은 강의를 들으면서 저와 같은 문제를 맞이하는 후배님(?)들이 고생하지 않기를..

application.yml

server:
  port: 8000

spring:
  application:
    name: my-zuul-service

zuul:
  routes:
    first-service:
      path: /first-service/**
      url: http://127.0.0.1:8081
    second-service:
      path: /second-service/**
      url: http://127.0.0.1:8082
  • zuul.routes : 라우팅을 설정
  • path, url : 해당 Path로 접근하면, 지정된 url로 보내겠다는 의미

main.java

@SpringBootApplication
@EnableZuulProxy // Zuul 서비스 이용
public class ZuulServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulServiceApplication.class, args);
    }

}

127.0.0.1:8080 포트로 요청을 보냈는데
뒤의 path에 따라서 다른 포트로 포워딩 해주는 모습을 확인할 수 있다.

8000번이라는 통일된 포트에서 사용자의 요청에 따라 어느 서비스를 호출할 것인지 결정해 주고 있다.
이것이 ZuulService가 제공하는 가장 기본적인 APIGateway, Routing 역할을 수행하는 모습을 볼 수 있다.


[NetfilxZuul] - filter 적용

AOP처럼 요청 전후로 특정한 행동을 취할 수 있는 기능을 제공한다.

ZuulLoggingFilter

package ....filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


@Slf4j
@Component
public class ZuulLoggingFilter extends ZuulFilter {
    /**
     * 실제 어떤 동작을 하는지 지정
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        log.info("********** printing logs: ");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        //Zuul 전용
//        HttpServletRequest request = RequestContext.getCurrentContext().getRequest();

        log.info("********** printing logs: " + request.getRequestURI());
        return null;
    }


    /**
     * 사전필터인지, 사후 필터인지 결정
     * @return "pre" : 사전필터임을 String 문자열로 표기하였음
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 여러개의 필터가 존재할 때 순서를 지정
     * @return 1 : 한개밖에 없으므로 현재 큰 의미는 없다.
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * 필터 사용여부
     * @return true : 사용
     * @return false : 사용하지 않음
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }
}

주석을 달아놨지만 한번 더 정리해본다.

  • filterType()
    해당 필터 타입을 지정한다. String 값이라고 아무값이나 적을수 있는건 아니고,
    적용할 수 있는 몇가지 값이 들이 존재한다.
    현재는 요청 전에 실행된다는 의미로 "pre"로 선언하였다.

  • filterOrder()
    필터가 여러개 존재할 경우 필터의 순서를 지정한다.
    여러필터에서 같은값을 입력해도 딱히 에러가 발생하진 않는다.

  • shouldFilter()
    해당 필터의 사용여부를 정한다
    true 라면 사용 , false라면 미사용

  • run()
    필터에 적용시킬 동작을 정의한다.
    예제에선 간단히 log를 남겼지만,
    상황에 따라서 인증작업을 수행할수도 있고,
    요청정보를 변환하는 과정을 수행하거나, 로그를 DB에 저장한다던가 기타 여러 기능을 수행 할 수 있다.


* 현재 예제에서 재미난점은

  1. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
  2. HttpServletRequest request = RequestContext.getCurrentContext().getRequest();

실제 현업에서 AOP를 적용할땐 1번 코드를 이용해서 request 객체를 가져왔는데
강의에선 2번 방법으로 request객체를 호출하였다.
궁금해져서 1번 방법으로 수행해보니 동일한 결과가 나타났다.

단지 RequestContext 객체는 Zuul이 관리하는 객체이고,
RequestContextHolder 객체는 Spring이 관리하는 객체일 뿐이였다.

1번 방법은 다른 의존성이 없어도 스프링 환경이라면 어디서든지 사용할 수 있는 방법이고,
2번 방법은 코드의 양이 다소 줄어드는 대신, Zuul 라이브러리에 의존적으로 되어있다.
다소 코드가 길어지더라도 버전등 호환성이 더 중요하다 판단하여
예제에서는 1번 방법을 남기고 2번방법을 주석처리 하였다.

profile
성숙해지려고 노력하지 않으면 성숙하기까지 매우 많은 시간이 걸린다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN