欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring-webflux?響應(yīng)式編程的實(shí)例詳解

 更新時間:2022年09月05日 14:59:12   作者:魚找水需要時間  
Spring 提供了兩個并行堆棧,一種是基于帶有 Spring MVC 和 Spring Data 結(jié)構(gòu)的 Servlet API,另一個是完全反應(yīng)式堆棧,它利用了 Spring WebFlux 和 Spring Data 的反應(yīng)式存儲庫,這篇文章主要介紹了Spring-webflux?響應(yīng)式編程,需要的朋友可以參考下

1. 前言

Spring 提供了兩個并行堆棧。一種是基于帶有 Spring MVC 和 Spring Data 結(jié)構(gòu)的 Servlet API。另一個是完全反應(yīng)式堆棧,它利用了 Spring WebFlux 和 Spring Data 的反應(yīng)式存儲庫。在這兩種情況下,Spring Security 都提供了對兩種堆棧的支持。

反應(yīng)式宣言

2. Spring-webflux簡介

Spring WebFlux 是在 5.0 版中添加的。它是完全無阻塞的,支持 Reactive Streams背壓,并且可以在 Netty、Undertow 和 Servlet 3.1+ 容器等服務(wù)器上運(yùn)行。

Spring-webflux官網(wǎng)

3. 什么是“響應(yīng)式”

所謂響應(yīng)式,舉個例子,當(dāng)調(diào)用一個api獲取數(shù)據(jù)時,無需阻塞等待數(shù)據(jù)返回,而是當(dāng)有數(shù)據(jù)返回時會進(jìn)行告知??梢婍憫?yīng)式是非阻塞的,意味著調(diào)用方法后,CPU可以去做別的事情,當(dāng)接收到數(shù)據(jù)響應(yīng)時CPU再回來處理,這種方式提高了系統(tǒng)的吞吐量。

而響應(yīng)式編程,其實(shí)是為這種異步非阻塞的流式編程制定的一套標(biāo)準(zhǔn)。流式編程已不陌生了,Java8提供的stream api就是這種風(fēng)格。這套標(biāo)準(zhǔn)包括對運(yùn)行環(huán)境(JVM、JavaScript)以及網(wǎng)絡(luò)協(xié)議相關(guān)的規(guī)范。

和傳統(tǒng)的阻塞式servlet容器不一樣。響應(yīng)式容器能進(jìn)一步提高資源的利用率,避免線程長時間處于等待狀態(tài),能以較少的線程處理更多的請求,缺點(diǎn)是整個處理鏈路必須是異步的,是基于事件響應(yīng)的,不能阻塞事件線程,不然服務(wù)器性能會急劇下降,當(dāng)然spring webflux并不能完整的替代傳統(tǒng)的阻塞式容器,可根據(jù)需求進(jìn)行選型。

應(yīng)用案例Geteway

所有微服務(wù)的請求都會通過網(wǎng)關(guān),如果采用mvc 對于并發(fā)量有一定的瓶頸。

4. Spring-webflux的響應(yīng)式API

Spring-webflux框架是基于Reactor這個開源項目開發(fā)的。Reactor框架是跟Spring緊密配合的。

里邊提供了兩種API類型,分別是MonoFlux

  • Mono表示0 或 1個元素,
  • Flux表示0 至 N個元素,

5. Spring MVC 還是 WebFlux?

這兩個web框架分別代表著兩種不同類型的編程流派,官方給出了一個圖作為對比如下

建議考慮以下具體點(diǎn):

  • 如果您有一個運(yùn)行良好的 Spring MVC 應(yīng)用程序,則無需更改。命令式編程是編寫、理解和調(diào)試代碼的最簡單方法。您可以選擇最多的庫,因?yàn)?strong>從歷史上看,大多數(shù)都是阻塞的。
  • Spring WebFlux 提供與該領(lǐng)域中其他人相同的執(zhí)行模型優(yōu)勢,并且還提供服務(wù)器選擇(Netty、Tomcat、Jetty、Undertow 和 Servlet 3.1+ 容器)、編程模型(帶注釋的控制器和功能性 Web 端點(diǎn))的選擇,以及反應(yīng)庫(Reactor、RxJava 或其他)的選擇。
  • 如果您對用于 Java 8 lambda 或 Kotlin 的輕量級、功能性 Web 框架感興趣,您可以使用 Spring WebFlux 功能性 Web 端點(diǎn)。對于要求不那么復(fù)雜的小型應(yīng)用程序或微服務(wù)來說,這也是一個不錯的選擇,它們可以從更高的透明度和控制中受益。
  • 在微服務(wù)架構(gòu)中,您可以混合使用帶有 Spring MVC 或 Spring WebFlux 控制器或帶有 Spring WebFlux 功能端點(diǎn)的應(yīng)用程序。在兩個框架中都支持相同的基于注釋的編程模型,可以更輕松地重用知識,同時為正確的工作選擇正確的工具。
  • 評估應(yīng)用程序的一種簡單方法是檢查其依賴關(guān)系。如果您要使用阻塞持久性 API(JPA、JDBC)或網(wǎng)絡(luò) API,那么 Spring MVC 至少是常見架構(gòu)的最佳選擇。Reactor 和 RxJava 在單獨(dú)的線程上執(zhí)行阻塞調(diào)用在技術(shù)上是可行的,但您不會充分利用非阻塞 Web 堆棧。
  • 如果您有一個調(diào)用遠(yuǎn)程服務(wù)的 Spring MVC 應(yīng)用程序,請嘗試響應(yīng)式WebClient. 您可以直接從 Spring MVC 控制器方法返回反應(yīng)類型(Reactor、RxJava或其他)。每個呼叫的延遲或呼叫之間的相互依賴性越大,好處就越顯著。Spring MVC 控制器也可以調(diào)用其他響應(yīng)式組件。
  • 如果您有一個大型團(tuán)隊,請記住向非阻塞、函數(shù)式和聲明式編程轉(zhuǎn)變的陡峭學(xué)習(xí)曲線。在沒有完全開關(guān)的情況下啟動的一種實(shí)用方法是使用 reactive WebClient。除此之外,從小處著手并衡量收益。我們預(yù)計,對于廣泛的應(yīng)用,這種轉(zhuǎn)變是不必要的。如果您不確定要尋找什么好處,請先了解非阻塞 I/O 的工作原理(例如,單線程 Node.js 上的并發(fā)性)及其影響。

其次: webflux兼容大部分springmvc的注解,也可以像mvc那樣創(chuàng)建controller處理請求。

區(qū)別:

  • WebFlux是完全異步非阻塞的,SpringMVC是同步阻塞的。
  • WebFlux采用異步響應(yīng)式編程,SpringMVC采用命令式編程。
  • WebFlux由于完全異步,所有操作數(shù)據(jù)庫的框架,以及數(shù)據(jù)庫也都要求是支持異步的,所以目前不支持Mybatis、不支持Oracle數(shù)據(jù)庫。

6. 并發(fā)模型

盡管webmvcwebflux都支持使用注解來定義一個Controller,但是其實(shí)現(xiàn)方式完全不同。

webmvc是一個Servlet應(yīng)用,實(shí)現(xiàn)是阻塞式IO,其維護(hù)一個線程池來處理每一個用戶請求,也就是當(dāng)Servlet容器啟動時,就會創(chuàng)建比如10個線程出來,因此系統(tǒng)吞吐量的瓶頸在于有限的連接數(shù)和阻塞的請求處理過程。

webflux可以基于netty這樣的NIO網(wǎng)絡(luò)框架,它只需要很少的幾個工作線程(Event loop worker)就能夠處理并響應(yīng)請求。由于無需阻塞等待方法返回,CPU資源就得到了更好的利用。

webflux并不能讓程序運(yùn)行地更快;而是提高了并發(fā)處理請求的能力,即提高系統(tǒng)吞吐量

7. webflux使用

pom依賴:

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

定義對象:

public class Person {
    private Integer id;
    private Integer age;
    private String name;

    public Person(Integer id, Integer age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public Person() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

然后定義PersonController,響應(yīng)式風(fēng)格中不再使用@RequestMapping聲明地址映射,而是通過RouterFunctions.route().GET()方法:

@Configuration
public class PersonRouter {
    @Resource
    private PersonHandler personHandler;
    @Bean
    public RouterFunction<ServerResponse> personRoutes() {
        return RouterFunctions.route()
                .GET("/person/{id}", RequestPredicates.accept(MediaType.APPLICATION_JSON), personHandler::getPerson)
                .GET("/person", RequestPredicates.accept(MediaType.APPLICATION_JSON), personHandler::listPeople)
                .POST("/person", personHandler::createPerson)
                .build();
    }
}

PersonHandler中處理對應(yīng)的HTTP請求,等同于MVC架構(gòu)中的Service層

@Component
public class PersonHandler {

    @Resource
    private IPersonDao personDao;

    public Mono<ServerResponse> listPeople(ServerRequest request) {
        Flux<Person> people = personDao.getList();
        return ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .body(people, Person.class);
    }

    public Mono<ServerResponse> createPerson(ServerRequest request) {
        return request.bodyToMono(Person.class)
                .flatMap(i -> personDao.savePerson(i))
                .flatMap(p -> ServerResponse.ok().bodyValue(p));
    }

    public Mono<ServerResponse> getPerson(ServerRequest request) {
        int personId = Integer.parseInt(request.pathVariable("id"));
        return personDao.getPerson(personId)
                .flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(person))
                .switchIfEmpty(ServerResponse.notFound().build());
    }
}

IPersonDao

public interface IPersonDao {

    /**
     * 獲取所有person
     * @author: yh
     * @date: 2022/9/4
     * @return Flux<Person>
     */
    Flux<Person> getList();

    /**
     * 保存對象
     * @param person person
     * @author: yh
     * @date: 2022/9/4
     * @return Mono<Void>
     */
    Mono<Void> savePerson(Person person);

    /**
     * 根據(jù)id查詢
     * @param id id
     * @author: yh
     * @date: 2022/9/4
     * @return Mono<Person>
     */
    Mono<Person> getPerson(Integer id);
}

PersonDao

@Component
public class PersonDao implements IPersonDao {

    private final List<Person> personList = new ArrayList<>();

    public PersonDao() {
        this.personList.add(new Person(1, 17, "張三"));
        this.personList.add(new Person(2, 18, "李四"));
    }

    @Override
    public Flux<Person> getList() {
        return Flux.fromIterable(personList);
    }

    @Override
    public Mono<Void> savePerson(Person person) {
        personList.add(person);
        System.out.println("personList.size = " + personList);
        return Mono.empty();
    }

    @Override
    public Mono<Person> getPerson(Integer id) {
        return Mono.justOrEmpty(personList.stream().filter(p -> p.getId().equals(id)).findFirst());
    }
}
@SpringBootApplication
@EnableWebFlux
public class SpringWebfluxSessionApplication implements WebFluxConfigurer {
    public static void main(String[] args) {
        SpringApplication.run(SpringWebfluxSessionApplication.class, args);
    }
}

8. 測試

通過啟動日志可以證實(shí)Spring-webflux是默認(rèn)使用Netty提供HTTP服務(wù)

GET請求:http://127.0.0.1:8080/person

POST請求:http://127.0.0.1:8080/person

boyd:

{
    "id": 9,
    "age": 17,
    "name": "張三"
}

控制臺輸出:

GET請求:http://127.0.0.1:8080/person/9

完整代碼已上傳 Gitee Spring整合常用組件

到此這篇關(guān)于Spring-webflux 響應(yīng)式編程的文章就介紹到這了,更多相關(guān)Spring webflux 響應(yīng)式編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis的動態(tài)Sql組合模式詳情

    Mybatis的動態(tài)Sql組合模式詳情

    這篇文章主要介紹了Mybatis的動態(tài)Sql組合模式詳情,這篇文章從組合模式的角度分析了Mybatis動態(tài)sql的部分,SqlNode是組合模式的Component接口,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-08-08
  • Java AtomicInteger類使用方法實(shí)例講解

    Java AtomicInteger類使用方法實(shí)例講解

    這篇文章主要介紹了Java AtomicInteger類使用方法實(shí)例講解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • SpringBoot使用H2嵌入式數(shù)據(jù)庫的實(shí)例代碼

    SpringBoot使用H2嵌入式數(shù)據(jù)庫的實(shí)例代碼

    本文通過實(shí)例代碼給大家介紹了SpringBoot使用H2嵌入式數(shù)據(jù)庫的相關(guān)知識,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-10-10
  • spring中的懶加載詳細(xì)解讀

    spring中的懶加載詳細(xì)解讀

    這篇文章主要介紹了spring中的懶加載詳細(xì)解讀,如果某個Bean再程序運(yùn)行周期中都可能不會被適用,那么可以設(shè)定該Bean為懶加載,優(yōu)勢是盡量節(jié)省了服務(wù)器的資源,缺點(diǎn)是可能會導(dǎo)致某個相應(yīng)的時間增加,需要的朋友可以參考下
    2023-10-10
  • 詳解Java中接口的定義與實(shí)例代碼

    詳解Java中接口的定義與實(shí)例代碼

    這篇文章主要介紹了詳解Java中接口的定義與實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Java中的==和equals()區(qū)別小結(jié)

    Java中的==和equals()區(qū)別小結(jié)

    在Java編程中,理解==操作符和equals()方法的區(qū)別是至關(guān)重要的,本文主要介紹了Java中的==和equals()區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • spring?kafka?@KafkaListener詳解與使用過程

    spring?kafka?@KafkaListener詳解與使用過程

    這篇文章主要介紹了spring-kafka?@KafkaListener詳解與使用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • Mybatis Criteria使用and和or進(jìn)行聯(lián)合條件查詢的操作方法

    Mybatis Criteria使用and和or進(jìn)行聯(lián)合條件查詢的操作方法

    這篇文章主要介紹了Mybatis Criteria的and和or進(jìn)行聯(lián)合條件查詢的方法,本文通過例子給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • 淺談spring使用策略模式實(shí)現(xiàn)多種場景登錄方式

    淺談spring使用策略模式實(shí)現(xiàn)多種場景登錄方式

    本文主要介紹了spring使用策略模式實(shí)現(xiàn)多種場景登錄方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Java實(shí)現(xiàn)簡單的貪吃蛇游戲

    Java實(shí)現(xiàn)簡單的貪吃蛇游戲

    這篇文章主要介紹了Java實(shí)現(xiàn)簡單的貪吃蛇游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評論