kok202
스프링 부트 강의 정리 (23 ~ 25 : 웹플럭스, 컨테이너)

2019. 5. 11. 02:58[공부] 영상/스프링 부트 강의

웹플럭스

특징 1. Servlet 을 안씀

특징 2. Reactor 기능을 써서 구현

특징 3. depedency에 spring-web 과 spring-webflux 가 동시에 있으면 Spring MVC로 설정한다.

 

 

 

 

 

웹플럭스의 생김새 1

- Annotation 형태

- 맵핑(라우팅)과 핸들러의 병합

- Spring MVC 에서 쓰는 것과 똑같다.

 

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("/{userId}")
    public Mono<User> getUser(@PathVariable Long userId) {
        return Mono.just(userService.findById(userId));
    }
}

 

웹플럭스의 생김새 2

- functional 형태

- 맵핑(라우팅)과 핸들러의 분리

- 핸들러를 핸들러라고 하지 않기 때문에 컨트롤러라고하지 않고 그냥 컴포넌트라고 부른다.

@Component
public class UserHandler{
    @Autowired
    UserService userService;
    
    public Mono<User> getUser(ServerRequest request) {
        // ...
        // request 로부터 userId를 뽑았다고 가정

        Mono<User> mono = Mono.just(userService.findById(userId));
        return ServerResponse
                    .ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(mono, User.class);
    }
}
@Configuration
public class RoutingConfiguration {
    @Bean
    public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
        return route(GET("/users/{userId}").and(accept(APPLICATION_JSON)), userHandler::getUser);
    }
}

 

 

 

 

웹플럭스 Http request, response를 위한 CodecConfigurer

HttpMessageReader and HttpMessageWriter스프링 웹플럭스는 Http 요청과 응답을 해석하기 위해 HttpMessageReader과 HttpMessageWriter를 사용한다.
-> HttpMessageReader과 HttpMessageWriter 는 Codec Configurer에 의해 설정이 된다.
-> 스프링 부트를 통해 CodecConfigurer 를 커스터 마이징 할 수 있다.

-> 예를들어 application.properties에서 spring.jackson.* 설정 키는 jackson codec 을 커스터 마이징 하기 위한 키다.

 

 

 

 

 

Static content

ResourceWebHandler 를 쓰기 때문에 Spring MVC와 거의 똑같다. 커스터마이징 하고 싶으면 WebFluxConfigurer 를 추가하고 WebFluxConfigurer 안의 addResourceHandlers 메소드를 오버라이딩 하면된다.

spring.webflux.static-path-pattern=/resources/**

기본적으로 /** 를 기준으로 resource를 탐색하는데 /resources/** 으로 path 를 바꾸고 싶다면 위와 같은 설정으로  static content의 path를 변경할 수 있다.

 

 

 

 

 

타임리프 템플릿을 웹플럭스에 적용하기

템플릿 리소스에 관련된 패스는 자동으로 src/main/resources/templates 으로 설정되어 있다.

타임리프는 리액티브의 특성을 반영해서 뷰를 완성하기 위해 block 이 되는 것을 최소화한다.

타임리프 관련 예제 프로젝트 : https://www.thymeleaf.org/issuetracking.html

 

Issue Tracking - Thymeleaf

 

www.thymeleaf.org

full : 모든 데이터가 컨트롤러에 준비가 되면 뷰에 전달해서 뷰가 렌더링 하도록 한다.

chunk : chunk 단위로 데이터가 컨트롤러에 가득 차면 뷰에 전달해서 뷰가 렌더링 하도록 한다.

응답 속도는 큰 차이가 없지만 반응 속도 면에서 굉장히 빨라진다.

 

 

 

 

에러 핸들링

WebExceptionHandler 를 이용하여 에러를 핸들링한다. 스프링 부트는 웹 브라우저용 클라이언트는 white label 이 만들어주는 페이지를 보여주고 머신 클라이언트는 Json 으로 에러정보를 보여준다. 이러한 행위(웹 브라우저용 클라이언트는 white label 이 만들어주는 페이지를 보여주고 머신 클라이언트는 Json)를 바꾸고 싶다면 ErrorWebExceptionHandler 를 재정의 해주면된다.

 

 

 

 



내장 서블릿 컨테이너

스프링 부트는 Tomcat, Jetty, Udertow, Netty 등을 내장 컨테이너로 지원한다.

* CentOS는 tomcat을 돌릴 때는 temporary directory에 업로드 하는 파일이 올라갈 수 있으므로 조심해야한다.

 

 

 

 

Servlet, Filter, Listener 를 등록하는 방법

1. @Component + implements 로 등록하기

2. Annotation 기반으로 등록하기 (추천)

3. WebApplicationInitializer 를 통해 등록하기

 

 

 


1. @Component + implements 로 등록하기 (웹 필터 예시)

스프링 부트는 웹 필터를 지원한다. 필터들간의 순서를 주고 싶으면 Ordered 구현체를 구현하거나 @Order를 사용하면된다. 

@Component
public class UserFilter implements WebFilter {
    @Override
    public Mono<User> filter(ServerWebExchange exchange, WebFilterChain chain){
        System.out.println("hello user filter");
        return chain.filter(exchange);
    }
}

curl -XGET localhost:8080/users/123

-> 요청이 처리되기 전에 필터가 처리되서 hello user filter가 서버에 찍히고 userId 가 1234 인 유저를 반환한다.

 

Webfilter 는 웹 브라우저를 통한 요청을 처리하는 필터고, Filter는 머신 클라이언트를 통한 요청을 처리하는 필터정도 인 듯 하다. 필터는 /* 기준으로 모두 적용된다. 이를 제어하고 싶다면 ServletRegistrationBean, FilterRegistrationBean, ServletListenerRegistrationBean 를 이용하면 된다.

 

 

 

 


2. Annotation 기반으로 등록하기

@WebServlet, @WebFilter, @WebListener 를 사용한 경우 @ServletComponentScan 를 이용하여 Annotation 으로 선언한 bean 을 불러올 수 있다. 이 방법을 사용할 경우 @ServletComponentScan 를 MainApplication에 달아주는 것을 잊지 말자.

 

 

 

 

 

3. WebApplicationInitializer 를 통해 등록하기

web.xml을 대체하는 자바 클래스 = WebApplicationInitializer

원래 web.xml 에 필터, 서블릿, 이니셜라이저를 추가하고 그랬지만 WebApplicationInitializer을 사용하여 등록할 수 있다.

 

 

 

 

 

ApplicationContext 

스프링 부트는 내장 컨테이너를 지원하기 위해 여러 ApplicationContext 를 지원한다. 대부분의 어플리케이션은 자동으로 설정이 완료되고 적당한 ApplicationContext ServletWebServerFactory 으로 만들어진다.

(팩토리 예시 :  TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory)

 

 

 

 

 

내장 컨테이너를 설정하는 방법

방법 1. application.properties 으로 구현하기 (추천)

방법 2. 프로그래밍으로 구현하기

방법 2가 궁금하다면 Doc 참조 : https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-programmatic-embedded-container-customization

 

내장 컨테이너의 설정을 바꿀 수 있는 것들은 다음의 것들이 있다.

- 네트워크 설정: ex. (server.port) (server.address)
- 세션 설정 : ex. 세션 타임아웃 (server.servlet.session.timeout) ...

- 쿠키 설정 : ex. (server.servlet.session.cookie.*) ...
- 에러 설정 : ex. 에러 페이지의 위치 변경 (server.error.path) ...
- SSL
- HTTP compression