The previous article used Webflux to implement a simple Hello World request and output, where we learned the crud operations of Webflux based on the annotation controller.
Learning Source: http://gitbook.cn/gitchat/column/5acda6f6d7966c5ae1086f2b/topic/5acda9d9d7966c5ae1087053
Before we started, we introduced the Lombok package in Pom.xml, as follows:
<!--Https://mvnrepository.com/artifact/org.projectlombok/lombok--
<dependency>
< groupid>org.projectlombok</groupid>
<artifactId>lombok</artifactId>
<version >1.16.20</version>
<scope>provided</scope>
</dependency>
The introduction of Lombok is mainly to avoid writing too many get and set methods, using annotations to automatically generate the get and set methods at compile time. Note that idea needs to be configured with the use of Lombok plug-ins, refer to: https://blog.csdn.net/zhglance/article/details/54931430
1, writing entity classes
Package com.jack.webflux1.entity;
Import Lombok. Data;
/**
* Create by Jack 2018/4/21
* Urban entity class */
@Data public
class
cities {/**
* * City number
* * Private Long ID;
/**
* Province number */
private Long Provinceid;
/**
* City name */
private String cityname;
/**
* Description * * *
private String description;
2. Writing the data access layer
Package Com.jack.webflux1.dao;
Import com.jack.webflux1.entity.City;
Import Org.springframework.stereotype.Repository;
Import java.util.Collection;
Import Java.util.concurrent.ConcurrentHashMap;
Import Java.util.concurrent.ConcurrentMap;
Import Java.util.concurrent.atomic.AtomicLong;
/** * Create by Jack 2018/4/21 * Data access layer, which is responsible for data crud */@Repository public class Cityrepository {//Save data collection as pseudo database
Private Concurrentmap<long, city> repository = new concurrenthashmap<> ();
ID Generator private static final Atomiclong Idgenerator = new Atomiclong (0);
Public Long Save (city) {Long id = idgenerator.incrementandget ();
City.setid (ID);
Repository.put (ID, city);
return ID;
} public collection<city> FindAll () {return repository.values ();
Public City Findcitybyid (Long ID) {return repository.get (ID); } public Long updatecity (city city) {Repository.put (City.getid (), city);
return City.getid ();
} public long deletecity (long id) {repository.remove (ID);
return ID;
}
}
3, Processor class
Package Com.jack.webflux1.handler;
Import Com.jack.webflux1.dao.CityRepository;
Import com.jack.webflux1.entity.City;
Import org.springframework.beans.factory.annotation.Autowired;
Import org.springframework.stereotype.Component;
Import Reactor.core.publisher.Flux;
Import Reactor.core.publisher.Mono;
/** * Create by Jack 2018/4/21 * City Processor * * * * mono and Flux apply to two scenarios, i.e.: Mono: Implements the publisher and returns 0 or 1 elements, that is, a single object.
Flux: Implements a publisher and returns N elements, the list object.
Some people ask, why not return objects directly, such as return city/long/list.
The reason is that direct use of Flux and Mono is a non-blocking notation, equivalent to a callback method. By using a function, you can reduce the callback so that the associated interface is not visible. This is precisely the benefit of Webflux: A collection of non-blocking + async * * @Component public class Cityhandler {/** * Data operations of the DAO layer Bean */private
Final Cityrepository cityrepository; /** * Initialization properties are injected through the constructor cityrepository * @param cityrepository */@Autowired public Cityhandler (Cityrepos
Itory cityrepository) {this.cityrepository = cityrepository; }/** * How to save City data * @param cities * @return */Public Mono<long> Save (city) {return mono.create (Citymonosink-citymonosink.success (Cityrepository.save)); /** * Check the city's handling method by City ID * @param ID * @return */public mono<city> Findcitybyid (Long
ID) {return mono.justorempty (Cityrepository.findcitybyid (id)); /** * Query All CITY Data * @return */public flux<city> findallcity () {return flux.fromiter
Able (Cityrepository.findall ());
}/** * Modify City Data * @param cities * @return */public mono<long> modifycity
Return Mono.create (Citymonosink-citymonosink.success (cityrepository.updatecity));
/** * Delete City data based on City ID * @param ID * @return */public mono<long> deletecity (Long ID) {
Return Mono.create (Citymonosink-citymonosink.success (cityrepository.deletecity (ID)));
}
}
The common methods of mono are:
mono.create (): Use Monosink to create mono.
Mono.justorempty (): Creates Mono from a Optional object or from a null object.
mono.error (): Create a Mono that contains only the error message.
mono.never (): Create a Mono that does not contain any message notifications.
Mono.delay (): After the specified delay time, create a Mono that produces the number 0 as a unique value
If you know that Publisher is 0 or 1, use Mono.
Flux Most noteworthy is the Fromiterable method, fromiterable (iterable<? extends t> it) can publish elements of the iterable type. Of course, Flux also includes basic operations: map, Merge, Concat, FlatMap, take, etc.
4, CONTROLLER
Package Com.jack.webflux1.controller;
Import com.jack.webflux1.entity.City;
Import Com.jack.webflux1.handler.CityHandler;
Import org.springframework.beans.factory.annotation.Autowired;
Import org.springframework.web.bind.annotation.*;
Import Reactor.core.publisher.Flux;
Import Reactor.core.publisher.Mono; /** * Create by Jack 2018/4/21 * Webflux Note-based controller */@RestController @RequestMapping ("/city") public class Citywebfluxco
Ntroller {@Autowired private cityhandler cityhandler; @GetMapping (value = "/{id}") Public mono<city> Findcitybyid (@PathVariable ("id") Long ID) {return CITYHA
Ndler.findcitybyid (ID);
} @GetMapping () public flux<city> findallcity () {return cityhandler.findallcity (); } @PostMapping () public mono<long> savecity (@RequestBody city) {return cityhandler.save
; } @PutMapping () public mono<long> modifycity (@RequestBody City city) {return cityhandleR.modifycity (city); } @DeleteMapping (value = "/{id}") Public mono<long> deletecity (@PathVariable ("id") Long ID) {retur
n cityhandler.deletecity (ID);
}
}
The controller above uses a rest-style interface.
5, run the test
1) Increase
Url:http://localhost:8080/city
Request Method: Post
Data format: JSON
The following figure:
2) search by specified ID
The following figure:
3) Find all data
4) Modify the data
5) Delete Data
The above illustrates the crud based on the rest interface, following a detailed analysis of the logic under the code:
1) New
The new time is the rest of the post way to pass the data, the data is in JSON format, the format is as follows:
{
"id": "", "
Provinceid": 75501,
"CityName": "Guangzhou",
"description": "Guangzhou has a small waist"
}
The new URL processing code is as follows:
@PostMapping () Public
mono<long> savecity (@RequestBody city) {
return cityhandler.save;
}
As can be seen from the above code, using the city object to receive parameters, call Cityhandler's Save method to hold the urban data, after processing success, return to the successful saving of the town ID.
The Cityhandler Save method code is as follows:
/**
* How
to save City data urban
@return
*
/public mono<long> Save ( City city) {
return mono.create (Citymonosink-citymonosink.success (Cityrepository.save));
/**
* How to save City data
* @param cities
* @return *
/
public mono<long> Save Return Mono.create (Citymonosink-citymonosink.success (Cityrepository.save));
Since only one of the returned data is using mono as the return data, create a mono object using the Mono class static Create method, with the following code:
public static <T> mono<t> Create (consumer<monosink<t>> callback) {
return onassembly (new Monocreate (callback));
}
Can be to the Create method to receive a parameter, the parameter is a consumer object, through the callback can be seen, here is using the interface callback, so the Mono.create () method parameters need an implementation class, implement consumer interface, The above code is the way to implement the interface using lambda, let's look at the definition of the consumer interface:
/* Copyright (c), Oracle and/or its affiliates.
All rights reserved. * ORACLE proprietary/confidential.
Use are subject to license terms.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * java.util.function
Import java.util.Objects; /** * Represents an operation, accepts a single input argument and returns no * result.
Unlike most other functional interfaces, {@code Consumer} are expected * to operate via side-effects. * * <p>this is a <a href= "package-summary.html" >functional interface</a> * whose functional method is
{@link #accept (Object)}. * * @param <T> The type of the input to the operation * * @since 1.8 */@FunctionalInterface public interface Co
nsumer<t> {/** * performs this operation on the given argument.
* * @param t the input argument */void accept (T t); /** * Returns A composed {@code Consumer} that performs, in sequence, this * operation followEd by the {@code after} operation. If performing either * operation throws an exception, it's relayed to the caller of the * composed operation.
If performing this operation throws a exception, * the {@code after} operation would not be performed. * * @param after the operation-perform after this operation * @return a composed {@code Consumer} that perfor MS in sequence this * operation followed by the {@code after} operation * @throws nullpointerexception if {@code After} is null */default consumer<t> andthen (consumer<? Super T> after) {Objects.requireno
Nnull (after);
Return (T T), {accept (T); after.accept (t);};
}
}
As can be seen from the above code, there are two methods, one is the default method Andthen, there is an accept method, the parameters of our Mono.create method is to implement the Accept method. Then look at the implementation of the Create method:
public static <T> mono<t> Create (consumer<monosink<t>> callback) {
return onassembly (new Monocreate (callback));
}
Called the Onassembly method inside the method, the parameter is the Monocreate object, and then we look at the Monocreate class, the code is as follows:
Source code recreated from a. class file by IntelliJ idea//(powered by Fernflower Decompiler)//package reactor.
Core.publisher;
Import java.util.Objects;
Import Java.util.concurrent.atomic.AtomicBoolean;
Import Java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
Import Java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
Import Java.util.function.Consumer;
Import Java.util.function.LongConsumer;
Import Reactor.core.CoreSubscriber;
Import reactor.core.Disposable;
Import reactor.core.Scannable.Attr;
Import reactor.core.publisher.FluxCreate.SinkDisposable;
Import reactor.util.annotation.Nullable;
Import Reactor.util.context.Context;
Final class Monocreate<t> extends Mono<t> {final consumer<monosink<t>> callback;
Monocreate (Consumer<monosink<t>> callback) {this.callback = callback; } public void subscribe (CORESUBSCRIBER<? Super t> Actual) {monocreate.defaultmonosink<t> emitter = new MonoCreate.defaultmonosink (Actual);
Actual.onsubscribe (emitter);
try {this.callback.accept (emitter);
} catch (Throwable var4) {emitter.error (Operators.onoperatorerror (VAR4, Actual.currentcontext ())); }} static final class Defaultmonosink<t> extends Atomicboolean implements Monosink<t>, Innerproduce
r<t> {final coresubscriber<? super t> actual;
volatile disposable disposable; Static final Atomicreferencefieldupdater<monocreate.defaultmonosink, disposable> disposable =
Atomicreferencefieldupdater.newupdater (MonoCreate.DefaultMonoSink.class, Disposable.class, "disposable");
volatile int state; Static final atomicintegerfieldupdater<monocreate.defaultmonosink> state =
Atomicintegerfieldupdater.newupdater (MonoCreate.DefaultMonoSink.class, "state");
Volatile Longconsumer Requestconsumer; Static Final Atomicreferencefieldupdater<monocReate. Defaultmonosink, longconsumer> Request_consumer = Atomicreferencefieldupdater.newupdater (
MonoCreate.DefaultMonoSink.class, Longconsumer.class, "Requestconsumer");
T value;
static final int no_request_has_value = 1;
static final int has_request_no_value = 2;
static final int has_request_has_value = 3;
Defaultmonosink (coresubscriber<? Super t> Actual) {this.actual = actual;
} public Context CurrentContext () {return this.actual.currentContext ();
} @Nullable Public Object Scanunsafe (Attr key) {if (Key! = attr.terminated) { Return key = = attr.cancelled?
Operatordisposables.isdisposed (this.disposable): Super.scanunsafe (key);
} else {return this.state = = 3 | | this.state = = 1;
}} public void success () {if (State.getandset (this, 3)! = 3) {try { This.actual.onComplete ();
} finally {This.disposeresource (false);
}}} public void success (@Nullable T value) {if (value = = null) {
This.success ();
} else {int s;
do {s = this.state;
if (s = = 3 | | s = = 1) {operators.onnextdropped (value, This.actual.currentContext ());
Return
} if (s = = 2) {if (State.compareandset (this, S, 3)) {
try {this.actual.onNext (value);
This.actual.onComplete ();
} finally {This.disposeresource (false);
}} return; } this.value = value; } while (!
State.compareandset (this, S, 1)); }} public void error (Throwable e) {if (State.getandset (this, 3)! = 3) {Try
{This.actual.onError (e);
} finally {This.disposeresource (false);
}} else {Operators.onoperatorerror (E, This.actual.currentContext ()); }} public monosink<t> onrequest (Longconsumer consumer) {Objects.requirenonnull (Consu
Mer, "ONrequest"); if (! Request_consumer.compareandset (this, (Object) NULL, CONSUMER)) {throw new IllegalStateException ("A consume
R have already been assigned to consume requests ");
} else {return this; }} public coresubscriber<?
Super t> actual () {return this.actual; } public monosink<t> OnCancel (disposable D) {objects.requirenonnull (d, "onCancel");
sinkdisposable sd = new sinkdisposable ((disposable) null, D);
if (!disposable.compareandset (this, (Object) null, SD)) {disposable c = this.disposable;
if (c instanceof sinkdisposable) {sinkdisposable current = (sinkdisposable) C;
if (Current.oncancel = = null) {current.oncancel = D;
} else {d.dispose ();
}}} return this;
} public monosink<t> Ondispose (disposable D) {objects.requirenonnull (d, "ondispose");
sinkdisposable sd = new Sinkdisposable (d, (disposable) null);
if (!disposable.compareandset (this, (Object) null, SD)) {disposable c = this.disposable; if (C instanceof sinkdisposable) {sinkdisposable current = (sinkdisposable) C;
if (current.disposable = = null) {current.disposable = D;
} else {d.dispose ();
}}} return this; public void request (long N) {if (Operators.validate (n)) {Longconsumer consumer =
This.requestconsumer;
if (consumer! = null) {consumer.accept (n);
} int s;
do {s = this.state;
if (s = = 2 | | s = = 3) {return;
} if (s = = 1) {if (State.compareandset (this, S, 3)) {
try {this.actual.onNext (this.value);This.actual.onComplete ();
} finally {This.disposeresource (false);
}} return;
}} while (!state.compareandset (this, S, 2)); }} public void Cancel () {if (State.getandset (this, 3)! = 3) {This.value =
Null
This.disposeresource (TRUE);
}} void Disposeresource (Boolean iscancel) {disposable d = this.disposable; if (d! = operatordisposables.disposed) {d = (disposable) Disposable.getandset (this, operatordisposables.di
sposed); if (d! = null && d! = operatordisposables.disposed) {if (iscancel && d instanceof Sin
kdisposable) {((sinkdisposable) d). Cancel (); } d.dispOSE ();
}
}
}
}
}
The above code is more, we mainly focus on the following two functions:
Monocreate (Consumer<monosink<t>> callback) {
this.callback = callback;
}
public void subscribe (CORESUBSCRIBER<? Super t> Actual) {
monocreate.defaultmonosink<t> emitter = new Monocreate.defaultmonosink (actual);
Actual.onsubscribe (emitter);
try {
this.callback.accept (emitter);
} catch (Throwable var4) {
Emitter.error (operators.onoperatorerror (VAR4, Actual.currentcontext ()));
}
}
Through the above code can be seen, a constructor, the parameter is consumer, inside the operation to save the consumer object, and then in the Subscribe method inside a code is this.callback.accept (emitter), It is here that the interface callback, callback consumer the Accept method, this method is to call the Mono.create () method when the implementation. Then, after a closer look at the subscribe method, there is a Actual.onsubscribe method, known by the method name, to subscribe to the message. Webflux is based on the reactor model, and is based on event messages and Asynchrony, which also manifests itself as an asynchronous.
The other uses of mono and flux can refer to the above source code process to see for themselves, will not elaborate.
Source Address: Https://github.com/wj903829182/springcloud5/tree/master/webflux1
Welcome Dabigatran: 331227121 Learning Communication