on the Webflux of spring
Not long ago, spring made a big change, primarily to increase support for responsive programming.
Spring defaults to the support of the reactor project as a responsive programming (reactive programming), which I also use as a basis for discussion.
Reactor Project Address: Https://github.com/reactor/reactor Why should reactor
In general, reactor is also a library for writing asynchronous code, and it is well known that the overhead of IO takes a long time for a synchronization program. So people are constantly advocating the use of asynchronous way to write some code, and Java also provides a way to write asynchronous programs to developers, then why we need reactor. In my short time experience, reactor makes it easier and faster to write asynchronous code, to make a job simpler or more efficient, and I think it's a problem that a library should solve, and obviously reactor did it, after using the reactor, You'll never have to write callback that smelly, long noodle code, and the readability and maintainability of the code is greatly enhanced. Compared to future, reactor provides more full-featured operations, and programming complexity is greatly reduced
Well, we're not here to introduce reactor, more information about reactor, and how it compares to other asynchronous ways of the JVM. Refer to Reactor Documentation: http://projectreactor.io/docs/core/release/ Analogy between Webflux and webmvc of reference Webflux instances
Webmvc |
Webflux |
Controller |
Handler |
Request Mapping |
Router |
* Pom.xml
<?xml version= "1.0" encoding= "UTF-8"?> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http ://www.w3.org/2001/XMLSchema-instance "xsi:schemalocation=" http://maven.apache.org/POM/4.0.0 http:// Maven.apache.org/xsd/maven-4.0.0.xsd "> <modelVersion>4.0.0</modelVersion> <GROUPID>CN.EDU.N Cu</groupid> <artifactId>reactive-demo</artifactId> <version>0.0.1-snapshot</version&
Gt <packaging>jar</packaging> <name>reactive-demo</name> <description>demo Project for
Spring boot</description> <parent> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.M7</version> <relativePath/> <!--lookup parent from repository--> </parent> <properties> &L t;project.build.sourceencoding>utf-8</pRoject.build.sourceencoding> <project.reporting.outputencoding>utf-8</ Project.reporting.outputencoding> <java.version>1.8</java.version> </properties>
;d ependencies> <dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactid>spring-boot-starter-test</a Rtifactid> <scope>test</scope> </dependency> <!--Https://mvnreposito Ry.com/artifact/org.springframework.boot/spring-boot-starter-webflux--> <dependency> <gro Upid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-webflux</artifactid&
Gt </dependency> <dependency&Gt <groupId>org.springframework.boot</groupId> <artifactid>spring-boot-starter-data-redis</a
Rtifactid> </dependency> <!--Https://mvnrepository.com/artifact/redis.clients/jedis--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis< /artifactid> <version>2.9.0</version> </dependency> <!--https://mvnre Pository.com/artifact/org.mindrot/jbcrypt--> <dependency> <groupid>org.mindrot</gro Upid> <artifactId>jbcrypt</artifactId> <version>0.4</version> & lt;/dependency> <!--Https://mvnrepository.com/artifact/com.alibaba/fastjson--> <DEPENDENCY&G
T <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> ≪version>1.2.44</version> </dependency> </dependencies> <build> <p
Lugins> <plugin> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins>
</build> <repositories> <repository> <id>spring-snapshots</id>
<name>spring snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </ repository> <repository> <id>spring-milestones</id> <name>sprin G milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots>
; <enabled>false</enabled> </snapshots> </repository> </repositories> & Lt;pluginrepositories> <pluginRepository> <id>spring-snapshots</id> & Lt;name>spring snapshots</name> <url>https://repo.spring.io/snapshot</url> &L t;snapshots> <enabled>true</enabled> </snapshots> </pluginrepo sitory> <pluginRepository> <id>spring-milestones</id> <NAME>SPR ing milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots&
Gt <enabled>false</enabled> </snapshots> </pluginRepository> </pluginrepos Itories> </project>
Write Handler
First write a Hello World handler practice practicing
Package cn.edu.ncu.reactivedemo.handlers;
@Service public
class HelloWorldHandler {public
mono<serverresponse> HelloWorld (serverrequest request {return
Serverresponse.ok ()
. ContentType (Mediatype.text_plain)
. Body (Bodyinserters.fromobject (" Hello World "));
}
Registering routes
Register a written handler on a route
Package Cn.edu.ncu.reactivedemo;
@Configuration public
class Router {
@Autowired private helloworldhandler HelloWorldHandler;
@Autowired private Userhandler Userhandler;
@Bean public
routerfunction<?> routerfunction () {return
Routerfunctions.route ( Requestpredicates.get ("/hello"), Helloworldhandler::helloworld);
}
Start class
The default is to use Netty as the underlying boot of the reactor
Package Cn.edu.ncu.reactivedemo;
@SpringBootApplication public
class Reactivedemoapplication {public
static void Main (string[] args) {
Springapplication.run (Reactivedemoapplication.class, args);
}
Visit Http://127.0.0.1:8080/hello
Return to Hello World for successful database use
Temporary support for reactive programming database only MongoDB, Redis, Cassandra, couchbase
We use the Redis as a test, do a simple registration login interface on the line
* Configure Redis
Package cn.edu.ncu.reactivedemo.config;
@Configuration public
class Redisconfig {
@Autowired
private redisconnectionfactory factory;
@Bean public
reactiveredistemplate<string, string> reactiveredistemplate (reactiveredisconnectionfactory ConnectionFactory) {return
to new reactiveredistemplate<string, string> (ConnectionFactory, Redisserializationcontext.string ());
}
@Bean Public
reactiveredisconnection Connection (reactiveredisconnectionfactory connectionfactory) {
return connectionfactory.getreactiveconnection ();
}
Public @PreDestroy void Flushdb () {
factory.getconnection (). FLUSHDB ();
}
}
Testing the Redis interface
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::p rintln);
}
Write Userhandler
Package cn.edu.ncu.reactivedemo.handlers;
@Service public class Userhandler {@Autowired private reactiveredisconnection connection; Public mono<serverresponse> Register (serverrequest request) {mono<map> 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 (HASHEDPA
Ssword.getbytes ()));
}). Flatmap (Aboolean-> {map<string, string> result = new hashmap<> ();
Serverresponse serverresponse = null;
if (Aboolean) {result.put ("message", "successful"); Return Serverresponse.ok (). ContentType (mediatype.
Application_json_utf8). Body (Bodyinserters.fromobject);
}else {result.put ("message", "failed");
Return Serverresponse.status (httpstatus.bad_request). ContentType (Mediatype.application_json_utf8)
. Body (Bodyinserters.fromobject (request));
}
}); mono<serverresponse> Login (serverrequest request) {mono<map> BODY = Request.bodytomono (M
Ap.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-> {by
te[] 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<string, string> result = new hashmap<> (); if (Hashedpassword = NULL | |!)
BCRYPT.CHECKPW (password, hashedpassword)) {result.put ("message", "Account or password error"); Return Serverresponse.status (httpstatus.unauthorized). ContentType (Mediatype.application_json_
UTF8). Body (Bodyinserters.fromobject);
}else {result.put ("token", "false token");
Return Serverresponse.ok (). ContentType (Mediatype.application_json_utf8)
. Body (Bodyinserters.fromobject);
}
});
});
}
}
Add Router
Package Cn.edu.ncu.reactivedemo;
@Configuration public
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);
}
Interface is very rough, did not write the model layer, there is no data validation, the test is directly with the HTTP requester test
Reference:
Https://spring.io/blog/2016/11/28/going-reactive-with-spring-data
http://projectreactor.io/docs/core/release/reference/
http://projectreactor.io/docs/core/release/api/
Https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-fn-handler-functions
Demo Address:
Https://github.com/ncuwaln/spring-reactive-demo