1. 程式人生 > 遊戲攻略 >《三角戰略》一週目普通難度英雄強度淺析

《三角戰略》一週目普通難度英雄強度淺析

目錄

1、Spring基礎

1.1簡介

  1. 由一個叫Rod Johnson的程式設計師在 2002 年最早提出(interface 21框架)並隨後建立,是為了解決企業級程式設計開發中的複雜性,實現敏捷開發的應用型框架 。
  2. Spring理念:使現有技術更加容易使用,本身是一個大雜燴,整合現有框架。
  3. 官網:https://spring.io/projects/spring-framework#overview
  4. 下載地址:
    https://repo.spring.io/ui/native/release/org/springframework/spring/

1.2 核心部分

  • IOC:控制反轉,把建立物件過程交給 Spring 進行管理 。
  • Aop:面向切面,不修改原始碼進行功能增強。

1.3優點

  1. Spring是一個開源免費框架(容器)。
  2. Spring是一個輕量級的,非入侵的框架。
  3. 控制反轉(IOC),面向切面程式設計(AOP)
  4. 支援事物的處理,對框架整合的支援

總結:Spring是一個輕量級的控制反轉(IOC)和麵向切面程式設計(AOP)的框架!

1.4拓展

  • Spring Boot

    • 一個快速開發的腳手架
    • 基於SpringBoot可以快速地開發單個微服務
    • 約定大於配置
  • Spring Cloud

    • SPringCloud是基於SpringBoot實現地

    很多公司都在使用SpringBoot進行快速開發,學習SpringBoot的前提是完全掌握Spring以及SpringMVC!

2、IOC容器

2.1 什麼是IOC

  1. 控制反轉,把物件建立和物件之間的呼叫過程交給Spring進行管理。

  2. 使用IOC的目的:為了降低耦合。

  3. IOC的底層原理:xml解析、工廠模式、反射。

  1. IOC 思想基於 IOC 容器完成,IOC 容器底層就是物件工廠

  2. Spring 提供 IOC 容器實現兩種方式:(兩個介面)

    1. BeanFactory:IOC 容器基本實現,是 Spring 內部使用 介面,不提供開發人員進行使用 。載入配置檔案時候不會建立物件,在獲取物件(使用)才去建立物件。
    2. ApplicationContext:BeanFactory 介面的子介面,提供更多更強大的功能,一般由開發人 員進行使用。載入配置檔案時候就會把在配置檔案物件進行建立。
      1. ApplicationContext 介面有實現類有FileSystemXmlApplicationContextClassPathXmlApplicationContext

2.2 IOC 操作(Bean管理)

  1. 什麼是 Bean 管理
    1. Spring 建立物件
    2. Spirng 注入屬性
  2. Bean 管理操作有兩種方式
    1. 基於 xml 配置檔案方式實現
    2. 基於註解方式實現

2.3 Bean 管理——基於 xml 方式

xml配置

alias:用於設定別名

<!--別名的設定,不常用,可以用name代替-->
<alias name="user" alias="uu"/>

import:用於將多個配置檔案匯入合併為一個,多用於團隊開發,applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="beans.xml"/>
    <import resource="beans2.xml"/>
</beans>

建立物件 使用bean標籤

<bean id="helloSpring" class="com.th.pojo.Hello" name="u1 u2,u3;u4">
    <property name="str" value="HelloSpring"/>
</bean>

在 spring 配置檔案中,使用 bean 標籤,並對應屬性,實現物件建立。

在 bean 標籤有很多屬性,介紹常用的屬性 :

  • id : bean的唯一標識 。
  • class :類全路徑(包類路徑) 。
  • name: 早期版本使用,可以用於別名設定,可以取多個別名,用逗號或者分號分開即可。
  • scope:prototype、request、session、singleton

建立物件時候,預設使用無參構造方法完成物件建立。所以存在有參構造時最好把無參構造顯示的寫出來

注入屬性

DI:依賴注入,就是注入屬性。

方式:

  • 使用setter方法
  • 使用使用有引數構造進行注入。

Spring可以根據這兩種方式分別使用propertyconstructor-arg標籤進行配置,從而注入屬性。

  1. property注入

    <bean id="helloSpring" class="com.th.pojo.Hello">
        <property name="str" value="HelloSpring"/>
    </bean>
    

    name: 類裡面屬性名稱

    value:向屬性注入的值

    ref:標識引用Spring容器中已經建立好的的物件

    各種資料型別的注入

    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-properties-detailed

    <bean id="student" class="com.th.pojo.Student">
        <!--第一種:普通值注入,用value-->
        <property name="name" value="ThreePure"/>
        
        <!--第二種:Bean注入,用ref-->
        <property name="address" ref="address"/>
    
        <!--第三種:陣列-->
        <property name="books">
            <array>
                <value>紅樓夢</value>
                <value>水滸傳</value>
                <value>西遊記</value>
                <value>三國演義</value>
            </array>
        </property>
    
        <!--第四種:List-->
        <property name="hobbys">
            <list>
                <value>籃球</value>
                <value>書法</value>
                <value>跑步</value>
            </list>
        </property>
    
        <!--第五種:Map-->
        <property name="card">
            <map>
                <entry key="身份證" value="13512626346"/>
                <entry key="銀行卡" value="13512624327236346"/>
            </map>
        </property>
    
        <!--第六種:Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>
    
        <!--第七種:空指標-->
        <property name="wife">
            <null/>
        </property>
    
        <!--第八種:Properties-->
        <property name="info">
            <props>
                <prop key="學號">13891</prop>
                <prop key="性別">男</prop>
                <prop key="年齡">21</prop>
            </props>
        </property>
    </bean>
    

    引入外部屬性檔案 以druid連線資料庫為例

    1. 建立外部檔案,properties 格式檔案,寫資料庫資訊

      prop.driverClass=com.mysql.jdbc.Driver
      prop.url=jdbc:mysql://localhost:3306/mybatis
      prop.userName=root
      prop.password=mysqlpw
      
    2. 把外部 properties 屬性檔案引入到 spring 配置檔案中

      <!--引入外部屬性檔案-->
      <context:property-placeholder location="druid.properties"/>
      

      注意:使用這個標籤時必須在配置檔案中匯入context約束。

    3. 獲取外部檔案的值 (使用 ${} 獲取properties的值)

      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
          <property name="driverClassName" value="${prop.driverClass}"/>
          <property name="url" value="${prop.url}"/>
          <property name="username" value="${prop.userName}"/>
          <property name="password" value="${prop.password}"/>
      </bean>
      
    4. 獲取使用DruidDataSource物件

      public void testOne(){
          ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);
          //jdbc:mysql://localhost:3306/mybatis
          System.out.println(dataSource.getUrl());
      }
      

    p 名稱空間注入(瞭解):如果對於一個屬性很多的實體類,那麼property使用過於繁瑣,p名稱空間是一種簡化的方法。

    第一步:新增p名稱空間到配置檔案xmlns:p="http://www.springframework.org/schema/p"

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    </beans>
    

    第二步:進行屬性注入,在 bean 標籤裡面進行操作

    <bean id="user1" class="com.th.pojo.User" p:age="20" p:name="TH"/>
    

    注意:p名稱空間依賴於getter和setter方法注入,所以需要設定getter和setter方法。

  2. constructor-arg注入

    <!--方式一:使用下標的方式-->
    <bean id="user" class="com.th.pojo.User">
        <constructor-arg index="0" value="狂神"/>
    </bean>
    
    <!--方式二:通過引數型別-->
    <bean id="user" class="com.th.pojo.User">
        <constructor-arg type="java.lang.String" value="kunagshen"/>
    </bean>
    
    <!--方式三:通過屬性名-->
        <!--name:可以設定別名,可以同時設定多個別名,空格、逗號,分號分隔-->
    <bean id="user" class="com.th.pojo.User" name="u1 u2,u3;u4">
        <constructor-arg name="name" value="KS"/>
    </bean>
    

    name: 類裡面屬性名稱。

    value:向屬性注入的值。

    type: 類屬性的型別。

    index:類屬性的下標(0表示第一個屬性)。

    ref:標識引用Spring容器中已經建立好的的物件。

    • 通過引數型別注入屬性只能對於一些簡單的不含相同屬性實體類,侷限性較大。
    • 最推薦通過屬性名進行屬性注入。

    c 名稱空間注入(瞭解)

    第一步:新增c名稱空間到配置檔案xmlns:c="http://www.springframework.org/schema/c""

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:c="http://www.springframework.org/schema/c"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    </beans>
    

    第二步:進行屬性注入,在 bean 標籤裡面進行操作

    <bean id="user2" class="com.th.pojo.User" c:age="18" c:name="三淳" scope="prototype"/>
    

    注意:c名稱空間依賴於構造器注入,所以需要設定有參構造方法。

  3. Bean的作用域

    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes

    singleton:單例模式,Spring預設使用單例模式。載入 spring 配置檔案時候就會建立單例項物件

    <bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
    

    prototype:原型模式,每次從容器中get的時候,都會產生新的物件。

    <bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
    

    requestsessionapplicationwebsocket在Web開發種使用。 在呼叫 getBean 方法時候建立多例項物件。

  4. Bean的自動裝配

    Spring種有3種裝配方式:

    1. 在xml中顯示配置
    2. 在java中顯示配置
    3. 隱式的自動裝配bean : Spring在上下文種自動尋找,並自動給bean裝配屬性

    byName自動裝配。 會自動在容器上下文中查詢和自己物件set方法後面的值對應的bean的id!

    <!--這個id必須小寫,否則報異常-->
    <bean id="cat" class="com.th.pojo.Cat"/>
    <bean id="dog" class="com.th.pojo.Dog"/>
    
    <bean id="man" class="com.th.pojo.People" autowire="byName">
    	<property name="name" value="ThreePure1"/>
        <!--其他物件屬性在配置後可以自動裝配-->
    </bean>
    

    注意: 使用byName需要保證所有的bean的id唯一,並且這個bean需要跟自動注入的類屬性名稱一樣!

    byType自動裝配。 會自動在容器上下文中查詢,和自己物件屬性型別相同的bean。

    <!--因為是按照型別裝配,所以id可以省略-->
    <bean class="com.th.pojo.Cat"/>
    <bean id="dog" class="com.th.pojo.Dog"/>
    
    <bean id="man" class="com.th.pojo.People" autowire="byType">
        <property name="name" value="ThreePure2"/>
    </bean>
    

    注意: 使用byType需要保證所有的bean的class唯一,並且這個bean需要跟自動注入的屬性的型別一致!

    使用註解實現自動裝配 (見下一節)

2.4 Bean 管理——基於註解方式

  1. 使用註解須知

    在Spring4之後,使用註解開發必須要匯入AOP包。匯入spring-webmvc後包含了AOP的包。

    1. 匯入約束

      xmlns:context="http://www.springframework.org/schema/context"

      http://www.springframework.org/schema/context

      https://www.springframework.org/schema/context/spring-context.xsd

    2. 配置註解的支援 <context:annotation-config/>

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
              https://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:annotation-config/>
          <!--掃描指定的包,這個包下所有使用的註解就會生效-->
          <context:component-scan base-package="com.th"/>
      </beans>
      
    3. 開啟元件掃描,配置掃描指定的包,使註解完全生效 ,多個包使用逗號隔開。

      <context:component-scan base-package="com.th"/>.

      當然也可以對掃描進行更加細緻的配置:

      use-default-filters="false" :不使用預設的過濾器,可以自定義配置。

      context:include-filter標籤: 設定掃描哪些內容,可以定義型別以及表示式。

      <!--掃描com.th包下的Controller註解-->
      <context:component-scan base-package="com.th" use-default-filters="false">
          <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
      

      context:exclude-filter標籤: 設定哪些內容不進行掃描,可以定義型別以及表示式。

      <!--掃描com.th包下的除Controller以外的註解-->
      <context:component-scan base-package="com.th">
          <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
      
    4. 使用註解

  2. 建立物件

    @Component: 元件、放於類上,表示建立這個類的物件,相當於<bean id="user" class="com.th.pojo.User" />

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Component
    public class User {
        //相當於:<property name="name" value="TH"/>   也可以放在setter方法前
        //@Value("TH")
        public String name;
    
        @Value("sanchun")
        public void setName(String name) {
            this.name = name;
        }
    }
    

    在註解裡面@componentvalue 屬性值可以省略不寫,預設值是類名稱,首字母小寫。比如User類的user

  3. 注入屬性

    public class User {
        //相當於:<property name="name" value="TH"/>   也可以放在setter方法前
        @Value("TH")
        public String name;
    }
    
    public String name;
    
    @Value("sanchun")
    public void setName(String name) {
        this.name = name;
    }
    

    對於複雜的資料注入到屬性中,建議使用xml方式進行注入。

  4. Component的衍生的註解

    • dao層 @Repository
    • service層 @Service
    • controller @Controller

    這四個註解的功能一致,都是代表將某個類註冊到Spring中,裝配bean,只是後三者在Web開發中按照MVC架構分層特定使用。

  5. 註解實現自動裝配 (@Autowired、@Qualifier、Resource) 一般時物件注入或者引用注入,而注入普通型別屬性使用@Value

    在匯入註解約束以及對註解支援的情況下使用@Autowired

    作用範圍:屬性前、setter方法前

    Autowired 我們可以不用編寫Setter方法了,前提是你這個自動裝配的屬性在IOC(Spring)容器中存在,且符合byType型別。

    public @interface Autowired {
        boolean required() default true;
    }
    

    根絕以上原始碼,可以知道@Autowired註解可以傳遞引數,required用於設定裝配屬性是否允許為空。如果定義了@Autowiredrequired屬性為false,說明這個屬性可以為空,否則不能為空。

    @Nullable :有相似作用,欄位標記了這個註解,說明這個欄位可以為null。

    @Qualifier:當一個Spring容器中含有多個相同類的物件時,自動裝配的環境較為複雜,可以結合使用@Qualifier註解來實現選取具體的某一個物件。其value值為確定的其中beanid值。典型案例就是一個介面含有多個實現類。

    Resource:java原生對自動裝配的支援。預設使用byName實現,其次才是對byType的支援,若二則都不存在則會報錯。Resourcename屬性可以實現與@Qualifier類似的功能。

    <bean id="cat11" class="com.th.pojo.Cat"/>
    <!--    <bean id="cat22" class="com.th.pojo.Cat"/>-->
    <bean id="dog11" class="com.th.pojo.Dog"/>
    <bean id="dog22" class="com.th.pojo.Dog"/>
    
    <bean id="man" class="com.th.pojo.People">
    	<property name="name" value="ThreePure2"/>
    </bean>
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.lang.Nullable;
    import javax.annotation.Resource;
    
    public class People {
    
        @Nullable
        private String name;
        @Resource(name = "cat11")
        private Cat cat;
        @Autowired
        @Qualifier(value = "dog22")
        private Dog dog;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Cat getCat() {
            return cat;
        }
    
    
        public Dog getDog() {
            return dog;
        }
    }
    
  6. 作用域 ( @Scope

    使用@Scope註解實現對作用域範圍的控制,括號內直接輸入具體的作用域並用""包起來。

    @Component
    @Scope("prototype")
    public class User {
    	……
    }    
    

2.5 使用JavaConfig實現配置

以上即便是使用註解方式也並沒有完全脫離xml檔案,而JavaConfig就是完全使用註解來實現。

  • 實體類中同樣可以通過@Component註解來進行建立物件,通過@Value實現屬性注入。

  • 需要一個配置類來替代applicationContext.xml的功能

    • @Configuration註解標識的類表示一個配置類
    • @Configuration註解標識的類也會被Spring容器託管,註冊到容器中,因為他本來就是一個@Component
  • 需要配置類中的方法代替applicationContext.xmlbean標籤進行bean的註冊。

    • 這個方法的名字,就相當於bean標籤的id屬性
    • 這個方法的返間值,就相當bean標籤中的class屬性,也就是要注入到容器的物件!
  • 通過Annotationconfig 上下文來獲收容器,通過配置類的class物件載入!AnnotationConfigApplicationContext

    ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
    
  • 其他註解

    • @ComponentScan : 用於自動掃描包
    • @Import : 用於匯入其他配置類

實體類

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    @Value("THREEPURE")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

配置類

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;

//這個也會被Spring容器託管,註冊到容器中,因為他本來就是一個@Component
//@Configuration代表這是一個配置類,相當於beans.xml/ applicationContext.xml
@Configuration
@ComponentScan("com.th.pojo")
@Import(UserConfig2.class)
public class UserConfig {

    //註冊一個bean,就相當於我們之前寫的一個bean標籤
    //這個方法的名字,就相當於bean標籤的id屬性
    // 這個方法的返間值,就相當bean標籤中的class屬性
    @Bean
    public User getUser(){
        //就是返回要注入到bean的物件!
        return new User();
    }
}

測試類

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置類方式去做,我們就只能通過Annotationconfig 上下文來獲收容器,通過配置類的class物件載入!
        ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser);
    }
}

2.6 Bean的生命週期

  1. 通過構造器建立 bean 例項(無引數構造)
  2. 為 bean 的屬性設定值和對其他 bean 引用(呼叫 set 方法)
  3. 呼叫 bean 的初始化的方法(需要進行配置初始化的方法)
  4. bean 可以使用了(物件獲取到了)
  5. 當容器關閉時候,呼叫 bean 的銷燬的方法(需要進行配置銷燬的方法)

測試

public class Orders {
    private String name;

    /**無參構造方法*/
    public Orders() {
        System.out.println("第一步 執行無引數構造建立 bean 例項");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("第二步 呼叫 set 方法設定屬性值");
    }

    /**建立執行的初始化方法*/
    public void initMethod(){
        System.out.println("第三步,執行初始化方法");
    }

    /**建立執行的銷燬的方法*/
    public void destroyMethod(){
        System.out.println("第五步 執行銷燬的方法");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="orders" class="com.th.pojo.Orders" init-method="initMethod" destroy-method="destroyMethod" >
        <property name="name" value="Phone"></property>
    </bean>

</beans>
import com.th.pojo.Orders;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestOne {
    @Test
    public void test(){
        //ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println(orders);
        System.out.println("第四步 獲取建立 bean 例項物件");
        System.out.println(orders);
        //手動讓 bean 例項銷燬 (ClassPathXmlApplicationContext物件才能實現close操作)
        context.close();
    }
}

結果:

第一步 執行無引數構造建立 bean 例項
第二步 呼叫 set 方法設定屬性值
第三步,執行初始化方法
com.th.pojo.Orders@1060b431
第四步 獲取建立 bean 例項物件
第五步 執行銷燬的方法

注意:需要使用ApplicationContext的實現類來實現手動銷燬操作。

另外,Bean的完整生命週期還有包括兩項在初始化之前的狀態。實現這兩個狀態需要為Spring配置後置處理器。實現後置處理器需要建立一個類並實現BeanPostProcessor介面並重寫postProcessBeforeInitializationpostProcessAfterInitialization兩個方法,這兩個方法對應這額外的兩種狀態。

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化方法之前執行的方法");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化方法之後執行的方法");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

有了後置處理器後需要將其配置到Spring中。在Spring中,只需要將這個後置處理器像配置bean一樣在applicationContext.xml中配置那麼這個Spring容器中的全部bean都會加上後置處理器。

<bean id="myBeabPostProcessor" class="com.th.pojo.MyBeanPostProcessor" ></bean>

輸出結果為:

第一步 執行無引數構造建立 bean 例項
第二步 呼叫 set 方法設定屬性值
在初始化方法之前執行的方法
第三步,執行初始化方法
在初始化方法之後執行的方法
com.th.pojo.Orders@e720b71
第四步 獲取建立 bean 例項物件
第五步 執行銷燬的方法

3、AOP

3.1 什麼是AOP

  • 面向切面程式設計(方面),利用 AOP 可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
  • 通俗地講就是不修改原有程式碼實現新功能的新增
  • 案例:原有的資料增刪改查前後新增日誌功能。

Spring 框架一般都是基於 AspectJ 實現 AOP 操作。AspectJ 不是 Spring 組成部分,獨立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,AOP 操作可以基於 xml 配置檔案實現 或者基於註解方式實現(使用)。

3.2 AOP原理

AOP 底層使用動態代理,動態代理有兩種,分別為JDK動態代理CGLIB動態代理

JDK動態代理 面向有介面的情況

  1. 原理:建立介面實現類代理物件,增強類的方法。

    使用:

    • java.lang.Object
      • java.lang.reflect.Proxy
        • newProxyInstance(ClassLoader loader, 類<?>[] interfaces, InvocationHandler h)
          • 第一引數,類載入器 。
          • 第二引數,增強方法所在的類,這個類實現的介面,支援多個介面 。
          • 第三引數,實現這個介面 InvocationHandler,建立代理物件,寫增強的部分。
  2. 例項

    使用動態代理前:

    public interface UserDao {
        public int add(int a, int b);
        public String update(String id);
    }
    
    public class UserDaoImpl implements UserDao{
        @Override
        public int add(int a, int b) {
            System.out.println("add() executed");
            return a+b;
        }
    
        @Override
        public String update(String id) {
            System.out.println("update()executed");
            return id;
        }
    }
    

    使用動態代理增加功能:

    1. 第一步:建立代理物件類、 實現InvocationHandler介面。

      class UserDaoProxy implements InvocationHandler {
      
          private Object obj;
      
          /**把建立的是誰的代理物件,就把誰傳遞過來,通過有參構造傳遞。比如這裡產生的是UserdaoImpl的代理物件。*/
          /**為例讓這個代理類使用更加廣泛,直接傳遞Object物件,*/
          public UserDaoProxy(Object obj) {
              this.obj = obj;
          }
      
          /**增強的邏輯程式碼*/
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              // 被增強方法之前
              System.out.println("It was executed before the "+method.getName()+",and the args :"+ Arrays.toString(args));
      
              // 被增強方法執行
              Object res = method.invoke(obj, args);
      
              // 被增強方法之後
              System.out.println("It was executed before ... :"+obj.toString());
      
              return res;
          }
      }
      
      1. 在建立代理物件程式碼時,需要代理哪個物件就傳遞哪個物件。通過代理類的有參構造實現代理物件的傳遞。

      2. 通過重寫invoke方法,在其內部新增擴充套件功能。其中引數:

        1. proxy : 呼叫該方法的代理例項,
        2. method:執行的方法(需要增強功能的方法)
        3. orgs: 為這個方法傳遞的引數。
      3. 通過method.invoke(obj, args)方法執行原來UserDao中的方法,method就是傳遞過來的方法。可以在其之前或者之後對功能進行擴充套件,

    2. 第二步:使用Proxy類建立介面代理物件(獲取代理例項執行方法)

      public class JDKProxy {
          public static void main(String[] args) {
              
              Class[] interfaces = {UserDao.class};
              UserDaoImpl userDao = new UserDaoImpl();
              
              //建立介面實現類的介面物件
              UserDao proxyDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
              //使用代理物件執行方法
              int addResult = proxyDao.add(1, 2);
              System.out.println("add method result:"+addResult);
          }
      }
      

      newProxyInstance()方法的三個引數:

      1. loader:類載入器定義代理類
      2. interfaces:被代理類實現的介面列表
      3. h:排程方法呼叫的呼叫處理函式(代理物件)

CGLIB動態代理 面向沒有介面的情況

  1. 原理:建立子類的代理物件,增強類的方法。

3.3 術語

  1. 連線點:類中可以增強功能的方法。
  2. 切入點:最終實際進行了功能增強的方法。
  3. 通知(增強):增加的那部分功能。含有多種型別:
    1. 前置通知
    2. 後置通知
    3. 環繞通知
    4. 異常通知
    5. 最終通知
  4. 切面:是一個動作,把一個通知應用到切入點的過程。

3.4 切入點表示式

  • 作用:知道對哪個類裡面的哪個方法進行增強
  • 語法結構: execution([許可權修飾符] [返回型別] [類全路徑].[方法名稱]([引數列表]))
  • 許可權修飾符可以用*代表全部許可權,返回型別一般省略。

舉例:

  1. 對 com.atguigu.dao.BookDao 類裡面的 add 方法進行增強 。

    execution(* com.atguigu.dao.BookDao.add(..))

  2. 對 com.atguigu.dao.BookDao 類裡面的所有的方法進行增強

    execution(* com.atguigu.dao.BookDao.* (..))

  3. 對 com.atguigu.dao 包裡面所有類,類裡面所有方法進行增強

    execution(* com.atguigu.dao.*.* (..))

3.5 AOP 操作

AspectJ 註解方式實現AOP

  1. 建立類(被增強功能的類),在類裡面定義方法。

    public class User {
        public void add(){
            System.out.println("add method...");
        }
    }
    
  2. 建立增強類(編寫增強邏輯)。

    public class UserProxy {
        public void before(){
            System.out.println("before...");
        }
    }
    
  3. 進行通知的配置。

    1. 在 spring 配置檔案中,開啟註解掃描。

      <!--開啟註解掃描-->
      <context:component-scan base-package="com.th" />
      
    2. 使用註解建立 User 和 UserProxy 物件。@Component

      @Component
      public class User {
      }
      
      @Component
      public class UserProxy {
      }
      
    3. 在增強類上面添加註解 @Aspect。 @Aspect 用於生成代理物件

      @Component
      @Aspect
      public class UserProxy {
      }
      
    4. 在 spring 配置檔案中開啟生成代理物件。

      proxy-target-class預設狀態為falseproxy-target-class="false"表示使用JDK動態代理proxy-target-class="true"表示使用cglib動態代理,

      <!--- 開啟 Aspect 生成代理物件-->
      <aop:aspectj-autoproxy/>
      
  4. 配置不同型別的通知。

    在增強類裡的通知方法上面新增通知型別註解,使用切入點表示式配置。

    @Component
    @Aspect
    public class UserProxy {
        /**前置通知 @Before 註解表示作為前置通知*/
        @Before("execution(* com.th.atguigu.aopanno.User.add(..))")
        public void before(){
            System.out.println("before...");
        }
    
        /**後置通知(返回通知)*/
        @AfterReturning(value = "execution(* com.th.atguigu.aopanno.User.add(..))")
        public void afterReturning() {
            System.out.println("afterReturning.........");
        }
    
        /**最終通知*/
        @After(value = "execution(* com.th.atguigu.aopanno.User.add(..))")
        public void after() {
            System.out.println("after.........");
        }
    
        /**異常通知*/
        @AfterThrowing(value = "execution(* com.th.atguigu.aopanno.User.add(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing.........");
        }
    
        /**環繞通知*/
        @Around(value = "execution(* com.th.atguigu.aopanno.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("環繞之前.........");
            //被增強的方法執行
            proceedingJoinPoint.proceed();
            System.out.println("環繞之後.........");
        }
    }
    

    結果:

    環繞之前.........
    before...
    add method...
    afterReturning.........
    after.........
    環繞之後.........
        
    //如果發生異常:
    環繞之前.........
    before...
    afterThrowing.........
    after.........
    

    異常通知:只有在被增強方法內部發生異常時呼叫。

    最終通知:無論是否發生異常都會被執行。而後置通知如果發生異常就不會被執行。

  5. 相同的切入點抽取

    如上所示,有多種不同型別的通知,在每個通知上都需要相同的註解表示式會比較麻煩,那麼可以抽取公共部分簡化操作。在通知的註解上使用配置了的方法名即可。

    @Pointcut("execution(* com.th.atguigu.aopanno.User.add(..))")
    public void pointDemo(){
    
    }
    
    /**前置通知 @Before 註解表示作為前置通知*/
    @Before("pointDemo()")
    public void before(){
        System.out.println("before...");
    }
    
  6. 設定增強類優先順序

    當有多個增強類對同一個方法進行增強時,可以設定增強類的優先順序。

    在增強類上面添加註解 @Order(數字型別值)數字型別值越小優先順序越高

    @Component
    @Aspect
    @Order(0)
    public class PersonProxy {
        @Before("execution(* com.th.atguigu.aopanno.User.add(..))")
        public void beforePerson(){
            System.out.println("before of PersonProxy");
        }
    }
    
    before of PersonProxy
    環繞之前.........
    before...
    add method...
    afterReturning.........
    after.........
    環繞之後.........
    
  7. 完全使用註解開發 (建立配置類,不需要建立 xml 配置檔案)

    @Configuration
    @ComponentScan(basePackages = {"com.atguigu"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }
    

    @EnableAspectJAutoProxy(proxyTargetClass = true)相當於<aop:aspectj-autoproxy/>

AspectJ XML配置檔案實現AOP

  1. 建立兩個類,增強類和被增強類,建立方法 。

  2. 在 spring 配置檔案中(使用bean)建立兩個類物件。

    <!--建立增強類和被增強類物件-->
    <bean id="book" class="com.th.atguigu.aopxml.Book"/>
    <bean id="bookProxy" class="com.th.atguigu.aopxml.BookProxy"/>
    
  3. 在 spring 配置檔案中配置切入點。

    <!--配置 aop 增強-->
    <aop:config>
        <!--切入點-->
        <aop:pointcut id="p" expression="execution(* com.th.atguigu.aopxml.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--增強作用在具體的方法上-->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
    
  4. 測試

    public void testTwo(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beanXml.xml");
        Book book = context.getBean("book", Book.class);
        book.buy();
    }
    

4、整合資料庫

4.1 整合mybatis

Mybatis使用步驟:

  1. 匯入依賴(mybatismysql-connector-java
  2. 配置mybatis(mybatis-config.xml)
  3. 構建工具類,獲取SqlSessionFactory和SqlSession
  4. 編寫實體類(可使用lombok
  5. Dao介面
  6. 介面實現類Impl【XXXMapper.xml】
  7. 在Mybatis核心配置檔案中註冊每一個Mapper.xml
  8. 測試

整合

  1. 導包

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.3</version>
    </dependency>
    

    mybatis-spring:將 MyBatis 程式碼無縫地整合到 Spring 中,允許 MyBatis 參與到 Spring 的事務管理之中,建立對映器 mapper 和 SqlSession 並注入到 bean 中,以及將 Mybatis 的異常轉換為 Spring 的 DataAccessException。 最終,可以做到應用程式碼不依賴於 MyBatis,Spring 或 MyBatis-Spring。

    http://mybatis.org/spring/zh/index.html

  2. 配置mybatis資料來源

    資料來源:用Spring的資料來源代替Mybatis的配置 ——————org.springframework.jdbc.datasource

    <bean id="DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="mysqlpw"/>
    </bean>
    

    資料來源的形式是多樣的,也可以使用其他形式對資料來源進行配置。

  3. 獲取SqlSessionFactory

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="DataSource" />
        <!--繫結mybatis的配置檔案-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/th/mapper/*.xml"/>
    </bean>
    

    可以在這個SqlSessionFactoryBean配置Mybatis的一些其他配置(別名等)。最主要的是可以直接匯入Mybatis的原有配置檔案mybatis-config.xml,兩種配置可以配合使用。

    mapperLocations獲取Mapper的路徑,相當於在Mybatis對Mappper的註冊。

  4. 獲取和SqlSessionSqlSessionTemplate:就是mybatis中的sqlSession。

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能通過構造器注入sqlSessionFactory,因為它沒有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
  5. 編寫實體類

  6. Dao介面

  7. 介面實現類XXXMapper.xmlImpl實現類,

    Impl實現類是必須的,而在Mybatis中實現類不需要,在Spring中Impl實現類是必須的,用於獲取sqlSessionTemplate

    public class UserMapperImpl implements UserMapper{
    
        //我們的所有操作,都用sqlSession來執行,在原來,現在使用SqlSessionTemplate;
        private SqlSessionTemplate sqlSessionTemplate;
    
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            this.sqlSessionTemplate = sqlSession;
        }
    
        @Override
        public List<User> selectUserList() {
            UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
            return mapper.selectUserList();
        }
    }
    

    當然Impl實現類也可以通過繼承SqlSessionDaoSupport類,通過呼叫 getSqlSession() 方法得到一個 SqlSessionTemplate來執行 SQL 方法。

    public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
        @Override
        public List<User> selectUserList() {
            return getSqlSession().getMapper(UserMapper.class).selectUserList();
        }
    }
    
  8. Spring配置檔案中建立實現類物件。

    <bean id="userMapperImpl" class="com.th.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSessionTemplate"/>
    </bean>
    

    通過繼承SqlSessionDaoSupport類的Impl實現類那麼在建立其物件時需要傳遞sqlSessionFactory

    <bean id="userMapperImpl2" class="com.th.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    
  9. 通過實現類物件進行業務操作

    public void testSelectUserList() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapper = context.getBean("userMapperImpl2", UserMapper.class);
        for (User user : userMapper.selectUserList()) {
            System.out.println(user);
        }
    }
    

5、宣告式事務管理

5.1 什麼事務

事務是資料庫操作最基本單元,邏輯上一組操作,要麼都成功,如果有一個失敗所有操作都失敗。

事務分類:

  • 宣告式事物:通過AOP實現。
  • 程式設計式事物:在程式碼中進行事務管理。

Spring均支援這兩種事物,但是推薦使用宣告式事物。

5.2、事務四個特性(ACID)

  1. 原子性
  2. 一致性
  3. 隔離性
  4. 永續性

5.3 Spring中的事務管理

Spring提供一個介面PlatformTransactionManager,代表事務管理器,這個介面針對不同的框架提供不同的實現類,DataSourceTransactionManagermybatisJdbcTemplate提供使用。

1、基於註解方式

  1. 在 spring 配置檔案配置事務管理器

    要開啟 Spring 的事務處理功能,在 Spring 的配置檔案中建立一個 DataSourceTransactionManager 物件:

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入資料來源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  2. 在 spring 配置檔案,開啟事務註解

    1. 在 spring 配置檔案引入名稱空間 tx

    2. 開啟事務註解

      <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
      
  3. 在 service 類上面(或者 service 類裡面方法上面)新增事務註解@Transactional

    @Transactional:這個註解作用在類上,也可以作用在方法上。

    @Service
    @Transactional()
    public class AccountService {
    }
    

    宣告式事務管理引數配置,@Transactional()屬性引數的設定。

    • propagation:事務傳播行為

      多事務方法(對資料庫表資料進行變換的操作)直接進行呼叫,這個過程中事務是如何進行管理的。如一個事物方法呼叫另一個事務方法,這個被呼叫的事務方法是否進行事務管理。Spring有7種事務傳播行為。

      @Transactional(propagation = Propagation.REQUIRED)
      
    • ioslation:事務隔離級別

      事務具有隔離性,不考慮隔離性可能會產生髒讀不可重複讀虛(幻)讀問題。

      髒讀:一個未提交事務讀取到另一個未提交事務的資料。

      不可重複讀:一個未提交事務讀取到另一提交事務修改資料。

      虛讀:一個未提交事務讀取到另一提交事務新增資料。

      Spring通過設定事務隔離級別,解決讀問題:

      髒讀 不可重複讀 幻讀
      READ_UNCOMMITTED
      READ_COMMITTED
      REPEATABLE_READ
      SERIALIZABLE
      @Transactional(isolation = Isolation.SERIALIZABLE)
      
    • timeout:超時時間

      • 事務需要在一定時間內進行提交,如果不提交則進行回滾 。

      • 預設值是 -1(不超時) ,設定時間以秒單位進行計算。

        @Transactional(timeout = -1)
        
    • readOnly:是否只讀

      • 讀:查詢操作,寫:新增修改刪除操作

      • readOnly 預設值 false,表示可以查詢,可以新增修改刪除操作

      • 設定 readOnly 值是 true,設定成 true 之後,只能查詢.

        @Transactional(readOnly = true)
        
    • rollbackFor:回滾

      • 設定出現哪些異常進行事務回滾
    • noRollbackFor:不回滾

      • 設定出現哪些異常不進行事務回滾

2、基於 xml 配置檔案方式

  1. 在 spring 配置檔案配置事務管理器

    <!--開啟 Spring 的事務處理功能-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>
    
  2. 配置事物通知,結合AOP實現事物的織入

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--給哪些方法配置事物-->
        <!--new 配置事物的傳播特性:propagation-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
  3. 配置事物切入

    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.th.kuang.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
    </aop:config>
    

3、完全註解開發

@Configuration //配置類
@ComponentScan(basePackages = "com.th.atguigu") //元件掃描
@EnableTransactionManagement //開啟事務
public class TxConfig {
    //建立資料庫連線池
    @Bean
    public DriverManagerDataSource getDruidDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8");
        dataSource.setUsername("root");
        dataSource.setPassword("mysqlpw");
        return dataSource;
    }
    //建立 JdbcTemplate 物件
    @Bean
    public JdbcTemplate getJdbcTemplate(DriverManagerDataSource dataSource) {
        //到 ioc 容器中根據型別找到 dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入 dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //建立事務管理器
    @Bean
    public DataSourceTransactionManager
    getDataSourceTransactionManager(DriverManagerDataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

關於No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected single matching bean but found 2: transactionManager,getDataSourceTransactionManager報錯問題。

由於在原來註解方式進行事務管理時存在一個數據源和事務管理器,@Transactional()註解時不直接指定,Spring就不知道具體使用哪一個事務管理器來進行事務管理了。使用只要@Transactional(transactionManager = “aaaTransactionManager”) 來進行指定具體的事務管理即可,當然最直接的方法是直接刪除原來的事務管理。

6、Spring5 框架新功能

6.1 基礎

整個 Spring5 框架的程式碼基於 Java8,執行時相容 JDK9,許多不建議使用的類和方 法在程式碼庫中刪除

  1. Spring 5.0 框架自帶了通用的日誌封裝。

    Spring5 已經移除 Log4jConfigListener,官方建議使用 Log4j2

  2. Spring5 框架核心容器支援@Nullable 註解

    @Nullable 註解可以使用在方法、屬性,引數上,分別表示方法返回可以為空,屬性值可以為空,引數值可以為空 。

  3. Spring5 核心容器支援函式式風格 GenericApplicationContext

    //函式式風格建立物件,交給 spring 進行管理
    @Test
    public void testGenericApplicationContext() {
        //1 建立 GenericApplicationContext 物件
        GenericApplicationContext context = new GenericApplicationContext();
        //2 呼叫 context 的方法物件註冊
        context.refresh();
        context.registerBean("user1",User.class,() -> new User());
        //3 獲取在 spring 註冊的物件
        // User user = (User)context.getBean("com.atguigu.spring5.test.User");
        User user = (User)context.getBean("user1");
        System.out.println(user);
    }
    
  4. Spring5 支援整合 JUnit4和 JUnit5

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration("classpath:bean1.xml")
    public class JTest5 {
        @Autowired
        private UserService userService;
        @Test
        public void test1() {	
        	userService.accountMoney();
        }
    }
    
    //使用一個複合註解替代上面兩個註解完成整合
    @SpringJUnitConfig(locations = "classpath:bean1.xml")
    public class JTest5 {
        @Autowired
        private UserService userService;
        @Test
        public void test1() {
        	userService.accountMoney();
        }
    }
    

6.1 Webflux

1、SpringWebflux 介紹

  • 是 Spring5 新增新的模組,用於 web 開發的,功能和 SpringMVC 類似的,Webflux 使用 當前一種比較流行的響應式程式設計出現的框架

  • 使用傳統 web 框架,比如 SpringMVC這些基於 Servlet 容器,Webflux 是一種非同步非阻塞的框架,非同步非阻塞的框架在 Servlet3.1 以後才支援,核心是基於 Reactor 的相關 API 實現 的。

  • 非同步和同步針對呼叫者,呼叫者傳送請求,如果等著對方迴應之後才去做其他事情就是同步,如果傳送請求之後不等著對方迴應就去做其他事情就是非同步。

  • 阻塞和非阻塞針對被呼叫者,被呼叫者受到請求之後,做完請求任務之後才給出反饋就是阻塞,受到請求之後馬上給出反饋然後再去做事情就是非阻塞。

  • Webflux 特點:

    • 非阻塞式:在有限資源下,提高系統吞吐量和伸縮性,以Reactor為基礎實現響應式程式設計。
    • 函數語言程式設計:Spring5 框架基於 java8,Webflux 使用 Java8 函數語言程式設計方式實現路由請求
  • 比較 SpringMVC

    • 兩個框架都可以使用註解方式,都執行在 Tomet 等容器中。
    • SpringMVC 採用指令式程式設計(程式碼一行一行執行),Webflux 採用非同步響應式程式設計

2、響應式程式設計

響應式程式設計程式設計RP,即Reactive Programming,響應式程式設計是一種面向資料流和變化傳播程式設計正規化。這意味著可以在程式語言中很方便地表達靜態或動態的資料流,而相關的計算模型會自動將變化的值通過資料流進行傳播。

電子表格程式就是響應式程式設計的一個例子。單元格可以包含字面值或類似"=B1+C1"的公 式,而包含公式的單元格的值會依據其他單元格的值的變化而變化。

響應式程式設計的思想是觀察者模式。Java8 及其之前版本提供的觀察者模式兩個類Observer Observable