项目应用webflux改造接口

作者: pilisiyang | 来源:发表于2019-11-18 14:38 被阅读0次

项目框架spring webflux

Spring boot 在 2.x 版本增添了新的框架 WebFlux。传统的web框架都是基于Servlet API与Servlet容器基础之上运行的,而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上。

什么是webflux:

右侧是spring 5.0 引入的基于Reactive Streams的Spring WebFlux框架,从上到下依次是Router Functions,WebFlux,Reactive Streams三个新组件。

Router Functions:

对标@Controller,@RequestMapping等标准的Spring MVC注解,提供一套函数式风格的API,用于创建Router,Handler和Filter。

WebFlux:

核心组件,协调上下游各个组件提供响应式编程支持。

Reactive Streams:

一种支持背压(Backpressure背压是一种常用策略,使得发布者拥有无限制的缓冲区存储元素,用于确保发布者发布元素太快时,不会去压制订阅者。)的异步数据流处理标准,主流实现有RxJava和Reactor,Spring WebFlux默认集成的是Reactor。
在Web容器的选择上,Spring WebFlux既支持像Tomcat,Jetty这样的的传统容器(前提是支持Servlet 3.1 Non-Blocking IO API),又支持像Netty,Undertow那样的异步容器。不管是何种容器,Spring WebFlux都会将其输入输出流适配成Flux<DataBuffer>格式,以便进行统一处理。

Webflux的优势

首先确定的是,非阻塞的处理方式规避了线程排队等待的情况,从而可以用少量而固定的线程处理应对大量请求的处理。他并不能提升程序的运行速度,但是在大规模同时请求时的吞吐量和响应时长能有显著改善。

Webflux目前的不足

由于MySQL数据库是同步,官方暂时还没推出MySQL数据库驱动异步解决方案,目前只有Mongodb、redis、couchdb、Cassandra官方提供了异步驱动。

项目结构

image.png

项目结构上与spring boot 没有太大区别,其中handler是Router Functions的写法,还有一种与mvc类似的结构,两种不能混用,返回结果统一都是Mono或者Flux。

webflux中使用filter

/**
 * 业务记录日志filter
 *
 * @author pilsy
 */
@Order(-1)
@Component
public class BusinessLogFilter implements WebFilter {

    private static final Logger log = LoggerFactory.getLogger(BusinessLogFilter.class);

    private final LogRepository logRepository;

    private final PathPattern pathPattern;

    @Autowired
    public BusinessLogFilter(LogRepository logRepository) {
        this.logRepository = logRepository;
        pathPattern = new PathPatternParser().parse("/bd-exchange/**");
    }

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {

        final ServerHttpRequest request = serverWebExchange.getRequest();
        // 匹配请求路径
        if (pathPattern.matches(request.getPath().pathWithinApplication())) {
            // 匹配到业务请求记录日志
            RequestPath path = request.getPath();
            MultiValueMap<String, String> queryParams = request.getQueryParams();
            String hostAddress = request.getRemoteAddress().getAddress().getHostAddress();

            LogEntity logEntity = new LogEntity();
            logEntity.setPath(path.value());
            logEntity.setQueryParams(queryParams.toString());
            logEntity.setHostAddress(hostAddress);
            // 保存日志,并打印
            Mono<LogEntity> mono = logRepository.save(logEntity);
            mono.subscribe(entity -> log.info(entity.toString()));
        }
        return webFilterChain.filter(serverWebExchange);
    }

}

webflux中使用RouterFunction

/**
 * 请求路由配置 RouterFunction
 *
 * @author pilsy
 */
@Configuration
public class RouterConfig {

    private final ExchangeHandler exchangeHandler;

    private final AuthHandler authHandler;

    private final ErrorHandler errorHandler;

    private final ViewHandler viewHandler;

    @Autowired
    public RouterConfig(ExchangeHandler exchangeHandler, AuthHandler authHandler, ErrorHandler errorHandler, ViewHandler viewHandler) {
        this.exchangeHandler = exchangeHandler;
        this.errorHandler = errorHandler;
        this.viewHandler = viewHandler;
        this.authHandler = authHandler;
    }

    /**
     * 业务请求路由
     *
     * @return
     */
    @Bean
    public RouterFunction<ServerResponse> exchangeRouterFunction() {
        return RouterFunctions
                .route(POST("/bd-exchange/services/validatePeople.do").and(accept(APPLICATION_JSON)), exchangeHandler::validatePeople)
                .andRoute(POST("/bd-exchange/services/queryPeople.do").and(accept(APPLICATION_JSON)), exchangeHandler::queryPeople);
    }

    /**
     * 鉴权请求路由
     *
     * @return
     */
    @Bean
    public RouterFunction<ServerResponse> AuthRouterFunction() {
        return RouterFunctions
                .route(GET("/auth/error").and(accept(APPLICATION_JSON)), errorHandler::authError)
                .andRoute(GET("/auth/getPage").and(accept(APPLICATION_JSON)), authHandler::getPage)
                .andRoute(POST("/auth/save").and(accept(APPLICATION_JSON)), authHandler::save)
                .andRoute(GET("/auth/delete/{id}").and(accept(APPLICATION_JSON)), authHandler::delete)
                .andRoute(GET("/auth/getSecret").and(accept(APPLICATION_JSON)), authHandler::getSecret);
    }

    /**
     * view页面路由
     *
     * @return
     */
    @Bean
    public RouterFunction<ServerResponse> viewRoutesRegister() {
        return RouterFunctions
                .route(GET("/index"), viewHandler::loginPage)
                .andRoute(GET("/"), viewHandler::loginPage);
    }
}

webflux(使用netty为Web容器)中调整request请求长度限制

package com.gsoft.xc.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class NettyConfiguration implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {

    @Value("${server.max-initial-line-length:65536}")
    private int maxInitialLingLength;

    public void customize(NettyReactiveWebServerFactory container) {
        container.addServerCustomizers(
                httpServer -> httpServer.httpRequestDecoder(
                        httpRequestDecoderSpec -> httpRequestDecoderSpec.maxInitialLineLength(maxInitialLingLength)
                )
        );
    }

}

相关文章

网友评论

    本文标题:项目应用webflux改造接口

    本文链接:https://www.haomeiwen.com/subject/oxfbictx.html