博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring的webflux初探
阅读量:4224 次
发布时间:2019-05-26

本文共 8795 字,大约阅读时间需要 29 分钟。

spring的webflux初探

不久前, spring进行了较大的改动, 主要目的是为了增加对响应式编程的支持.

spring 默认是采用了reactor项目作为响应式编程(reactive programming)的支持, 我也以此作为基础来谈.
reactor项目地址:

为什么要reactor

总的来说, reactor也是一个用于编写异步代码的库, 众所周知, 对于同步程序来说, 有IO耗时长之类的开销. 所以人们不断的推崇使用异步的方式来编写一些代码, 而java也提供了编写异步程序的方法给开发者, 那么我们为什么需要reactor. 就我短时间的使用体验来说, reactor使我们编写异步代码变得更加简单快捷, 让某项工作更加简单或让其更有效率, 我觉得就是一个库应该解决的问题, 显然reactor做到了, 在使用了reactor后, 你就再也不用写callback那种又臭又长的面条代码了, 代码的可读性与可维护性大大加强了. 相比于future, reactor又提供了更多功能齐全的操作, 编程复杂的也大大降低

好了, 我们并不是来介绍reactor的, 更多有关reactor的资料以及它与jvm其他异步方式的对比请参考reactor文档:

webflux实例

  • webflux与webmvc的类比
webmvc webflux
controller handler
request mapping router

* pom.xml

4.0.0
cn.edu.ncu
reactive-demo
0.0.1-SNAPSHOT
jar
reactive-demo
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.0.M7
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-webflux
org.springframework.boot
spring-boot-starter-data-redis
redis.clients
jedis
2.9.0
org.mindrot
jbcrypt
0.4
com.alibaba
fastjson
1.2.44
org.springframework.boot
spring-boot-maven-plugin
spring-snapshots
Spring Snapshots
https://repo.spring.io/snapshot
true
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
spring-snapshots
Spring Snapshots
https://repo.spring.io/snapshot
true
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
  • 编写handler
    先写个hello world handler练练手
package cn.edu.ncu.reactivedemo.handlers;@Servicepublic class HelloWorldHandler {
public Mono
helloWorld(ServerRequest request){ return ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .body(BodyInserters.fromObject("hello world")); }}
  • 注册路由
    将写好的handler注册到路由上
package cn.edu.ncu.reactivedemo;@Configurationpublic class Router {
@Autowired private HelloWorldHandler helloWorldHandler; @Autowired private UserHandler userHandler; @Bean public RouterFunction
routerFunction(){ return RouterFunctions.route(RequestPredicates.GET("/hello"), helloWorldHandler::helloWorld); }}
  • 启动类
    默认采用netty作为reactor的底层启动
package cn.edu.ncu.reactivedemo;@SpringBootApplicationpublic class ReactiveDemoApplication {
public static void main(String[] args) { SpringApplication.run(ReactiveDemoApplication.class, args); }}

访问

返回hello world表示成功

使用数据库

暂时支持reactive编程的数据库只有MongoDB, redis, Cassandra, Couchbase

我们直接采用redis作为测试, 做一个简陋的注册登录的接口就行了
* 配置redis

package cn.edu.ncu.reactivedemo.config;@Configurationpublic class RedisConfig {
@Autowired private RedisConnectionFactory factory; @Bean public ReactiveRedisTemplate
reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory){ return new ReactiveRedisTemplate
(connectionFactory, RedisSerializationContext.string()); } @Bean public ReactiveRedisConnection connection(ReactiveRedisConnectionFactory connectionFactory){ return connectionFactory.getReactiveConnection(); } public @PreDestroy void flushDb(){ factory.getConnection().flushDb(); }}
  • 测试redis接口
package cn.edu.ncu.reactivedemo;@RunWith(SpringRunner.class)@SpringBootTest(classes = ReactiveDemoApplication.class)public class RedisTests {
@Autowired private ReactiveRedisConnection connection; @Test public void testRedis(){ connection .stringCommands().set(ByteBuffer.wrap("h".getBytes()), ByteBuffer.wrap("w".getBytes())) .subscribe(System.out::println); }}
  • 编写userHandler
package cn.edu.ncu.reactivedemo.handlers;@Servicepublic class UserHandler {    @Autowired    private ReactiveRedisConnection connection;    public Mono
register(ServerRequest request) { Mono
body = request.bodyToMono(Map.class); return body.flatMap(map -> { String username = (String) map.get("username"); String password = (String) map.get("password"); String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt()); return connection.stringCommands() .set(ByteBuffer.wrap(username.getBytes()), ByteBuffer.wrap(hashedPassword.getBytes())); }).flatMap(aBoolean -> { Map
result = new HashMap<>(); ServerResponse serverResponse = null; if (aBoolean){ result.put("message", "successful"); return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(result)); }else { result.put("message", "failed"); return ServerResponse.status(HttpStatus.BAD_REQUEST) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(request)); } }); } public Mono
login(ServerRequest request){ Mono
body = request.bodyToMono(Map.class); return body.flatMap(map -> { String username = (String) map.get("username"); String password = (String) map.get("password"); return connection.stringCommands().get(ByteBuffer.wrap(username.getBytes())).flatMap(byteBuffer -> { byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes, 0, bytes.length); String hashedPassword = null; try { hashedPassword = new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } Map
result = new HashMap<>(); if (hashedPassword == null || !BCrypt.checkpw(password, hashedPassword)){ result.put("message", "账号或密码错误"); return ServerResponse.status(HttpStatus.UNAUTHORIZED) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(result)); }else { result.put("token", "假token"); return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(result)); } }); }); }}
  • 添加router
package cn.edu.ncu.reactivedemo;@Configurationpublic class Router {
@Autowired private HelloWorldHandler helloWorldHandler; @Autowired private UserHandler userHandler; @Bean public RouterFunction
routerFunction(){ return RouterFunctions.route(RequestPredicates.GET("/hello"), helloWorldHandler::helloWorld) .andRoute(RequestPredicates.POST("/register"), userHandler::register) .andRoute(RequestPredicates.POST("/login"), userHandler::login); }}

接口很粗糙,没有写model层, 也没有数据验证, 测试也直接用http requester进行测试了

参考:

demo地址:

转载地址:http://sigmi.baihongyu.com/

你可能感兴趣的文章
面试心得(BAT)
查看>>
Windows Server 2012 Web方式修改域用户密码-通过Remote Desktop Web实现
查看>>
华为USG5300 采用IKE安全策略方式建立IPSec隧道
查看>>
Centos7 nginx访问日志文件割接
查看>>
我是一条内存!
查看>>
OIM API Usage
查看>>
OIM实现OIM用户修改、OIM用户Disable流程审批
查看>>
UEFI与MBR区别
查看>>
Ubuntu每次开机后提示:检测到系统程序出现问题的解决方法
查看>>
CC2640 看门狗配置
查看>>
linnux外网不通,提示Destination Host Unreachable解决
查看>>
为strawberry perl安装PadWalker
查看>>
Notepad++的字体设置加Consolas和微软雅黑混合字体
查看>>
gdb 调试常用命令
查看>>
POJ 3125 (Queue)
查看>>
trees in a row
查看>>
在VirtualBox中安装Ubuntu
查看>>
ubuntu mount cifs
查看>>
ubuntu14.04 git server setup
查看>>
SMACK简介
查看>>