主頁 > 後端開發 > 狂神說Java --- 記錄Spring學習筆記

狂神說Java --- 記錄Spring學習筆記

2021-09-21 09:22:02 後端開發

?傳送門 ==>B站遇見狂神說—Spring5教程

感謝狂神,學習視頻真的是通俗易懂???

筆記和練習只是跟著視頻整理的;有的知識點并沒有整理進來


ml

  • 1.Spring概述
  • 2. 控制反轉IOC
  • 3.試試Spring
    • 3.1 IOC創建物件的方式
    • 3.2 Spring配置說明
    • 3.3 DI (依賴注入)
      • 3.3.1 set注入
      • 3.3.2 (擴展) p命名set注入 ; c命名構造注入
    • 3.4 Bean的作用域
    • 3.5 自動裝配Bean
      • 3.5.1 byName,byType自動裝配
      • 3.5.2 使用注解實作裝配
        • Spring注解開發
      • 3.5.3 使用JavaConfig實作配置
  • 4. 靜態代理模式
  • 5. 動態代理模式
  • 6.面向切面 AOP
    • 方式1:使用原生的Spring API介面
    • 方式 2;使用自定義 實作
    • 方式3: 使用注解實作
  • 7. 整合Mybatis
    • 7.1Spring整合 Mybatis的方式一
    • 7.2 Spring整合 Mybatis的方式二
  • 8.宣告式事務


Spring 官網==>https://spring.io
Spring官方檔案==>https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html

本次使用的是Spring Web MVC

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
</dependency>

之后還可能用到spring jdbc

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.9</version>
</dependency>

1.Spring概述

Spring是開源免費的輕量級的控制反轉(IOC)和面向切面(AOP)的容器框架;支持事務處理.

由7個模塊組成,

在這里插入圖片描述

(Spring Boot) 構建一切,(Sprint Cloud)協調一切,(Spring Cloud Data Flow)連接一切

(Spring Boot)就像腳手架,可實作快速開發單個微服務;而學習它的前提是學習Spring和SpringMVC.


2. 控制反轉IOC

IOC理論推導

創建一個空的maven專案,洗掉src目錄;作為父級專案;

還是和之前一樣,先去檢查maven地址;

在這里插入圖片描述

pom.xml導包

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!--測驗使用-->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
</dependencies>

可看到,下載結束后,出現了好幾個資源包

在這里插入圖片描述

創建一個子級maven工程;

在這里插入圖片描述

在這里插入圖片描述


就用一個基礎的專案構建來說吧;
持久層介面UserDao;

public interface UserDao {
    //查詢用戶;
    void findUser();
}

持久層實作類UserDaoImpl;

public class UserDaoImpl implements UserDao{
    public void findUser() {
        System.out.println("默認呼叫的方法");
    }
}

業務層介面UserService;

public interface UserService {
    //查詢用戶;
    void findUser();
}

業務層介面的實作類UserServiceImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserDaoImpl();

    public void findUser() {
      //在業務層呼叫持久層的方法;
        userDao.findUser();
    }
}

測驗呼叫

@Test
    public void test(){
        UserService userService=new UserServiceImpl();
        userService.findUser();
    }

這時輸出

在這里插入圖片描述

而如果說,這時候又來需求了,持久層新增了一個實作類UserMySqlImpl

public class UserMySqlImpl implements UserDao{
    public void findUser() {
        System.out.println("MySql的方法");
    }
}

那么如果說想要拿到這個需求的實作,就要在業務層的實作類UserServiceImpl中;去更改持久層的實作類改為UserMySqlImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserMySqlImpl();

    public void findUser() {
      //在業務層呼叫持久層的方法;
        userDao.findUser();
    }
}

測驗呼叫,即可

在這里插入圖片描述

如果說又有一個新的需求,創建了一個新的持久層實作類UserOracleImpl;

public class UserOracleImpl implements UserDao{
    public void findUser() {
        System.out.println("Oracle方式");
    }
}

那么就得去業務層UserServiceImpl中更改;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserOracleImpl();

    public void findUser() {
      //在業務層呼叫持久層的方法;
        userDao.findUser();
    }
}

然后測驗呼叫

在這里插入圖片描述

在之前的業務中,用戶的需求可能會影響原來的代碼,就要根據用戶的需求更改代碼.

要是在UserServiceImpl中用set實作動態修改實作類;

public class UserServiceImpl implements UserService{
     private UserDao userDao;
    //控制反轉的原型,在業務層提供動態的用戶需求方法;
    //用set實作動態注入值;
     public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
      }

    public void findUser() {
      //在業務層呼叫持久層的方法;
      userDao.findUser();
    }
}

在測驗執行的方法內,只需要呼叫setUserDao 方法,去更改里面的持久層實作類即可

public class MyTest {
    @Test
    public void test() {
        UserService userService = new UserServiceImpl();
        ((UserServiceImpl) userService).setUserDao(new UserMySqlImpl());
        userService.findUser();
    }
}

在這里插入圖片描述


每使用set設定之前,程式是需要主動創建物件,控制權在開發者手中,使用了set注入后,程式不再具有主動性,變為被動的接受物件.
開發者不必管理物件的創建,系統耦合性降低,專注于業務的實作.

即控制反轉 IOC 的原型.


IOC的本質

控制反轉IOC 設計思想,而 DI(依賴注入)是實作IOC的一種方法,
在沒有使用IOC的程式,作為面向物件編程的語言,物件的創建和物件間的依賴關系是必須硬編碼在程式中,物件的創建由程式自己控制,

控制反轉后將物件的創建轉移到第三方, 獲取依賴物件的方式反轉.


3.試試Spring

ok新建一個物體類User;

public class User {
    private String name;

    public User(){
        System.out.println("User類的無參構造");
    }
    
    public User(String name){
        this.name=name;
        System.out.println("User類的有參構造");
    }
    
    public String getName() {
        return name;
    }

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

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

resources目錄下創建beans.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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--使用spring 創建物件;就是 bean-->
    <!--這時的id就是變數名;class就是new的物件-->
    <!--property: 可以為物件的屬性設定值-->

    <bean id="user" class="com.lzq.pojo.User">
        <property name="name" value="xiaozhi"/>
    </bean>
</beans>

測驗

public class Test01 {
    public static void main(String[] args) {
        //獲取Spring得背景關系物件;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于創建物件就是 Spring 中的bean; 獲取bean即可獲取物件;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

輸出:

User類的無參構造
User{name='xiaozhi'}

可以看出,從始至終沒有使用new構造方法進行創建User類的物件;
但是實際上在xml組態檔中,已經被Spring創建物件了;且設定了屬性name的值;
程式本身不去創建物件,作為了被動的接收物件.

此程序就是控制反轉;IOC; 由Spring 創建 管理 裝配.

在這里插入圖片描述

這里使用了set方法來進行注入的;若洗掉set方法;就無法得到屬性name.
設定value是針對于基本資料;

在這里插入圖片描述

設定物體類顯示小葉子圖示;

在這里插入圖片描述


再看看剛才的UserDao,實際上,根據需要就可以直接在組態檔修改即可.

ref: 會參考 在Spring中設定創建的物件


3.1 IOC創建物件的方式

剛在在測執行時;注意到,輸出有呼叫到無參構造方法;

在這里插入圖片描述

那么如果將User類的無參構造方法去掉;即為User類寫個顯示的有參構造,默認隱式的無參構造就沒有了;

在這里插入圖片描述

再次執行,出現例外提示;提示初始化例外;

在這里插入圖片描述

在xml組態檔中也有提示

在這里插入圖片描述

IOC創建物件時默認使用無參構造方法,

那么如果說想用有參構造方法呢,有三種方式;

方式1:使用index(下標) 指定有參構造方法的引數是第幾個; value 為引數賦值 ;
beans.xml 檔案的bean標簽下的constructor-arg標簽中配置

<?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-3.0.xsd">

    <!--方式1:使用 index(下標)  指定有參構造方法的引數是第幾個; value 為引數賦值 -->

    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg index="0" value="小智從零開始學Java"/>
    </bean>
</beans>

執行,是呼叫了有參構造方法的;且為引數name賦值也取到了.

在這里插入圖片描述

方式2:使用type 屬性 顯式的指定建構式引數的型別;value為引數賦值.

注意: 基本型別可直接寫;參考型別要注明類的地址;
例如官方檔案中是這么寫的.

<bean id="exampleBean" class="examples.ExampleBean">
   <constructor-arg type="int" value="2001"/>
   <constructor-arg type="java.lang.String" value="Zara"/>
</bean>

ok,用方式2調有參構造方法,為user類創建物件.

<?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-3.0.xsd">
    <!--方式2: 使用 type屬性 顯式的指定建構式引數的型別; value 為引數賦值-->
    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg type="java.lang.String" value="方式二"/>
    </bean>
</beans>

執行,使用成功;

在這里插入圖片描述

方式 3: 直接使用 引數名name設定 ; value 引數賦值

<?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-3.0.xsd">
    <!--方式3: 使用引數名name; -->
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    </bean>
</beans>

執行,使用成功;

在這里插入圖片描述


還有就是,在pojo包下,再創建一個Student類;

public class Student {
    private int age;

    public Student() {
        System.out.println("Student類的無參構造方法");
    }

    public int getAge() {
        return age;
    }

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

注意;僅僅是在beans.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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--User類-->
    <!--方式3: 使用引數名name; -->
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    </bean>

    <!--Student類-->
    <bean id="student" class="com.lzq.pojo.Student">

    </bean>

</beans>

誒,這里還是執行之前測驗User類的代碼;

public class Test01 {
    public static void main(String[] args) {
        //獲取Spring得背景關系物件;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于創建物件就是 Spring 中的bean; 獲取bean即可獲取物件;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

但是輸出結果時,發現Student類創建物件時呼叫的無參構造方法也有記錄;

在這里插入圖片描述

實際上, Spring容器就像是一個婚介網站

在組態檔加載的時候,容器中管理的物件就已經初始化了.


3.2 Spring配置說明

別名
alias

比如說;為User類創建物件時的變數id user 取個別名u

<alias name="user"  alias="u"/>

在這里插入圖片描述

那么,在執行測驗時,使用別名也能獲取到這個User類的物件;

在這里插入圖片描述

Bean的配置
細細看看<bean>標簽內的幾個配置標簽

id 就是 bean的唯一識別符號 ,也就相當于物件名;

classbean 對應的全限定名==> 包名 +型別;

name別名 ;且 可以寫多個別名,用逗號或者分號隔開即可

<bean id="user" class="com.lzq.pojo.User"  name="u1,u2;u3">
</bean>

import標簽
一般在團隊開發中使用;可以將多個組態檔匯入合并為一個

<import resource="beans.xml"/>
<import resource="otherbeans.xml"/>
<import resource="otherbeans2.xml"/>

3.3 DI (依賴注入)

第一個就是建構式注入,也就是剛才在創建物件時修改呼叫有參無參構造方法時;就使用過了.

第二個就是set注入,這個很重要

依賴: = = > bean物件的創建依賴于Spring容器
注入: = => bean物件中的所有屬性,由容器注入.

3.3.1 set注入

用一個復雜的案例看看這個set注入

新建一個Adderss

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

新建一個Student

public class Student {
    private String name;
    //這里的Address是自定義的類;
    private Address address;

    private String[] books;

    private List<String> hobby;

    private Map<String,String>  card;

    private Set<String> games;

    private String friend;

    private Properties info;

    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getFriend() {
        return friend;
    }

    public void setFriend(String friend) {
        this.friend = friend;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString()  +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", friend='" + friend + '\'' +
                ", info=" + info +
                '}';
    }
}

resources 目錄下創建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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--為Address類創建物件-->
    <bean id="address" class="com.xiaozhi.pojo.Address">
        <property name="address" value="陜西"/>
    </bean>

    <!--為Student類創建物件-->
    <bean id="student" class="com.xiaozhi.pojo.Student">

        <property name="name" value="小智"/>
        <!--自定義參考型別 -->
        <property name="address" ref="address"/>
        <!--陣列型別的 books-->
        <property name="books">
            <array>
                <value>演算法圖解</value>
                <value>大話資料結構</value>
                <value>劍指Offer</value>
                <value>java核心技術</value>
            </array>
        </property>
        <!--list型別的 hobby-->
        <property name="hobby">
            <list>
                <value>吃飯</value>
                <value>睡覺</value>
                <value>學習</value>
                <value>敲代碼</value>
            </list>
        </property>
        <!--map型別的 card-->
        <property name="card">
            <map>
                <entry key="電卡" value="123456789"/>
                <entry key="水卡" value="223456789"/>
                <entry key="燃氣卡" value="000000000"/>
            </map>
        </property>
        <!--set型別的 games-->
        <property name="games">
            <set>
                <value>Fortnite</value>
                <value>OverWatch</value>
            </set>
        </property>
        <!--null型別的 friend-->
        <property name="friend" >
            <null/>
        </property>
        <!--Properties型別的 info-->
        <property name="info">
            <props>
                <prop key="性別"></prop>
                <prop key="電話">123654</prop>
            </props>
        </property>
     </bean>
</beans>

執行測驗輸出,不同型別的屬性賦值均取到;

public class Test03 {
    public static void main(String[] args) {
        //讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取Student類的 bean;
        Student student = (Student) applicationContext.getBean("student");

        System.out.println(student.toString());
    }
}

在這里插入圖片描述


3.3.2 (擴展) p命名set注入 ; c命名構造注入

p: 命名空間注入,可直接注入屬性和值
注意在beans標簽的頭部需要匯入這個xml約束

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

物體類User

public class User {
    private String name;
    private int age;
    
    public User() {
        System.out.println("無參構造方法");
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("有參構造方法");
    }
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

組態檔

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--創建User類的物件   p: 命名空間注入,可直接注入屬性和值-->
    <bean id="user" class="com.xiaozhi.pojo.User" p:name="小智" p:age="21"/>
</beans>

getBean(“物件”,型別)
若在第二個引數處指明使用的型別,就不用強制轉換型別了;

public class Test04 {
    public static void main(String[] args) {
        //讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //獲取User類的 bean;
        User user =  applicationContext.getBean("user",User.class);

        System.out.println(user.toString());
    }
}

輸出

無參構造方法
User{name='小智', age=21}

c: 命名空間注入,可直接注入構造方法的引數與值
注意在beans標簽的頭部需要匯入這個xml約束

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

在組態檔中使用

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--可直接 使用構造方法的 引數-->
    <bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21"/>

    <!--也可使用 構造方法的 引數的索引-->
    <bean id="user2" class="com.xiaozhi.pojo.User" c:_0="阿杰" c:_1="21"/>
</beans>

測驗執行

public class Test04 {
    public static void main(String[] args) {
        //讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //獲取User類的 bean;
        User user1 =  applicationContext.getBean("user1",User.class);
        User user2 =  applicationContext.getBean("user2",User.class);

        System.out.println(user1.toString());
        System.out.println(user2.toString());
    }
}

輸出:

有參構造方法
有參構造方法
User{name='小智', age=21}
User{name='阿杰', age=21}

3.4 Bean的作用域

singleton(默認值) 單例模式:在 Spring 中只存在一個 bean 實體

即使不寫也是默認存在的.

<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="singleton"/>

在這里插入圖片描述

比如說,我在執行這邊分別獲取兩次bean;兩次取到到的bean是同一個

在這里插入圖片描述

prototype:原型模式 getBean()的時候都會 new Bean()

<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="prototype"/>

在這里插入圖片描述

還是剛才的執行例子;兩次取到的物件不一致了.

在這里插入圖片描述

request:每次 http 請求都會創建一個 bean, 僅用于 WebApplicationContext環境
session:同一個 http session 共享一個 Bean, 不同 Session 使用不同的 Bean, 使用環境同上


3.5 自動裝配Bean

自動裝配是Spring為滿足bean依賴的一種方式;由Spring在背景關系中自動尋找,自動裝配bean.

有三種裝配方式;
在xml顯示的手動裝配;
在java中顯示地裝配
隱式的自動裝配

首先設計幾個類

Cat類

public class Cat {
    public void shoot(){
        System.out.println("阿貓說喵喵");
    }
}

Dog類

public class Dog {
    public void shoot(){
        System.out.println("阿狗說汪汪");
    }
}

Person類

public class Person {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

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

配置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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--配置Cat類和Dog類的bean-->
    <bean id="cat" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog" class="com.xiaozhi.pojo.Dog"/>

    <!--配置Person類的bean-->
    <bean id="person" class="com.xiaozhi.pojo.Person">
        <property name="name" value="小智"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

</beans>

測驗呼叫

public class Test04 {
    public static void main(String[] args) {
        //讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

        //獲取User類的 bean;
        Person person = applicationContext.getBean("person", Person.class);
        person.getCat().shoot();
        person.getDog().shoot();
    }
}

輸出

阿貓說喵喵
阿狗說汪汪

3.5.1 byName,byType自動裝配

使用byName時,需要保證所有的bean 的id是唯一的,且bean是需要與自動注入的屬性的set方法一致;

使用byType時,需要保證所有bean的class唯一; 且bean要和自動注入的屬性的型別保持一致.

先看看byName

需要在applicationContext.xml中更改配置Person類的bean;

直接用autowire="byName" 屬性
自動在容器的背景關系中查找,與自己物件的set方法后的值對應的bean.

<!--配置Cat類和Dog類的bean-->
    <bean id="cat" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog" class="com.xiaozhi.pojo.Dog"/>
    
 <!--配置Person類的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
    <property name="name" value="小智"/>
</bean>

在這里插入圖片描述

在執行后,依然可輸出

在這里插入圖片描述

但是,配置Cat類和Dog類的bean時,修改id;

<!--配置Cat類和Dog類的bean-->
<bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog666" class="com.xiaozhi.pojo.Dog"/>

<!--配置Person類的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
    <property name="name" value="小智"/>
</bean>

誒,執行時就出現例外了

在這里插入圖片描述

這個說明什么呢;
只要配置的類的bean的id ; 和這個想要自動裝配bean 的類中的set方法名字后面的名稱一致,它就能自動裝配bean了.


再看看 byType

和byName設定時差不多
需要在applicationContext.xml中更改配置Person類的bean;
設定autowire="byType"
自動在容器的背景關系中查找;對應類的屬性中的型別相同的bean

<!--配置Cat類和Dog類的bean-->
    <bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog666" class="com.xiaozhi.pojo.Dog"/>
    
    <!--配置Person類的bean-->
    <!--byType 對應類的屬性中的型別相同的bean-->
    <bean id="person" class="com.xiaozhi.pojo.Person" autowire="byType">
        <property name="name" value="小智"/>
    </bean>

雖然這里的id是和set方法后面的名稱不一致的;但是仍然可以執行成功;

在這里插入圖片描述

但是有個問題啊;你這邊一旦創建多個bean;就不行了;
byType需要保證這里的型別要是唯一的

在這里插入圖片描述

但是,用了byType后,你甚至可以把裝配的bean的id給省略了

在這里插入圖片描述


3.5.2 使用注解實作裝配

需要匯入相關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"
    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/>

</beans>

配置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"
       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">

    <bean id="cat" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog" class="com.xiaozhi.pojo.Dog"/>
    <bean id="person" class="com.xiaozhi.pojo.Person"/>
    
    <!--注意開啟注解支持-->
    <context:annotation-config/>

</beans>

直接在Person類的屬性cat和dog處使用注解即可;@Autowired

@Autowired先執行byType

不過還是建議在setter方法上使用注解.

在這里插入圖片描述

同樣地裝配成功了

在這里插入圖片描述

擴展

(1) @Nullable 注解,在欄位處標記后,該欄位可以為null

(2) 仔細看看注解==@Autowired==;注意到后面是可以寫引數required (默認為true)的;
要是顯示地定義了 @Autowired(required = false) ,那么說明此欄位的物件可以為null

package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

(3) 如果xml檔案中同一個物件被多個bean使用;使用@Autowired無法按型別找到;’

這時就需要使用注解 @Qualifier(value=" ") 配合注解@Autowired;指定唯一的bean物件注入

在這里插入圖片描述

(4) 使用注解 @Resource ,java的原生注解; 它是根據class來找的.

@Resource先執行byName

如果xml檔案中同一個物件被多個bean使用;@Resource還可以加引數 @Resource(name=" ")

在這里插入圖片描述


Spring注解開發

spring后,先保證匯入 aop的包
且注解有約束和支持

<?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:component-scan base-package="com.xiaozhi.pojo"/>
    <!--注意開啟注解支持-->
    <context:annotation-config/>
</beans>

bean的注入

在類上使用注解 @Component 可以代替xml檔案中的配置bean

比如說這里使用注解就相當于

<bean id="user" class="com.xiaozhi.pojo.User"/>

在這里插入圖片描述

屬性的注入
在屬性的欄位上使用注解 @Value(“賦值”) 即可

比如說這里使用了注解就相當于

<bean id="user" class="com.xiaozhi.pojo.User">
     <property name="name" value="小智"/>
     <property name="age" value="21"/>
</bean>

在這里插入圖片描述

實際上; 注解 @Component 還有衍生的幾個注解;
一般在dao層使用注解 @Repository ; 表示倉庫;
service層使用注解 @Service ;
controller 層 使用 注解 @Controller

對于作用域還可使用注解 @Scope ;里面可傳參value指定所用域范圍.


3.5.3 使用JavaConfig實作配置

這部分不使用spring的組態檔;

之前僅作為spring的子專案,但在spring4之后是作為核心功能.

在一個類上使用注解 @Configuration ;該注解的底層已使用了注解@Component; 他也被spring接管了;表示該類為一個配置類

使用注解@ComponentScan("com.xiaozhi.pojo")配置包掃描;配置包掃描后,其實默認的id就是類名的小寫了;

注解 @Bean 就相當于組態檔的bean標簽;方法名相當于id;方法的回傳值相當于class 屬性;

注解 @Import(“其他組態檔類”) 可用來合并組態檔.

注意獲取物件時,要先用AnnotationConfigApplicationContext獲取背景關系物件;

物體類User

//注解表名該類被spring接管;注入bean;
@Component
public class User {

    private String name;

    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    //該注解為屬性賦值;
    @Value("小智")
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @Value("21")
    public void setAge(int age) {
        this.age = age;
    }

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

配置類UserConfig

//該注解的底層已使用了注解@Component; 他也被spring接管了;
//表示該類為一個配置類
@Configuration
//配置包掃描;
@ComponentScan("com.xiaozhi.pojo")
public class UserConfig {


    //配置bean;
    //方法名相當于之前組態檔的bean標簽的id 屬性
    //方法的回傳值相當于class 屬性;
    @Bean
    public User getUser(){
        return new User();
    }
}

執行;

public class Test06 {
    public static void main(String[] args) {
        //用注解的方式獲取的背景關系物件
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserConfig.class);

        //獲取物件;
        User user = applicationContext.getBean("getUser", User.class);

        System.out.println(user);

    }
}

可輸出

User{name='小智', age=21}

4. 靜態代理模式

代碼模式原型

在這里插入圖片描述

關于靜態代理

抽象角色 = => 介面或 抽象類

真實角色 = => 被代理的角色

代理角色 = => 代理真實角色, 代理真實角色后,會做出附屬操作

客戶 = => 訪問代理物件

(1)可以使真實角色的操作簡單;不用去關注公共業務;而公共業務交給代理角色;實作了業務的分工;公共業務發生擴展時,方便集中管理.
(2)缺點: 一個真實角色就要產生一個代理角色;代碼量翻倍;開發效率會變低.

第一個例子;面向中介去租房;
租房介面

//租房
public interface Rent {
    public void rent();
}

房東物體類

//房東
public class Host implements Rent{

    public void rent() {
        System.out.println("房東出租房子");
    }
}

代理中介

//代理中介
public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    public void rent() {
        seeHouse();
        host.rent();
        contract();
        fee();
    }

    //看房子;
    public void seeHouse(){
        System.out.println("由中介帶著看房");
    }
    //收費;
    public void fee(){
        System.out.println("收中介費用");
    }
    //簽合同
    public void contract(){
        System.out.println("和中介簽合同");
    }
}

租房的客戶

//租房的人 =,我
public class Me {
    public static void main(String[] args) {
        Host host=new Host();

        Proxy proxy = new Proxy(host);
        //直接面向代理中介;
        proxy.rent();
    }
}

直接執行客戶租房

由中介帶著看房
房東出租房子
和中介簽合同
收中介費用

在這里插入圖片描述

例子2:
比如說原有一個抽象業務介面
UserService

//抽象的業務;
public interface UserService {
    void addUser();
    void deleteUser();
    void updateUser();
    void findUser();
}

有他的實作類UserServiceImpl

//真實物件;
public class UserServiceImpl implements UserService{
    public void addUser() {
        System.out.println("添加用戶");
    }

    public void deleteUser() {
        System.out.println("洗掉用戶");
    }

    public void updateUser() {
        System.out.println("更新用戶");
    }

    public void findUser() {
        System.out.println("查詢用戶");
    }
}

業務已經跑起來了,但是需要一個額外的擴展功能;這時就需要一個代理類;
UserServiceProxy

//代理人;  可擴展功能;并不影響原來的業務功能;
public class UserServiceProxy implements UserService{

    private  UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void addUser() {
        log("add添加");
        userService.addUser();
    }

    public void deleteUser() {
        log("delete洗掉");
        userService.deleteUser();
    }

    public void updateUser() {
        log("update更新");
        userService.updateUser();
    }

    public void findUser() {
        log("find查詢");
        userService.findUser();
    }

    //模擬使用日志;
    public void log(String str){
        System.out.println("[模擬日志]=>使用的是"+str+"方法");
    }
}

那么用戶在實作時,只要走代理類的功能;既保證了原有的業務功能,也有新的擴展功能;

public class Me {
    public static void main(String[] args) {

        UserServiceImpl userService=new UserServiceImpl();

        //使用代理角色;
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(userService);
        userServiceProxy.addUser();
        userServiceProxy.deleteUser();
        userServiceProxy.updateUser();
        userServiceProxy.findUser();
    }
}

輸出

[模擬日志]=>使用的是add添加方法
添加用戶
[模擬日志]=>使用的是delete洗掉方法
洗掉用戶
[模擬日志]=>使用的是update更新方法
更新用戶
[模擬日志]=>使用的是find查詢方法
查詢用戶

5. 動態代理模式

代理類是動態生成的,
基于介面是 -->JDK動態代理 ;
基于類–> cglib
java的位元組碼實作時–>javasist

動態 代理介面,對應一類業務.

java.lang.reflect
Interface InvocationHandler

是由代理實體的呼叫處理程式實作的介面 ,

其中有一個invoke方法;

Object invoke(Object proxy, 方法 method, Object[ ] args)
處理代理實體上的方法呼叫并回傳結果,

在這里插入圖片描述

java.lang.reflect
Class Proxy

Proxy提供了創建動態代理類和實體的靜態方法,它也是由這些方法創建的所有動態代理類的超類,

在這里插入圖片描述

為某個介面創建代理FooInvocationHandler handler = new MyInvocationHandler(...);
     Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
                     newInstance(handler); 或更簡單地: 
  Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class<?>[] { Foo.class },
                                          handler); 

在這里插入圖片描述

案例;
還是剛才的userservice,userimpl案例;
但是代理類動態生成

//動態生成代理類;
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的介面;
    private Object object;

    public void setObject(Object object){
        this.object=object;
    }

    //生成代理類;
    public Object findProxy(){
        return  Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

    //處理代理實體,回傳結果;
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        //動態代理本質,用反射實作;
        Object res=method.invoke(object,args);
        return res;
    }

    //模擬日志的方法;
    public void log(String str){
        System.out.println("[模擬日志]=>使用的是"+str+"方法");
    }
}

在用戶呼叫時;

public class Me {
    public static void main(String[] args) {
        //真實的角色;  UserServiceImpl
        UserServiceImpl userService=new UserServiceImpl();

        //并不存在的代理角色;
        ProxyInvocationHandler pI=new ProxyInvocationHandler();
        //設定需要代理的物件;
        pI.setObject(userService);
        //動態得到代理類;
        UserService proxy = (UserService) pI.findProxy();

        proxy.addUser();
        proxy.findUser();
        proxy.deleteUser();
        proxy.updateUser();
    }
}

輸出

[模擬日志]=>使用的是addUser方法
添加用戶
[模擬日志]=>使用的是findUser方法
查詢用戶
[模擬日志]=>使用的是deleteUser方法
洗掉用戶
[模擬日志]=>使用的是updateUser方法
更新用戶

6.面向切面 AOP

AOP (Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實作程式功能的統一維護的一種技術,AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的重要內容,是函式式編程的一種衍生范型,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率,

在這里插入圖片描述

在這里插入圖片描述

使用spring實作AOP,先用maven導包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

方式1:使用原生的Spring API介面

創建UserService介面

//抽象的業務;
public interface UserService {
    void addUser();
    void deleteUser();
    void updateUser();
    void findUser();
}

實作類UserServiceImpl

//真實物件;
public class UserServiceImpl implements UserService{
    public void addUser() {
        System.out.println("添加用戶");
    }

    public void deleteUser() {
        System.out.println("洗掉用戶");
    }

    public void updateUser() {
        System.out.println("更新用戶");
    }

    public void findUser() {
        System.out.println("查詢用戶");
    }
}

模擬前置日志BeforeLog

//模擬前置日志;
public class BeforeLog implements MethodBeforeAdvice {
    /**
     *
     * @param method  要執行的目標物件方法;
     * @param objects 引數
     * @param target 目標物件
     * @throws Throwable
     */
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被執行");
    }
}

模擬后置日志

//模擬后置日志;
public class AfterLog implements AfterReturningAdvice {
    /**
     *
     * @param returnValue 回傳值
     * @param method  要執行的目標物件方法;
     * @param objects 引數
     * @param target 目標物件
     * @throws Throwable
     */
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(method.getName()+"執行后,回傳"+returnValue);
    }
}

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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--注冊bean-->
   <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
   <bean id="beforeLog" class="com.xiaozhi.log.BeforeLog"/>
   <bean id="afterLog" class="com.xiaozhi.log.AfterLog"/>

    <!--方式1   原生api介面-->
    <!--配置aop-->
    <aop:config>
        <!--切入點    要執行的位置 execution(回傳值 類名 方法名)
                     (..)兩個點代表可以有任意個引數    -->
        <aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>

        <!--執行環繞增加-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="point"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
    </aop:config>
</beans>

執行輸出

public class Test08 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //獲取bean;

        //動態代理的是介面;
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        //呼叫方法;
        userService.addUser();
        userService.deleteUser();
        userService.findUser();
        userService.updateUser();
    }
}

輸出

com.xiaozhi.service.UserServiceImpl的addUser方法被執行
添加用戶
addUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的deleteUser方法被執行
洗掉用戶
deleteUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的findUser方法被執行
查詢用戶
findUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的updateUser方法被執行
更新用戶
updateUser執行后,回傳null

方式 2;使用自定義 實作

不用去實作介面,直接自定義類MyLog

public class MyLog {
    public void beforeLog(){
        System.out.println("========模擬執行前置========");
    }
    public void afterLog(){
        System.out.println("========模擬執行后置========");
    }
}

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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    <!--注冊bean-->
    <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
    <bean id="myLog" class="com.xiaozhi.mydiy.MyLog"/>
    <!--方式2;使用自定義的類-->
    <!--配置aop-->
    <aop:config>
        <!--使用自定義的切面-->
        <aop:aspect ref="myLog">
            <!--配置切入點-->
            <aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>
            <!--配置方法-->
            <aop:before method="beforeLog" pointcut-ref="point"/>
            <aop:after method="afterLog" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
    
</beans>

測驗執行;同樣可執行

========模擬執行前置========
添加用戶
========模擬執行后置========
========模擬執行前置========
洗掉用戶
========模擬執行后置========
========模擬執行前置========
查詢用戶
========模擬執行后置========
========模擬執行前置========
更新用戶
========模擬執行后置========

方式3: 使用注解實作

自定義的類,用注解標注為切面

//使用注解實作;
//@Aspect 標注該類是個切面;
@Aspect
public class MyAnnotation {

    //注意使用的是 import org.aspectj.lang.annotation.Before;包下的
    @Before("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void beforeLog(){
        System.out.println("========注解方式模擬執行前置========");
    }

    //import org.aspectj.lang.annotation.After;
    @After("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void afterLog(){
        System.out.println("========注解方式模擬執行后置========");
    }

    //在環繞增強時,可給定引數,表示獲取處理切入的點
    @Around("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("在環繞之前");
        Signature signature = pjp.getSignature();
        System.out.println("獲取資訊=>"+signature);
        Object proceed = pjp.proceed();
        System.out.println("執行方法=>"+proceed);
        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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    <!--方式三  使用注解-->
    <!--注冊bean-->
    <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
    <bean id="myAnnotation" class="com.xiaozhi.annotation.MyAnnotation"/>

    <!--開啟注解支持-->
    <aop:aspectj-autoproxy/>

</beans>

執行也可實作

在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.addUser()
========注解方式模擬執行前置========
添加用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.deleteUser()
========注解方式模擬執行前置========
洗掉用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.findUser()
========注解方式模擬執行前置========
查詢用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.updateUser()
========注解方式模擬執行前置========
更新用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后

7. 整合Mybatis

官方檔案mybatis-spring整合檔案

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

需要用到的包

<dependencies>
        <!--測驗包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--資料庫驅動連接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <!-- spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--spring -jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <!--mybatis-spring整合-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
    </dependencies>

先回顧一下Mybatis;

創建

注意需要在pom.xml組態檔中配置資源指向地址

<!--為防止資源匯出失敗;在build中需要配置resources-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

創建工具類MybatisUtils;

public class MybatisUtils {
    private  static SqlSessionFactory sqlSessionFactory=null;
    //在呼叫工具類時就執行;
    static {
        try {
            //獲取SqlSessionFactory物件;

            //獲得組態檔;
            String resource = "mybatis-config.xml";
            //使用流讀取資源;
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //加載資源流;
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //從 SqlSessionFactory 中獲取 SqlSession;
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }
}

物體類User

//物體類User;
//使用lombok插件的注解;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

持久層介面UserMapper

public interface UserMapper {
    //查詢方法;
    public  List<User> findUser();
}

持久層組態檔UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--這里mapper的空間對應創建的持久層介面;-->
<mapper namespace="com.xiaozhi.dao.UserMapper">


    <select id="findUser" resultType="user">
        select * from user;
    </select>

</mapper>

核心組態檔mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
    <!--引入外部組態檔-->
    <properties resource="db.properties"/>
    <!--設定標準日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--使用包掃描的方式 ;物體類的別名默認為首字母小寫的類名-->
    <typeAliases>
        <package name="com.xiaozhi.pojo"/>
    </typeAliases>

    <!--environments:配置的環境,可以配置多個-->
    <environments default="development">
        <environment id="development">
            <!--transactionManager:事務管理;這里默認使用JDBC-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--加載連接資料庫的重要欄位屬性-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--系結介面-->
    <mappers>
        <mapper resource="com/xiaozhi/dao/UserMapper.xml"/>
    </mappers>
</configuration>

與資料庫互動的屬性檔案db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username=root
password=123456

測驗執行搭建環境

public class Test09 {
    @Test
    public void testFindUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //getmapper;
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> allUser = userMapper.findUser();
        //遍歷結果;
        for (User user : allUser) {
            System.out.println(user);
        }
        //關閉sqlSession;
        sqlSession.close();
    }
}

測驗成功;

在這里插入圖片描述


7.1Spring整合 Mybatis的方式一

新建UserMapper介面的實作類UserMapperImpl

public class UserMapperImpl implements UserMapper{

    //操作是用sqlSession執行的;
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> findUser() {
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        return userMapper.findUser();
    }
}

直接新建spring-dao.xml組態檔
撰寫資料源配置;sqlSessionFactory配置;SqlSessionTemplate配置;將實作類UserMapperImpl的bean也注入;

<?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: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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--使用Spring的資料源替換mybatis-->

    <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true&amp;serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!-- 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/xiaozhi/dao/UserMapper.xml"/>
        <property name="typeAliases" value="com.xiaozhi.pojo.User"/>
    </bean>

    <!-- SqlSessionTemplate   即使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--將實作類的bean注冊進來-->
    <bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
     </bean>
</beans>

這么一來,工具類MybatisUtils可直接省略;
且Mybatis的核心組態檔mybatis-config.xml也不用去寫太多的配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
    <!--設定標準日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
</configuration>

測驗執行

//整合Mybatis后;
    @Test
    public void testFindUser2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
       //獲取bean
       UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> user = userMapper.findUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
    }

輸出

在這里插入圖片描述


7.2 Spring整合 Mybatis的方式二

在寫UserMapper介面的實作類UserMapperImpl時,可繼承一個類SqlSessionDaoSupport;用來提供 SqlSession ;呼叫 getSqlSession()方法即可得到SqlSessionTemplate
省略了手動注入SqlSession

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    public List<User> findUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        return userMapper.findUser();
    }
}

且在配置bean時,用ref參考指向 賦值即可

<bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

執行測驗,查詢成功

在這里插入圖片描述


8.宣告式事務

在這里插入圖片描述

UserMapper介面再添加幾個方法

public interface UserMapper {
    //查詢方法;
    public  List<User> findUser();

    //添加用戶
    public  void addUser(User user);

    //洗掉用戶
    public void deleteUser(int id);
}

UserMapper.xml中撰寫sql陳述句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--這里mapper的空間對應創建的持久層介面;-->
<mapper namespace="com.xiaozhi.dao.UserMapper">


    <!--查詢用戶-->
    <select id="findUser" resultType="user">
        select * from user;
    </select>

    <!--添加用戶-->
    <insert id="addUser" parameterType="user">
        insert into user values (#{id},#{name},#{password});
    </insert>

    <!--洗掉用戶-->
    <delete id="deleteUser" parameterType="_int">
      delete from user where id=#{id}
    </delete>
</mapper>

UserMapper介面的實作類UserMapperImpl

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

    public List<User> findUser() {
        UserMapper userMapper=getSqlSession().getMapper(UserMapper.class);

        User user=new User(16,"石榴號","dsaasd");
        //添加用戶;
        userMapper.addUser(user);
        //洗掉用戶;
        userMapper.deleteUser(16);
        return userMapper.findUser();
    }

    public void addUser(User user) {
        getSqlSession().getMapper(UserMapper.class);
    }

    public void deleteUser(int id) {
        getSqlSession().getMapper(UserMapper.class);
    }
}

Mybatis的核心組態檔mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
    <!--設定標準日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
</configuration>

sping-dao.xml組態檔;
撰寫資料源配置;sqlSessionFactory配置;SqlSessionTemplate配置;配置事務;

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--使用Spring的資料源替換mybatis-->

    <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true&amp;serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!-- 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/xiaozhi/dao/UserMapper.xml"/>
        <property name="typeAliases" value="com.xiaozhi.pojo.User"/>
    </bean>

    <!-- SqlSessionTemplate   即使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--配置宣告事務-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--事務置入-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--為方法配置事務-->
        <!--配置事務的特性;默認為 propagation="REQUIRED"-->
        <tx:attributes>
            <tx:method name="findUser" propagation="REQUIRED"/>
            <tx:method name="addUser" propagation="REQUIRED"/>
            <tx:method name="deleteUser" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置事務切入-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.xiaozhi.dao.*.*(..))"/>
        <aop:advisor pointcut-ref="point" advice-ref="txAdvice"/>
    </aop:config>
    
</beans>

還可以用一個spring容器的xml檔案來合并其他的組態檔
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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--將pring-dao.xml 的配置合并過來-->
    <import resource="spring-dao.xml" />
    
    <!--將持久層的實作類的bean注冊進來-->
    <bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

測驗執行

public class Test10 {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取bean
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> user = userMapper.findUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
    }
}

一旦某個執行出現錯誤;不會將事務提交.


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

標籤:java

上一篇:LeetCode 1903. 字串中的最大奇數

下一篇:Java專案:網上電商系統(java+SSM+mysql+maven+tomcat)

標籤雲
其他(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