主頁 > 後端開發 > Spring5

Spring5

2022-04-29 06:11:43 後端開發

    # Spring概述

1、Spring是輕量級開源JavaEE框架

2、Spring可以解決企業應用開發的復雜性

3、組成核心IOC、Aop

  • IOC:控制反轉,把創建物件程序交給Spring進行管理

  • Aop:面向切面,不修改源代碼進行功能增強

4、Spring特點

  • 方便解耦,簡化開發
  • Aop編程支持
  • 方便程式測驗
  • 方便集成各種優秀框架
  • 方便進行事務管理
  • 降低java api的使用難度

*此檔案版本為Spring5

IOC

什么是IOC

? (1)控制反轉,把物件的創建和物件之間呼叫的程序,交給Spring進行管理

? (2) 使用IOC的目的:為了降低耦合

? (3) 做入門案例就是IOC的實作

IOC底層原理

? (1) xml決議、工廠模式、反射

image-20220223170558636

IOC程序 (進一步降低耦合度)

? 第一步 xml組態檔,配置創建的物件

<bean id="dao" ></bean>

? 第二步 有service類和dao類 創建工廠類

class UserFactory{
	public static UserDao getDao(){
		String classValue = https://www.cnblogs.com/hanyk/p/class屬性值;//1 xml決議 
        Class class = Class.forName(classValue);//2 通過反射創建物件
        return (UserDao)class.newInstance();//回傳物件
	}
}	

IOC介面

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

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

  • BeanFactory :IOC容器基本實作,是Spring內部的使用介面,不提供給開發人員使用
    • 加載組態檔時不會創建物件,獲取\使用物件時才會創建物件
  • ApplicationContext :BeanFactory介面的子介面,提供更多更強大的功能,一般由開發人員使用
    • 加載組態檔時就會把組態檔中物件創建(服務器啟動時創建)

ApplicationContext介面有實作類

image-20220223185151278

IOC操作 Bean管理

什么是Bean管理

包含以下兩個操作

  1. Spring創建物件
  2. Spring注入屬性

Bean管理操作

1 bean創建物件

1 基于xml組態檔方式

<!--配置User物件創建-->
<bean id="user" ></bean>   

(1)在Spring組態檔中,使用bean標簽,標簽里添加對應屬性,就可以實作物件創建
(2)在bean標簽中有很多屬性:

  • id屬性:唯一標識(不能加特殊符號)

  • class屬性:類全路徑(包類路徑)

  • name:類似id(可添加特殊符號)

(3)創建物件的時候,默認也是執行無參構造方法

2 基于注解方式

2 基于xml注入屬性

(1) DI:依賴注入,就是注入屬性(DI是IOC的一種具體實作,在創建物件的基礎之上進行)

第一種注入方式:使用set方法進行注入

第一步:創建類、創建屬性、創建對應的set方法

public class Book {
    //創建屬性
    private String bname;
    private String bauthor;
    //創建屬性對應的set方法
    public void setBname(String bname) {
        this.bname = bname;
    }

    public void getBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}

第二步:在Spring組態檔配置物件創建,配置屬性注入

<!--2 set方法注入屬性-->
<bean id="book" >
    <!--使用property完成屬性注入
        name:類里面屬性名稱
        value:向屬性注入的值
    -->
    <property name="bname" value="https://www.cnblogs.com/hanyk/p/張三日記"></property>
    <property name="bauthor" value="https://www.cnblogs.com/hanyk/p/法外狂徒張三"></property>
</bean>
public class Book {
    //創建屬性
    private String bname;
    private String bauthor;
    //創建屬性對應的set方法
    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}
第二種注入方法:使用有參構造進行注入

第一步:創建類 ,定義屬性,創建屬性對應有參構造方法

/**
 * 使用有參構造注入
 * */

public class Orders {
    private String oname;
    private String address;

    public Orders(String oname,String address){
        this.oname = oname;
        this.address = address;
    }
}

第二步:在Spring的組態檔中進行配置

<!--3 使用有參構造注入屬性-->
<bean id="orders" >
    <!-- constructor-arg標簽用于有參構造注入屬性-->
    <constructor-arg name="oname" value="https://www.cnblogs.com/hanyk/p/電腦"></constructor-arg>
    <constructor-arg name="address" value="https://www.cnblogs.com/hanyk/p/China"></constructor-arg>
</bean>
第三種注入方式:P名稱空間注入(底層使用的還是set方法注入)

使用p名稱空間注入,可以簡化基于xml配置方式

  • 添加p名稱空間在組態檔中

image-20220224175509505

  • 進行屬性注入,在bean標簽里面進行操作

    <!--4 使用p名稱空間注入-->
    <bean id="book"  p:bname="張三的一生" p:bauthor="羅翔">
    </bean>
    
xml注入其他型別屬性

字面量:固定值

  1. null值

    <!--null值-->
        <property name="address">
            <null/>
        </property>
    </bean>
    
  2. 屬性包含特殊符號

    <!--注入特殊符號
        1 拔尖括號進行轉義 &lt;&gt;
        2 把特殊符號內容寫到CDATA
    -->
    <property name="address">
        <value><![CDATA[<<南京>>]]></value>
    </property>
    
注入屬性-外部bean
  1. 創建兩個類service類和dao類

  2. 在service呼叫dao里面的方法

  3. 在Spring組態檔中進行檔案配置

    <!--1 service和Dao物件創建-->
    <bean id="userService" >
        <!--注入userDao物件
            name屬性值:類里面的屬性名稱
            ref屬性:創建userDao物件bean標簽id值
        -->
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" ></bean>
    
    public class UserService {
    
         //創建UserDao型別屬性,生成set方法
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void add(){
            System.out.println("service add............");
            userDao.update();
    
            //原始方式:創建UserDao物件
    //        UserDao userDao = new UserDaoImpl();
    //        userDao.update();
        }
    }
    
注入屬性-內部bean
  1. 一對多關系,部門和員工

    一個部門有多個員工,一個員工屬于一個部門, 部門是一 員工是多

  2. 在物體類之間表示一對多關系

    員工表示所屬部門,使用物件型別進行表示

    //部門類
    public class Dept {
        private String dname;
        public void setDname(String dname) {
            this.dname = dname;
        }
    }
    

    ?

    //員工類
    public class Emp {
        private String ename;
        private String gender;
        //員工屬于某一個部門,使用物件形式表示
        private Dept dept;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    }
    
  3. 在Spring組態檔中進行配置

    ?

    <!--內部bean-->
    <bean id="emp" >
        <!--設定兩個普通屬性-->
        <property name="ename" value="https://www.cnblogs.com/hanyk/p/lucy"></property>
        <property name="gender" value="https://www.cnblogs.com/hanyk/p/女"></property>
    
        <!--設定物件型別屬性-->
        <property name="dept">
            <bean id="dept" >
                <property name="dname" value="https://www.cnblogs.com/hanyk/p/安保部門"></property>
            </bean>
        </property>
    </bean>
    
注入屬性-級聯賦值

第一種寫法

<!--級聯賦值-->
<bean id="emp" >
    <!--設定兩個普通屬性-->
    <property name="ename" value="https://www.cnblogs.com/hanyk/p/lucy"></property>
    <property name="gender" value="https://www.cnblogs.com/hanyk/p/女"></property>

    <!--級聯賦值-->
    <property  name="dept" ref="dept"></property>
</bean>
<bean id="dept" >
    <property name="dname" value="https://www.cnblogs.com/hanyk/p/財務部"></property>
</bean>

第二種寫法 類中需要寫get方法

//員工類
public class Emp {
    private String ename;
    private String gender;
    //員工屬于某一個部門,使用物件形式表示
    private Dept dept;
    //生成dept的get方法

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void add(){
        System.out.println(ename+"::"+gender+"::"+dept);
    }
}
<!--級聯賦值-->
<bean id="emp" >
    <!--設定兩個普通屬性-->
    <property name="ename" value="https://www.cnblogs.com/hanyk/p/lucy"></property>
    <property name="gender" value="https://www.cnblogs.com/hanyk/p/女"></property>

    <!--級聯賦值-->
    <property  name="dept" ref="dept"></property>
    <property name="dept.dname" value="https://www.cnblogs.com/hanyk/p/技術部" ></property>
</bean>
<bean id="dept" >
    <property name="dname" value="https://www.cnblogs.com/hanyk/p/財務部"></property>
</bean>
xml注入集合屬性
  1. 注入陣列型別屬性

  2. 注入List集合屬性

  3. 注入Map集合型別屬性

  4. 注入set集合型別屬性

    創建類,定義陣列、list、map、set型別屬性,生成對應set方法

    public class Stu {
        //1 陣列型別屬性
        private String[] courses;
    
        //2 list集合型別屬性
        private List<String> list;
    
        //3 map集合型別屬性
        private Map<String,String> maps;
    
        //4 set集合型別屬性
        private Set<String> set;
    
        public void setSet(Set<String> set) {
            this.set = set;
        }
    
        public void setCourses(String[] courses) {
            this.courses = courses;
        }
    
        public void setList(List<String> list) {
            this.list = list;
        }
    
        public void setMaps(Map<String, String> maps) {
            this.maps = maps;
        }
    }
    

    在Spring組態檔進行配置

    <!--1 集合型別屬性注入-->
    <bean id="stu" >
        <!--陣列型別屬性注入-->
        <property name="courses" >
            <array>
                <value>java課程</value>
                <value>sql課程</value>
            </array>
        </property>
        <!--list集合屬性注入-->
        <property name="list">
            <list>
                <value>張三</value>
                <value>小三</value>
            </list>
        </property>
        <!--map型別屬性注入-->
        <property name="maps">
            <map>
                <entry key="JAVA" value="https://www.cnblogs.com/hanyk/p/java"></entry>
                <entry key="PHP" value="https://www.cnblogs.com/hanyk/p/php"></entry>
            </map>
        </property>
        <!--set型別屬性注入-->
        <property name="set">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>
    
  5. 在集合里設定物件型別值

    ?

    <!--注入list集合型別,值是物件-->
    <property name="courseList">
        <list>
            <ref bean="course1"></ref>
            <ref bean="course2"></ref>
        </list>
    </property>
    
    <!--創建多個course物件-->
    <bean id="course1" >
        <property name="cname" value="https://www.cnblogs.com/hanyk/p/Spring5框架"></property>
    </bean>
    <bean id="course2" >
    <property name="cname" value="https://www.cnblogs.com/hanyk/p/Mybatis框架"></property>
    
  6. 把集合注入部分提取出來

    1. 在Spring組態檔中引入空間名稱util
    <beans xmlns="http://www.springframework.org/schema/beans"
          	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    </beans>
    
    1. 使用util標簽完成list集合注入提取

      <!--1 提取list集合型別屬性注入-->
      <util:list id="bookList" >
          <!--若引入物件使用ref標簽-->
          <value>張三日記</value>
          <value>張三的悔改</value>
          <value>法外狂徒</value>
      </util:list>
      
      <!--2 提取list集合型別屬性注入使用-->
      <bean id="book" >
          <property name="list" ref="bookList"></property>
      </bean>
      

FactorBean

Spring里有兩種bean,一種普通的bean,另外一種是FactoryBean(Spring內置的)

  1. 普通bean

    Spring組態檔中定義bean型別即為回傳型別

  2. FactoryBean

    Spring組態檔中定義bean型別可與回傳型別不同

  1. 創建類,讓這個類作為工廠bean,實作介面FactoryBean

  2. 實作介面里面的方法,在實作的方法中定義回傳的bean型別

    public class MyBean implements FactoryBean <Course>{
        //定義回傳bean
        @Override
        public Course getObject() throws Exception {
            Course course = new Course();
            course.setCname("abc");
            return course;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    
    //測驗方法
    @Test
        public void testCollection3(){
            ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
            Course course=context.getBean("myBean",Course.class);
            System.out.println(course);
        }
    

    組態檔

    <bean id="myBean" >
    </bean>
    

bean的作用域

  1. 在Spring里,默認設定下,bean是單實體物件

    @Test
    public void testCollection2(){
        ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
        Book book1=context.getBean("book", Book.class);
        Book book2=context.getBean("book", Book.class);
        //book.test();
        System.out.println(book1);
        System.out.println(book2);
    }
    

輸出顯示地址相同為單實體物件:

image-20220303171118846

  1. 如何設定單實體或多實體

    (1)在Spring組態檔bean標簽里面有用于設定的屬性(scope)

    (2)scope屬性值

    • 默認值:singleton,表示單實體物件
    • prototype,表示多實體物件
    <!--2 提取list集合型別屬性注入使用-->
    <bean id="book"  scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>
    

    兩物件地址不同:

    image-20220303171843088

  2. singleton和prototype區別

    • singleton表示單實體,prototype多實體
    • 設定scope值是singleton時,加載Spring組態檔時就會創建單實體物件
    • 設定scope值是prototype時,不是在加載Spring組態檔時創建物件,在呼叫getBean方法時創建多例物件

Bean生命周期

從物件的創建到生命的銷毀的程序

bean生命周期:

  1. 通過構造器創建bean實體(無引數構造)

  2. 為bean的屬性設定值和對其他bean的參考(呼叫set方法)

    把bean實體傳給bean后置處理器的方法postProcessBeforeInitialization(bean的后置處理器BeanPostProcessor,bean共有7步)

  3. 呼叫bean初始化的方法(需要進行配置)

    把bean實體傳給bean后置處理器的另外一個方法postProcessAfterInitialization(bean的后置處理器BeanPostProcessor,bean共有7步)

  4. bean可以使用了(物件獲取到了)

  5. 當容器關閉時,呼叫bean的銷毀的方法(需要進行配置銷毀的方法)

    <bean id="orders"  init-method="initMethod" destroy-method="destoryMethod">
        <property name="oname" value="https://www.cnblogs.com/hanyk/p/手機"> </property>
    </bean>
    
    public class Orders {
        //1 無參構造
        public Orders(){
            System.out.println("第一步 執行無參構造方法創建bean實體");
        }
    
        private String oname;
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println("第二步 呼叫set方法設定屬性值");
        }
    
        //3 創建執行的初始化方法
        public void initMethod(){
            System.out.println("第三步 執行初始化方法");
        }
        //5 創建執行的銷毀方法
        public void destoryMethod(){
            System.out.println("第五步 執行銷毀方法");
        }
    }
    
    //測驗類
        @Test
        public void testBean3(){
    //        ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
            ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
            Orders orders=context.getBean("orders",Orders.class);
            System.out.println("第四步 獲取創建bean實體物件");
            System.out.println(orders);
    
            //手動讓bean實體銷毀
            context.close();
        }
    

添加后置處理器之后:

  1. 創建類,實作介面BeanPostProcessor,創建后置處理器

    public class MyBeanPost implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("在初始化之前執行的方法");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("在初始化之后執行的方法");
            return bean;
        }
    }
    
    <!--配置后置處理器-->
    <bean id="myBeanPost" ></bean>
    

IOC操作Bean管理(xml自動裝配)

什么是自動裝配?

根據指定裝配規則(屬性名稱或屬性型別),Spring自動將匹配的屬性值進行注入

演示自動裝配程序:

根據屬性名稱自動注入

<!--實作自動裝配
        bean標簽屬性autowire,配置自動裝配
        autowire屬性常用的兩個值:
            byName根據屬性名稱,注入值bean的id和類屬性名稱一樣
            byType根據屬性型別注入
    -->
    <bean id="emp"  autowire="byName">
<!--        <property name="dept" ref="dept"></property>-->
    </bean>
    <bean id="dept" ></bean>
</beans>

根據屬性型別自動注入

<!--實作自動裝配
        bean標簽屬性autowire,配置自動裝配
        autowire屬性常用的兩個值:
            byName根據屬性名稱,注入值bean的id和類屬性名稱一樣
            byType根據屬性型別注入
    -->
    <bean id="emp"  autowire="byType">
<!--        <property name="dept" ref="dept"></property>-->
    </bean>
    <bean id="dept" ></bean>
</beans>

IOC操作Bean管理(外部屬性檔案)

  1. 直接配置資料庫資訊

    ? 1.配置德魯伊連接池(Druid連接池,阿里巴巴)

    ? 2.引入德魯伊連接池依賴jar包

    <!--直接配置連接池-->
    <bean id="database" >
        <property name="DriverClassName" value="https://www.cnblogs.com/hanyk/p/com.mysql.jdbc.Driver"></property>
        <property name="url" value="https://www.cnblogs.com/hanyk/p/jdbc:mysql://locahost:3306/userDb"></property>
        <property name="username" value="https://www.cnblogs.com/hanyk/p/root"></property>
        <property name="password" value="https://www.cnblogs.com/hanyk/p/root"></property>
    </bean>
    
  2. 引入外部屬性檔案配置資料庫連接池

    (1)創建外部屬性檔案,properties格式檔案,寫資料庫資訊

    properties檔案存盤key:value格式配置

    prop.driverClass=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/userDb
    prop.userName=root
    prop.password=root
    

    (2)把外部properties屬性檔案引入到Spring組態檔中

    • 引入context名稱空間

      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             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
                                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
      </beans>
      
    • 在Spring組態檔標簽引入外部屬性檔案

      <!--引入外部屬性檔案-->
      <context:property-placeholder location="classpath:jdbc.properties"/>
      <!--配置連接池-->
          <bean id="database" >
              <property name="DriverClassName" value="https://www.cnblogs.com/hanyk/p/${prop.driverClass}"></property>
              <property name="url" value="https://www.cnblogs.com/hanyk/p/${prop.url}"></property>
              <property name="username" value="https://www.cnblogs.com/hanyk/p/${prop.userName}"></property>
              <property name="password" value="https://www.cnblogs.com/hanyk/p/${prop.password}"></property>
          </bean>
      

IOC操作Bean管理(基于注解方式)

什么是注解?

  • 注解是代碼特殊標記,格式:@注解名稱(屬性名稱=屬性值,屬性名稱=屬性值,,,)

  • 使用注解,注解作用在類、方法、屬性上面

  • 使用注解的目的:簡化xml配置

Spring針對Bean管理中創建物件提供注解:

  • @Component

  • @Service

  • @Controller

  • @Repository

    *四個注解功能相同,都可以用來創建bean物件

基于注解方式實作物件的創建:

  1. 引入依賴

  2. 開啟組件掃描

    <!--1 開啟組件掃描
            1 掃描多個包時,使用逗號隔開
            2 掃描包上層目錄可掃描包下多個包
    -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
    
  3. 創建類,在類上面添加創建物件注解

    //在注解里面value屬性值可以不寫
    //默認值是類名稱,首字母小寫
    //UserService.class---userService
    @Service(value = "https://www.cnblogs.com/hanyk/p/userService")//<bean id="userService" >相同
    public class UserService {
        public void add(){
            System.out.println("service add....");
        }
    }
    
  4. 開啟組件掃描的細節配置

    <!--示例1
        use-default-filters="false"表示不使用默認filter(掃描所有子目錄),自己配置filter
        context:include-filter,設定掃描哪些內容
    -->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
    
    <!--示例2
        下面示例掃描包下所有內容
        context:exclude-filter ,設定哪些不掃描
    -->
    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
    
  5. 基于注解方式實作屬性注入

    • @AutoWired:根據屬性型別進行自動裝配

      ? ①把service和dao物件創建,在service和dao類添加創建物件注解

      ? ②在service注入dao物件,在service類添加dao型別屬性,在屬性前使用注解

      @Service(value = "https://www.cnblogs.com/hanyk/p/userService")//<bean id="userService" >相同
      public class UserService {
      
          //定義dao型別屬性
          //不需要添加set方法(spring已經封裝了這一步)
          //添加注入屬性的注解
          @Autowired
          private UserDao userDao;
          public void add(){
              System.out.println("service add....");
              userDao.add();
          }
      }
      
    • @Qualifier:根據屬性名稱進行注入

      此注解的使用需要與@Autowired一起使用

      @Repository(value = "https://www.cnblogs.com/hanyk/p/userDaoImpl1")
      public class UserDaoImpl implements UserDao{
          @Override
          public void add() {
              System.out.println("dao add...");
          }
      }
      
      @Service(value = "https://www.cnblogs.com/hanyk/p/userService")//<bean id="userService" >相同
      public class UserService {
      
          //定義dao型別屬性
          //不需要添加set方法(spring已經封裝了這一步)
          //添加注入屬性的注解
          @Autowired  //根據型別進行注入
          @Qualifier(value = "https://www.cnblogs.com/hanyk/p/userDaoImpl1")
          private UserDao userDao;
          public void add(){
              System.out.println("service add....");
              userDao.add();
          }
      }
      
    • @Resource:(javax中的注解,jdk11之后移除)可以根據型別注入,可以根據名稱注入

    //    @Resource//默認根據型別注入
        @Resource(name = "userDaoImpl1")
        private UserDao userDao;
    
    • @Value:注入普通型別屬性

      @Value(value = "https://www.cnblogs.com/hanyk/p/abc")
      private String name;
      
  6. 完全注解開發

    (1)創建配置類,替代xml組態檔

    @Configuration//作為配置類,替代xml組態檔
    @ComponentScan(basePackages = {"com.atguigu"})
    public class SpringConfig {
    }
    

    (2)撰寫測驗類

    @Test
    public void testService2(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService",UserService.class);
        System.out.println(userService);
        userService.add();
    }
    

AOP

什么是AOP?

? 面向切面編程,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各個部分之間的耦合度降低,提高程式的可重用性,同時提高開發效率,

通俗描述:可不修改源代碼,在主干功能里添加新的功能

例子:在原登錄基礎上添加權限判斷

image-20220308163433475

AOP底層原理

AOP底層使用動態代理

有兩種情況的動態代理

  1. 有介面的情況 ,使用JDK動態代理

    創建介面實作類代理物件,增強類的方法

    image-20220308164729412

  2. 沒有介面的情況 ,使用CGLIB動態代理

    創建子類的代理物件,增強類的方法

    image-20220308165207366

AOP底層原理(JDK動態代理)

使用JDK動態代理,使用Proxy類里面的方法創建代理物件

image-20220308170122797

呼叫newProxyInstans方法

image-20220308170308516方法有三個引數:

  • 類加載器
  • 增強方法所在的類,這個類實作的介面,支持多個介面
  • 實作這個介面InvocationHandler,創建代理物件,寫增強方法

撰寫JDK動態代理代碼:

  1. 創建介面,定義方法

    public interface UserDao {
        public int add(int a,int b);
        public String update(String id);
    }
    
  2. 創建介面實作類,實作方法(原功能)

    public class UserDaoImpl implements UserDao{
    
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    
        @Override
        public String update(String id) {
            return id;
        }
    }
    
  3. 使用Proxy類創建介面代理物件(加新功能)

    public class JDKProxy {
        public static void main(String[] args){
    //        //創建介面實作類代理物件
            Class[] interfaces = {UserDao.class};
    //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        });
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1,2);
            System.out.println("result:"+result);
        }
    }
    
    //創建代理物件代碼
    class UserDaoProxy implements InvocationHandler{
        //1 把創建的是誰的代理物件,把誰傳遞進來
        //有引數的構造
        private Object obj;
        public UserDaoProxy(Object obj){
            this.obj = obj;
        }
    
        //增強的邏輯
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            //方法之前
            System.out.println("方法之前執行,,,,"+method.getName()+":傳遞的引數,,,"+ Arrays.toString(args));
    
            //被增強的方法執行
            Object  res = method.invoke(obj,args);
    
            //方法之后
            System.out.println("方法之后執行,,,,"+obj);
    
            return res;
        }
    }
    

AOP(術語)

  1. 連接點:類里面可以被增強的方法

  2. 切入點:類里面實際被增強的方法

  3. 通知(增強):實際增強的邏輯部分(新加的部分)

    *假如add()方法被增強

    • 前置通知:add()之前執行的增強
    • 后置通知:add()之后執行的增強
    • 環繞通知:add()之前之后都執行的增強
    • 例外通知:add()例外時執行的增強
    • 最終通知:return之后執行的增強,后置通知之后,有例外時不執行
  4. 切面(動作)

    把通知應用到切入點的程序

AOP操作(準備)

1、Spring框架中一般基于AspectJ實作AOP操作

AspectJ:AspectJ不是Spring組成部分,獨立AOP框架,一般把AspectJ和Spring框架一起使用,進行AOP操作

2、基于AspectJ實作AOP操作有兩種方式:

  1. 基于xml組態檔使用
  2. 基于注解方式實作(使用)

3、在專案工程里引入AOP相關依賴

image-20220309102111127

4、切入點運算式

  1. 切入點運算式的作用:知道對哪個類里面哪個方法進行增強

  2. 語法結構:

    execution([權限修飾符] [回傳型別] [類全路徑] [方法名稱] ([引數串列]))

    例1:對com.atguigu.dao.BookDao類里面的add方法進行增強

    execution(public void com.atguigu.dao.BookDao.add(int a,int b))

    權限修飾符可省略,默認public

    回傳型別可以用*號表示全型別

    execution(* com.atguigu.dao.BookDao.add(int a,int b))

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

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

    例3:對com.atguigu.dao包里的所有類,類里的所有方法進行增強

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

AOP(AspectJ注解)

演示:

  1. 創建類,在類里定義方法

    public class User {
        public void add(){
            System.out.println("add...");
        }
    }
    
  2. 創建增強類

    1. 在增強類里面,創建方法,讓不同方法代表不同通知型別

      //增強的類
      public class UserProxy {
      
          //前置通知
          public void before(){
              System.out.println("before...");
          }
      }
      
  3. 進行通知的配置

    1. 在Spring組態檔中,開啟注解的掃描

      <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"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
                                 http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd">
      
              <!--開啟注解掃描-->
              <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
      </beans>
      
    2. 使用注解創建User和UserProxy物件

    3. 在增強類上面添加注解@Aspect

      //增強的類
      @Component
      @Aspect //生產代理物件
      public class UserProxy {
      
          //前置通知
          public void before(){
              System.out.println("before...");
          }
      }
      
    4. 在Spring組態檔中開啟生成代理物件

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

      • 在增強類的里面,在通知方法上面添加通知型別的注解,使用切入點運算式配置

      • @Before

      • @After

      • @AfterReturning

      • @AfterThrowing

      • @Around

      //增強的類
      @Component
      @Aspect //生產代理物件
      public class UserProxy {
      
          //前置通知
          //@Before注解表示前置通知
          @Before(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void before(){
              System.out.println("before...");
          }
      
          @After(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void after(){
              System.out.println("after...");
          }
      
          @AfterReturning(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void afterReturning(){
              System.out.println("afterReturning...");
          }
      
          @AfterThrowing(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void afterThrowing(){
              System.out.println("afterThrowing...例外");
          }
      
          @Around(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
              System.out.println("around...之前");
      
              //被增強方法
              proceedingJoinPoint.proceed();
      
              System.out.println("around...之前后");
          }
      }
      
    6. 公共切入點

      //相同切入點抽取
      @Pointcut(value = "https://www.cnblogs.com/hanyk/p/execution(* com.atguigu.spring5.aopanno.User.add(..))")   //切入點注解
      public void pointdemo(){
      }
      
      //前置通知
      //@Before注解表示前置通知
      @Before(value = "https://www.cnblogs.com/hanyk/p/pointdemo()")
      public void before(){
          System.out.println("before...");
      }
      
    7. 多個增強類對同一個切入點增強時,可設定優先級

      在增強類上面加一個注釋@Order(數字型別值),數字型別值越小它的優先級越高(值從0開始)

    8. 完全使用注解開發

      創建配置類(config),不需要創建xml組態檔

      @Configuration
      @ComponentScan(basePackages = "com.atguigu")    //開注解掃描
      @EnableAspectJAutoProxy(proxyTargetClass = true)    //開啟Aspect生成代理物件
      public class ConfigAop {
      }
      

AOP(AspectJxml組態檔)

  1. 創建兩個類:增強類和被增強類,創建方法

  2. 在Spring組態檔中創建兩個類的物件

  3. 在Spring組態檔中配置切入點

    <!-- 創建兩個類的物件-->
    <bean id="book" ></bean>
    <bean id="bookProxy" ></bean>
    
    <!-- 配置切入點-->
    <aop:config>
        <!-- 切入點-->
        <aop:pointcut id="buy" expression="execution(* com.atguigu.spring5.aopxml.Book.buy()) "/>
    
        <!-- 配置切面(把增強應用到切入點的程序)-->
        <aop:aspect ref="bookProxy">
            <!-- 增強作用在具體方法上-->
            <aop:before method="before" pointcut-ref="buy"></aop:before>
        </aop:aspect>
    </aop:config>
    

JdbcTemplate

Spring框架對JDBC進行封裝,使用JdbcTemplate方便實作對資料庫操作

JdbcTemplate使用準備作業

  1. 引入相關jar包

    image-20220310175133948

  2. 在Spring組態檔中配置資料庫連接池

    <!--資料庫連接池-->
    <bean id="dataSource"  destroy-method="close">
        <property name="name" value="https://www.cnblogs.com/hanyk/p/jdbc:mysql:///user_db"/>
        <property name="username" value="https://www.cnblogs.com/hanyk/p/root"/>
        <property name="password" value="https://www.cnblogs.com/hanyk/p/root"/>
        <property name="driverClassName" value="https://www.cnblogs.com/hanyk/p/com.mysql.jdbc.Driver"/>
    </bean>
    
  3. 配置JdbcTemplate物件,注入Datasource

    <!--JdbcTemplate物件-->
    <bean id="jdbcTemplate" >
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  4. 創建service類,創建dao類,在dao注入JdbcTemplate物件

    1. <!--1 開啟組件掃描-->
      <context:component-scan base-package="com.atguigu"></context:component-scan>
      
    2. @Service
      public class BookService {
          //注入Dao
          @Autowired
          private BookDao bookDao;
      }
      
    3. @Repository
      public class BookDaoImpl implements BookDao{
      
          //注入JdbcTemplate
          @Autowired
          private JdbcTemplate jdbcTemplate;
      }
      

JdbcTemplate操作資料庫(添加)

  1. 對應資料庫創建

  2. 撰寫service和dao

    1. 在dao進行資料庫添加操作

      jdbcTemplate.update();
      
    2. 呼叫JdbcTemplate中的update()實作添加操作

      有兩個引數:

      1. sql陳述句
      2. 可變引數設定sql陳述句中的值
      
      @Repository
      public class BookDaoImpl implements BookDao{
      
          //注入JdbcTemplate
          @Autowired
          private JdbcTemplate jdbcTemplate;
      
      
          //添加方法
          @Override
          public void add(Book book) {
              //1 創建sql陳述句
              String sql="insert into t_book value(?,?,?)";
              //2 呼叫方法實作
              Object[] args = {book.getUser_id(),book.getUsername(),book.getUstatus()};
              int update = jdbcTemplate.update(sql,args);
              System.out.println(update);
          }
      }
      
    3. 測驗類

      public class TestBook {
          @Test
          public void testJdbcTemplate(){
              ApplicationContext context=
                      new ClassPathXmlApplicationContext("bean1.xml");
              BookService bookServcie = context.getBean("bookService", BookService.class);
              Book book = new Book();
              book.setUser_id(1);
              book.setUsername("張三");
              book.setUstatus("a");
              bookServcie.addBook(book);
          }
      }
      

JdbcTemplate操作資料庫(修改和洗掉)

  1. 方法的實作
//修改的方法
    @Override
    public void updateBook(Book book) {
        //1 創建sql陳述句
        String sql="update t_book set username=?,ustatus=? where user_id=?";
        //2 呼叫方法實作
        Object[] args = {book.getUsername(),book.getUstatus(),book.getUser_id()};
        int update = jdbcTemplate.update(sql,args);
        System.out.println(update);
    }

    //洗掉的方法
    @Override
    public void deleteBook(String id) {
        //1 創建sql陳述句
        String sql="delete from t_book where user_id=?";
        //2 呼叫方法實作
        int update = jdbcTemplate.update(sql,id);
        System.out.println(update);
    }
  1. 測驗

    public class TestBook {
        @Test
        public void testJdbcTemplate(){
            ApplicationContext context=
                    new ClassPathXmlApplicationContext("bean1.xml");
            BookService bookServcie = context.getBean("bookService", BookService.class);
    //        //添加
    //        Book book = new Book();
    //        book.setUser_id(1);
    //        book.setUsername("張三");
    //        book.setUstatus("a");
    //        bookServcie.addBook(book);
            //修改
            Book book = new Book();
            book.setUser_id(1);
            book.setUsername("javaupup");
            book.setUstatus("atguigu");
            bookServcie.updateBook(book);
    //        //洗掉
    //        bookServcie.deleteBook("1");
        }
    

JdbcTemplate操作資料庫(查詢)

查詢回傳某個值

  1. 場景:查詢表里有多少條記錄,回傳是某個值

  2. 使用JdbcTemplate實作查詢回傳某個值

    jdbcTemplate.queryForObject(sql,Integer.class);
    

    有兩個引數:

    1. sql陳述句
    2. 回傳型別Class
    //查詢表中的記錄數
    @Override
    public int selectCount() {
        String sql="SELECT COUNT(*) FROM t_book";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }
    

查詢回傳物件

  1. 場景:查詢圖書詳情

  2. JdbcTemplate實作查詢回傳物件

    jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Book.class), id);

    三個引數:

    1. sql陳述句

    2. RowMapper,是介面,回傳不同型別的資料,使用這個介面里面的實作類完成資料封裝

    3. 傳遞sql陳述句中?(占位符)的值

      @Override
      public Book findBookInfo(int id) {
          String sql="SELECT * FROM t_book where user_id=?";
          //呼叫方法
          Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
      
          return book;
      }
      

查詢回傳集合

  1. 場景:查詢圖書串列分頁

  2. 呼叫JdbcTemplate實作查詢回傳集合

    jdbcTemplate.query(sql, new BeanPropertyRowMapper(Book.class));

    三個引數:

    1. sql陳述句

    2. RowMapper,是介面,回傳不同型別的資料,使用這個介面里面的實作類完成資料封裝

    3. 傳遞sql陳述句中?(占位符)的值

      *第三個引數也可不寫

      @Override
      public List<Book> findAllBook() {
          String sql = "select * from t_book";
          List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
          return bookList;
      }
      

JdbcTemplate操作資料庫(批量)

  1. 批量添加

    image-20220311202913560

    兩個引數:

    1. sql陳述句

    2. List集合,添加多條記錄資料

      //批量添加
      @Override
      public void batchAddBook(List<Object[]> batchArgs) {
          String sql = "insert into t_book value(?,?,?)";
          int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
          System.out.println(Arrays.toString(ints));
      }
      
  2. 批量修改

    @Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = "update t_book set username=?,ustatus=? where user_id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
    

    測驗

    //批量修改
    List<Object[]> batchArgs = new ArrayList<>();
    Object[] objects1 = {"cc00","ccc00","3"};
    Object[] objects2 = {"dd00","ddd00","4"};
    Object[] objects3 = {"ee00","eee00","5"};
    batchArgs.add(objects1);
    batchArgs.add(objects2);
    batchArgs.add(objects3);
    bookServcie.batchUpdate(batchArgs);
    
  3. 批量洗掉

    @Override
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql="delete from t_book where user_id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
    

    測驗

    List<Object[]> batchArgs = new ArrayList<>();
    Object[] objects1 = {"3"};
    Object[] objects2 = {"4"};
    Object[] objects3 = {"5"};
    batchArgs.add(objects1);
    batchArgs.add(objects2);
    batchArgs.add(objects3);
    bookServcie.batchDelete(batchArgs);
    

事務操作

1、事務是資料庫操作最基本單元,邏輯上一組操作,要么都成功,如果有一個失敗則全失敗

典型場景:銀行轉賬:

  • lucy轉賬100元給mary
  • lucy少100,mary多100

2、事務的四個特性(ACID):

(1)原子性(atomicity):成功都成功,失敗都失敗

(2)一致性(consistency):操作之前和操作之后總量不變

(3)隔離性(isolation):多事務操作時,之間不會產生影響

(4)持久性(durability):提交之后表中資料就會發生變化

事務操作(搭建事務操作環境)

典型場景:銀行轉賬:

轉賬環境:image-20220311214628302

  1. 創建資料庫,添加記錄

image-20220311215159992

  1. 創建service,搭建dao,完成物件創建和注入關系

    1. service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DateSource

    2. @Service
      public class UserService {
          //注入Dao
          @Autowired
          private UserDao userDao;
      
      }
      
    3. @Repository
      public class UserDaoImpl implements UserDao{
          @Autowired
          private JdbcTemplate jdbcTemplate;
      }
      
    4. <!--1 開啟組件掃描-->
      <context:component-scan base-package="com.atguigu"></context:component-scan>
      
      <!--資料庫連接池-->
      <bean id="dataSource"  destroy-method="close">
          <property name="url" value="https://www.cnblogs.com/hanyk/p/jdbc:mysql:///user_db"/>
          <property name="username" value="https://www.cnblogs.com/hanyk/p/root"/>
          <property name="password" value="https://www.cnblogs.com/hanyk/p/root"/>
          <property name="driverClassName" value="https://www.cnblogs.com/hanyk/p/com.mysql.jdbc.Driver"/>
      </bean>
      
      <!--JdbcTemplate物件-->
      <bean id="jdbcTemplate" >
          <!--注入DataSource-->
          <property name="dataSource" ref="dataSource"></property>
      </bean>
      
  2. 在dao創建兩個方:多錢和少錢,在service創建轉賬方法

  3. 以上代碼如果正常執行是沒有問題的,但是如果以上代碼出現例外,有問題,則應符合原子性和一致性,賬戶資料都不變

事務管理(Spring事務管理介紹)

  1. 事務一般添加到JavaEE三層結構里的service層(業務邏輯層)
  2. 在Spring進行事務管理操作有兩種方式
    1. 編程式事務管理
    2. 宣告式事務管理(常用)
  3. 宣告式事務管理
    1. 基于注解方式實作(常用)
    2. 基于xml組態檔方式
  4. 在Spring進行宣告式事務管理,底層使用AOP原理
  5. Spring事務管理API
    1. 提供了一個介面,代表事務管理器,這個介面針對不同的框架提供不同的實作類

image-20220312110914933

事務操作(注解宣告式事務管理)

  1. 在Spring組態檔配置事務管理器

    <!-- 創建事務管理器-->
    <bean id="dataSourceTransactionManager" >
        <!-- 注入資料源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  2. 在Spring組態檔中開啟事務注解

    1. 在Spring組態檔中引入名稱空間tx

      xmlns:tx="http://www.springframework.org/schema/tx"
      
    2. 開啟事務注解

      <!-- 開啟事務注解-->
      <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
      
  3. 在service類上面添加事務注解

    @Transactional
    
    1. 如果添加到類上面,則類中所有方法都添加事務
    2. 如果添加到方法上面,則只給此方法添加事務

事務操作(宣告式事務管理引數配置)

  1. 在service類上面添加@Transactional,在這個注解里可以配置事務相關的引數

    image-20220312113822417

    1. propagation:事務傳播行為

      *多事務方法直接進行呼叫,這個程序中事務是如何進行管理的

      image-20220312114612365image-20220312114741323

    2. isolation:事務隔離級別

      默認值:@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)

      *事務有特性稱為隔離性,多事務操作之間不會產生影響,不考慮隔離性會產生很多問題

      *有三個讀的問題:臟讀、不可重復讀、虛(幻)讀

      • 臟讀:一個提交事務讀取到了另一個未提交事務的資料
      • 不可重復度:一個未提交事務讀取到另一提交事務修改資料
      • 虛讀:一個未提交事務讀取到另一提交事務添加****資料

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

      image-20220312145603002

    3. timeout:超時時間

      • 事務需要在一定時間內提交,如果不提交就會進行回滾
      • 默認值:-1(不超時)
      • 設定以秒為單位
    4. readOlay:是否只讀

      • 讀:查詢操作;寫:添加修改洗掉操作
      • 默認值:false(表示可以讀也可以寫)
      • 設定成true時只能讀不能寫
    5. rollbackFor:回滾

      • 設定出現哪些例外進行事務回滾
    6. noRollbackFor:不回滾

      • 設定出現哪些例外不進行事務回滾

事務操作(xml宣告式事務管理)

  1. 在Spring管理檔案中進行配置

    1. 配置事務管理器

    2. 配置通知

    3. 配置切入點和切面

      <!--1 創建事務管理器-->
          <bean id="transactionManager" >
              <!-- 注入資料源-->
              <property name="dataSource" ref="dataSource"></property>
          </bean>
          <!--2 配置通知-->
          <tx:advice id="txadvice">
              <!--配置事務引數-->
              <tx:attributes>
                  <!--指定在哪種規則的方法上面添加事務-->
                  <tx:method name="accountMoney" propagation="REQUIRES_NEW" isolation="REPEATABLE_READ" read-only="false"/>
      <!--            <tx:method name="account*"/>-->
              </tx:attributes>
          </tx:advice>
          <!--3 配置切入點和切面-->
          <aop:config>
      <!--        切入點-->
              <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
      <!--        切面-->
              <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
          </aop:config>
      

事務操作(完全注解宣告式注解管理)

創建配置類,使用配置類代替xml組態檔

@Configuration  //配置類
@ComponentScan(basePackages = "com.atguigu")    //組件掃描
@EnableTransactionManagement    //開啟事務
public class TxConfig {
    //1. 創建資料庫連接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql:///user_db");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }
    //2. 創建JdbcTemplate物件
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //到IOC容器中根據型別找到DateSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入DateSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //3. 創建事務管理器物件
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

Spring5框架新功能

整個Spring5框架基于java8,運行時兼容JDK9,許多不建議使用的類和方法在代碼庫中洗掉

Spiring5框架自帶了通用的日志框架

  • Spring5已經移除了Log4jConfigListener,官方建議使用Log4j2
  • Spring5框架整合Log4j2

Log4j2使用:

1. 引入jar包

image-20220312160311370

  1. 創建Log4j2.xml組態檔

    <?xml version="1.0" encoding="UTF-8"?>
    <!--日志級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--Configuration后面的status用于設定log4j2自身內部的資訊輸出,可以不設定,當設定成trace時,可以看到log4j2內部各種詳細輸出-->
    <?import org.apache.logging.log4j.core.layout.PatternLayout?>
    <configuration status="INFO">
        <!--先定義所有的appender-->
        <appenders>
            <!--輸出日志資訊到控制臺-->
            <console name="Console" target="SYSTEM_OUT">
                <!--控制日志輸出的格式-->
                <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </console>
        </appenders>
        <!--然后定義logger,只有定義了logger并引入的appender,appender才會生效-->
        <!--root:用于指定專案的根日志,如果沒有單獨指定Logger,則會使用root作為默認的日志輸出-->
        <loggers>
            <root level="info">
                <appender-ref ref="Console"/>
            </root>
        </loggers>
    </configuration>
    

Spring5框架核心容器支持@Nullable注解

@Nullable注解可以使用在方法上面,屬性上面,引數上面,表示方法回傳可以為空,屬性值可以為空,引數值可以為空

Spring5核心容器支持函式風格GenericApplicationContext(lambda運算式)

public void testGenericApplicationContext(){
        //創建GenericApplicationContext物件
        GenericApplicationContext context = new GenericApplicationContext();
        //呼叫context方法注冊物件
        context.refresh();
        context.registerBean("user1",User.class,()-> new User());
        //獲取Spring注冊的物件
//        User user = (User) context.getBean("com.atguigu.spring5.test.User");
        User user = (User) context.getBean("user1");
        System.out.println(user);
    }

Spring5支持整合JUnit5

  1. 整合JUnit4

    1. 引入Spring測驗相關的依賴

      image-20220312171459491

    2. @RunWith(SpringJUnit4ClassRunner.class) //指定單元測驗框架的版本
      @ContextConfiguration("classpath:bean1.xml")    //加載組態檔
      public class JTest4 {
          @Autowired
          private UserService userService;
      
          @Test
          public void test1(){
              userService.accountMoney();
          }
      }
      
  2. 整合JUnit5

    1. 引入JUnit5的jar包

    image-20220312180019155

    1. 創建測驗類,使用注解完成

      package com.atguigu.spring5.test;
      
      import com.atguigu.spring5.service.UserService;
      
      import org.junit.jupiter.api.Test;
      import org.junit.jupiter.api.extension.ExtendWith;
      import org.junit.runner.RunWith;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit.jupiter.SpringExtension;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @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")

//@ExtendWith(SpringExtension.class)
//@ContextConfiguration("classpath:bean1.xml")    //加載組態檔
@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5 {
    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        userService.accountMoney();
    }
}

SpringWebFlux

image-20220312181857297

webflux介紹

  1. 基本概念

    • Spring5添加的新的模塊,用于web開發的,功能與SpringMVC相似,webflux使用一種回應式編程出現的框架

    • 使用傳統的web框架,比如SpringMVC,這些基于Servlet容器,webflux是一種異步非阻塞的框架,異步非阻塞的框架在servlet3.1之后才支持,核心是基于Reactor的相關API實作的

  2. 回應式編程

  3. webflux執行流程和核心API

  4. Springwebflux(基于注解編程模型)

  5. Springwebflux(基于函式式編程模型)

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/466941.html

標籤:Java

上一篇:靈感乍現!造了個與眾不同的Dubbo注冊中心擴展輪子

下一篇:【架構視角】一篇文章帶你徹底吃透Spring

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more