我的编程空间,编程开发者的网络收藏夹
学习永远不晚

spring webflux自定义netty 参数解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

spring webflux自定义netty 参数解析

自定义 webflux 容器配置

配置代码


@Component
public class ContainerConfig extends ReactiveWebServerFactoryCustomizer {
    public ContainerConfig(ServerProperties serverProperties) {
        super(serverProperties);
    }
    @Override
    public void customize(ConfigurableReactiveWebServerFactory factory) {
        super.customize(factory);
        NettyReactiveWebServerFactory nettyFactory = (NettyReactiveWebServerFactory) factory;
        nettyFactory.setResourceFactory(null);
        nettyFactory.addServerCustomizers(server ->
                server.tcpConfiguration(tcpServer ->
                        tcpServer.runOn(LoopResources.create("mfilesvc", Runtime.getRuntime().availableProcessors() * 4, Runtime.getRuntime().availableProcessors() * 8, true))
                                .selectorOption(CONNECT_TIMEOUT_MILLIS, 200)
                ).channelGroup(new ChannelGroup())
        );     
    }
    @Override
    public int getOrder() {
        return -10;
    }
}

服务重启时 报错

SpringContextShutdownHook Socket couldn't be stopped within 3000ms

解决方案

初识Spring WebFlux

在我的认识中,大部分人都在用SpringMVC(包括我自己)。在最近的学习中,发现spring5中有一个和SpringMVC平级的东西Spring WebFlux,接下来初步认识一下这是个什么东东?

Spring Web新的改变

众所周知Spring MVC是同步阻塞的IO模型,当我们在处理一个耗时的任务时,如上传文件,服务器的处理线程会一直处于等待状态,等待文件的上传,这期间什么也做不了,等到文件上传完毕后可能需要写入,写入的过程线程又只能在那等待,非常浪费资源。为了避免这类资源的浪费,Spring WebFlux应运而生,在Spring WebFlux中若文件还没上传完毕,线程可以先去做其他事情,当文件上传完毕后会通知线程,线程再来处理,后续写入也是类似的,通过异步非阻塞机制节省了系统资源,极大的提高了系统的并发量。这两种形式,是不是像极了BIO和NIO这两种形式,实际上,SpringMVC和Spring WebFlux也就是这两种IO特点的体现。

以下为官网的介绍:

在这里插入图片描述

Spring WebFlux的特性

1.异步非阻塞

如上文所说,线程不需要一直处于等待状态,Spring WebFlux很好的体现了NIO的异步非阻塞思想。

2.响应式(reactive)编程

响应式编程是一种新的编程风格,其特点是异步和并发、事件驱动、推送PUSH机制一级观察者模式的衍生。reactive引用允许开发者构建事件驱动,可扩展性,弹性的反应系统:提供高度敏感的实时用户体验感觉,可伸缩性和弹性的引用程序栈的支持,随时可以部署在多核和云计算架构。

Reactive的主要接口:

  • Publisher:发布者,数据的生产端
  • Subscriber:消费者,此处可以定义获取到数据后响应的操作
  • Processor:消费者与发布者之间的数据处理
  • back pressure:背压,消费者告诉发布者自己能处理多少数据

消费者的回调方法:

  • onSubscribe:订阅关系处理,用它来响应发布者
  • onNext:接收到数据后会响应的方法
  • onError:出现错误时处理的方法
  • onComplete:任务完成后响应的方法

3.适配多种web容器

既然Spring WebFlux很好的体现了NIO的异步非阻塞思想。作为首屈一指的NIO框架netty,便是Spring WebFlux默认的运行容器。此外,大家熟悉的Tomcat、Jetty等Servlet容器,也能运行Spring WebFlux,前提是容器需要支持Servlet3.1,因为非阻塞IO是使用了Servlet3.1的特性。

Spring WebFlux简单实践

本文默认开发环境是JDK8,开发工具是IDEA。实践分两部分内容,第一部分与SpringMVC对比开发中的不一样的地方;第二部分为Spring WebFlux独有的响应式编程的简单实践。

在webflux中,Mono代表返回0或1个元素(相当于一个对象)。Flux代表返回0-n个元素(相当于集合)

1.工程创建

新建springboot工程。

选择Web -> Spring Reactive Web 创建

在这里插入图片描述

或者在springboot工程中pom文件添加依赖


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2.Controller中与SpringMVC的对比

在controller中,webflux的写法可以和springMVC的写法类似


@RestController
@Slf4j
public class UserController {
    @RequestMapping("/index")
    public String index(){
        log.info("springmvc index begin");
        String result="cc666";
        log.info("springmvc index end");
        return result;
    }
    @RequestMapping("/index2")
    public Mono<String> index2(){
        log.info("webflux index begin");
        Mono<String> result=Mono.just("666cc");
        log.info("webflux index end");
        return result;
    }
}

3.异步非阻塞的体现

上面已经实现了初步的数据返回,不过webflux和springmvc目前来看没有什么区别,已知springmvc线程执行时会阻塞的,webflux线程是异步非阻塞的。下面修改一下代码,在获取数据的时候加一些额外的耗时操作,看看webflux是否是真的异步非阻塞


@RestController
@Slf4j
@AllArgsConstructor
public class UserController {
    
    public String createStr(){
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "cc666cc";
    }
    @RequestMapping("/index")
    public String index(){
        log.info("springmvc index begin");
        String result=this.createStr();
        log.info("springmvc index end");
        return result;
    }
    @RequestMapping("/index2")
    public Mono<String> index2(){
        log.info("webflux index begin");
        Mono<String> result=Mono.fromSupplier(()->this.createStr());
        log.info("webflux index end");
        return result;
    }
}

通过日志结果,可以很明显的发现,虽然前端页面展示的效果是一样的,但springmvc是等待后返回结果;而webflux是先执行,等有结果后,再返回结果。由此体现了webflux异步非阻塞的特性

springmvc
2020-08-04 21:28:57.430  INFO 14156 --- [ctor-http-nio-2] c.w.webflux.controller.UserController    : springmvc index begin
2020-08-04 21:29:00.430  INFO 14156 --- [ctor-http-nio-2] c.w.webflux.controller.UserController    : springmvc index end
webflux
2020-08-04 21:29:09.640  INFO 14156 --- [ctor-http-nio-2] c.w.webflux.controller.UserController    : webflux index begin
2020-08-04 21:29:09.641  INFO 14156 --- [ctor-http-nio-2] c.w.webflux.controller.UserController    : webflux index end

4.添加数据库支持

对于数据库的支持,webflux用到的是r2dbc这样一个东西。

R2DBC(Reactive Relational Database Connectivity)是一个使用反应式驱动集成关系数据库的孵化器。Spring Data R2DBC运用熟悉的Spring抽象和repository 支持R2DBC。基于此,在响应式程序栈上使用关系数据访问技术,构建由Spring驱动的程序将变得非常简单。

在pom中引入依赖:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
    <groupId>com.github.jasync-sql</groupId>
    <artifactId>jasync-r2dbc-mysql</artifactId>
    <version>1.1.3</version>
</dependency>

在application.yml中加入数据源:


spring:
  r2dbc:
    url: r2dbc:mysql://127.0.0.1:3306/study
    username: xxx
    password: xxx

5.Dao的编写

Dao的编写和springmvc中类似,本文中继承了ReactiveCrudRepository类,是Repository的一个实现类,其中实现了简单的crud操作,model和dao的实现:


@Table("user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @Id
    private Long id;
    private String username;
    private String password;
}

public interface UserDao extends ReactiveCrudRepository<User,Long> {
}

6.Controller的编写

controller的编写还是和springmvc类似,这里采用RESTful的方式


@RestController
@AllArgsConstructor
public class UserController {
    private final UserDao userDao;
    @GetMapping("/findAll")
    public Flux<User> findAll(){
        return userDao.findAll();
    }
    @PostMapping("/save")
    public Mono save(@RequestBody User user){
        return this.userDao.save(user);
    }
    @DeleteMapping("/delete/{id}")
    public Mono delete(@PathVariable Long id){
        return this.userDao.deleteById(id);
    }
    @GetMapping("/get/{id}")
    public Mono get(@PathVariable Long id){
        return this.userDao.findById(id);
    }
}

7.响应式编程Handler的编写

在使用上,webflux可以和springmvc类似,不过webflux也有自己的一套响应式编程的写法,先定义handler,类似于controller,不过只有业务处理的代码,其中就用到了reactive模拟的request(ServerRequest )和response(ServerResponse),同样的实现简单的crud功能:


@Component
@AllArgsConstructor
public class UserHandler {
    private final UserDao userDao;
    public Mono<ServerResponse> saveUser(ServerRequest request){
        Mono<User> mono=request.bodyToMono(User.class);
        User user = mono.block();
        return ServerResponse.ok().build(this.userDao.save(user).then());
    }
    public Mono<ServerResponse> deleteById(ServerRequest request){
        Long id=Long.parseLong(request.pathVariable("id"));
        return ServerResponse.ok().build(this.userDao.deleteById(id).then());
    }
    public Mono<ServerResponse> getByid(ServerRequest request){
        Long id=Long.parseLong(request.pathVariable("id"));
        Mono<User> mono = this.userDao.findById(id);
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(mono,User.class);
    }
    public Mono<ServerResponse> findAll(ServerRequest request){
        Flux<User> all = this.userDao.findAll();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(all,User.class);
    }
}

8.响应式编程Route的编写

在handler中我们编写了处理代码,但是怎么通过请求地址访问呢?

学习过vue的老铁们应该知道,vue是通过路由定义地址和页面的对应关系的,vue也是响应式编程的一种体现。webflux中也是通过类似的方式来实现的,在Route中定义规则:


@Configuration
public class UserRoute {
    @Bean
    public RouterFunction<ServerResponse> routeUser(UserHandler userHandler){
        return RouterFunctions
                .route(RequestPredicates.GET("findAll2")
                        .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),userHandler::findAll)
                .andRoute(RequestPredicates.GET("/get2/{id}")
                        .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),userHandler::getByid)
                .andRoute(RequestPredicates.DELETE("/delete2/{id}")
                        .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),userHandler::deleteById)
                .andRoute(RequestPredicates.POST("/save2")
                        .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),userHandler::saveUser);
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

spring webflux自定义netty 参数解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

shell自定义函数及参数调用解析

一、定义函数function fname(){statements;} 或 fname(){statements;}二、调用函数 只需要使用函数名,即可调用某个函数:$ fname ; #执行函数 可以传递参数给函数,并由脚本进行访问:fn
2022-06-04

怎么用Spring的spel获取自定义注解参数值

这篇文章主要介绍了怎么用Spring的spel获取自定义注解参数值的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用Spring的spel获取自定义注解参数值文章都会有所收获,下面我们一起来看看吧。spel获
2023-06-29

关于spring的自定义缓存注解分析

这篇文章主要介绍了关于spring的自定义缓存注解分析,因为所有的key的失效时间都一样,要想实现不同的key不同的失效时间,就得需要自定义缓存注解,需要的朋友可以参考下
2023-05-20

spring自定义校验注解ConstraintValidator的示例分析

这篇文章主要介绍spring自定义校验注解ConstraintValidator的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以
2023-06-20

java怎么自定义注解做参数校验

在Java中,可以使用自定义注解来进行参数校验。以下是一个简单的示例:import java.lang.annotation.ElementType;import java.lang.annotation.Retention;impo
2023-10-26

Spring Security密码解析器PasswordEncoder自定义登录逻辑

这篇文章主要为大家介绍了Spring Security密码解析器PasswordEncoder自定义登录逻辑示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Spring MVC参数自动绑定List的解决方法

最近遇到一个问题,在项目中需要传入一组对象。以前都只遇到过传入一个对象、多个对象或者一组数组的情况。很少遇到传入一组对象的情况。所以遇到这个问题的时候感觉有点棘手。本以为用这样的方法就能解决的。@RequestMapping("save1"
2023-05-30

SpringBoot通过自定义注解实现参数校验

实现参数校验说实话方式还挺多,个人使用过直接在Controller代码里面写、AOP+自定义注解、ConstraintValidator。本文主要和大家讲的是ConstraintValidator实现,感兴趣的可以了解一下
2022-12-23

C/C++宏定义的可变参数详细解析

在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似
2022-11-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录