Spring5框架

发布日期:2022-04-08

Spring5框架

一、内容介绍

  1. Spring 框架概述
  2. IOC容器
    • IOC底层原理
    • IOC接口(BeanFactory)
    • IOC操作Bean管理(基于xml)
    • IOC操作管理(基于注解)
  3. AOP
  4. JdbcTemplate
  5. 事务管理
  6. Spring5新特性

二、Spring5框架概述

  1. Spring是轻量级的开源的Java框架
  2. Spring可以解决企业应用开发的复杂性
  3. Spring有两个核心部分: IOC和AOP
    • IOC:控制反转,把创建对象过程交给Spring进行管理
    • AOP:面向切面,不修改源代码进行功能增强
  4. Spring特点
    • 方便解耦,简化开发
    • AOP编程支持
    • 方便程序测试
    • 方便和其他框架进行整合
    • 方便进行事务管理
    • 降低API开发难度
  5. Spring5框架下载 下载地址

三、Spring5入门案例

1、在spring官网下载最新稳定版

image-20220304210334775

2、下载之后解压在libs目录

3、使用IntellJ IDEA 创建一个JAVA工程

3.1、创建一个java工程

image-20220304211031419

3.2、工程界面

image-20220304211141680

3.3、导入需要用的Jar包

image-20220304211339160

image-20220304211834546

image-20220304211922381

4、创建entity包并创建普通类User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package top.withlevi.spring5.entity;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/3/4 9:20 PM
 */
public class User {
    public void add(){
        System.out.println("add method.....");
    }
}




image-20220304213015686

5、创建Spring配置文件, 在配置文件配置创建的对象-bean01.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

 <!--配置User对象创建-->
<bean id="user" class="top.withlevi.spring5.entity.User"/>

</beans>

image-20220304225109408

6、进行测试代码编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package top.withlevi.spring5.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import top.withlevi.spring5.entity.User;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/3/4 9:24 PM
 */
public class testAdd {

    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user);
        user.add();

    }
}

1
2
3
4
5
6
# 输出结果
top.withlevi.spring5.entity.User@cb0ed20
add method.....

Process finished with exit code 0

四、IOC(概念和原理)

  1. 什么是IOC
    • 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
    • 使用IOC目的: 为了耦合度降低
  2. IOC底层原理
    • XML解析、工厂模式、反射
  3. IOC底层原理

image-20220304225946989

  1. IOC(BeanFactory接口)

    • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

    • Spring提供IOC容器实现两种方式:(两个接口)

      • BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用

        *加载配置文件时候不会创建对象,在获取对象使用才去创建对象

      • ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用

        *加载配置文件时候就会把在配置文件对象进行创建

      • ApplicationContext接口有实现类(Ctrl+H 显示类的继承关系

  1. image-20220304230816131

5、IOC操作Bean管理(概念)

5.1、什么是Bean管理
  1. Bean管理指的是两个操作
  2. Spring创建对象
  3. Spring注入对象
5.2、 Bean管理操作有两种方式
  1. 基于xml配置文件方式实现
  2. 基于注解方式实现

6、IOC操作Bean管理(基于xml方式)

6.1、基于xml方式创建对象
1
2
<!--配置User对象创建-->
<bean id="user" class="top.withlevi.spring5.entity.User"/>
  1. 在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
  2. 在bean标签有很多属性,介绍常用的属性
    • id属性:唯一标识
    • class属性:类全路径(包类路径)
  3. 创建对象时候,默认也是执行五参数构造方法完成对象创建
6.2、基于xml方式注入属性
  1. DI: 依赖注入,就是注入属性
6.3、第一种注入方式:使用set方法进行注入
  1. 创建类,定义属性和对象的set方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package top.withlevi.spring5.entity;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/3/4 11:22 PM
 */
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;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", bauthor='" + bauthor + '\'' +
                '}';
    }

    // 创建打印方法
    public void print(){
        System.out.println("bname: "+bname+", bauthor: "+bauthor);
    }
}


  1. 在spring配置文件配置对象创建,配置属性注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--set方法注入属性-->
    <bean id="book" class="top.withlevi.spring5.entity.Book">
        <!--使用property完成属性注入
            name: 类里面属性名称
            value:向属性注入的值
        -->
        <property name="bname" value="Spring5"/>
        <property name="bauthor" value="Levi.Zhao"/>
    </bean>

</beans>
6.4、第二种注入方式: 使用有参构造进行注入
  1. 创造类,定义属性,创建属性对应有参构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
     package top.withlevi.spring5.entity;
       
    /**
        * @author Levi.Zhao
     * @version 1.0
     * @date 2022/3/5 11:02 PM
     */
       
    public class Orders {
       
        // 属性
           private String oname;
        private String addrss;
       
        // 有参构造
           public Orders(String oname, String addrss) {
            this.oname = oname;
            this.addrss = addrss;
        }
       
        @Override
           public String toString() {
            return "Orders{" +
                    "oname='" + oname + '\'' +
                    ", addrss='" + addrss + '\'' +
                    '}';
        }
       
        // 输出
           public void print(){
            System.out.println("oname: "+oname+", address: "+addrss);
        }
    }
       
    
  2. 在Spring配置文件中进行配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
     <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
                         
        <!--有参构造注入属性-->
            <bean id="orders" class="top.withlevi.spring5.entity.Orders">
          <constructor-arg name="oname" value="电脑"/>
          <constructor-arg name="addrss" value="北京市"/>
      </bean>
                         
    </beans>
    
6.5、p名称空间注入(了解)
  1. 使用p空间注入、可以简化基于xml配置方式

    1. 第一步添加p空间在配置文件中并进行属性注入、在bean标签里面进行操作

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
       <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:p="http://www.springframework.org/schema/p"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd">
                                                
          <bean id="book1" class="top.withlevi.spring5.entity.Book" p:bname="Hello World" p:bauthor="Java"/>
                                                
      </beans>
      

7、IOC操作Bean管理(xml注入其他类型属性)

7.1、字面量
  1. null值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
       <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
       
        <!--null值-->
               <bean id="book2" class="top.withlevi.spring5.entity.Book">
            <property name="bauthor">
                <null/>
            </property>
        </bean>
       
    </beans>
    
  2. 属性值包含特殊符号

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
     <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
                         
        <!--null值-->
                  <bean id="book2" class="top.withlevi.spring5.entity.Book">
            <property name="bauthor">
                <null/>
            </property>
                         
            <property name="bname">
                      <value><![CDATA[<<北京>>]]></value>
            </property>
        </bean>
                         
    </beans>
    
7.2、注入属性-外部bean
  1. 创建两个类service类和Dao类

  2. 在service调用dao里面的方法

  3. 在spring配置文件中进行配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    // 创建接口对象UserDao
                         
    package top.withlevi.spring5.dao;
                         
    /**
     * @author Levi.Zhao
     * @version 1.0
     * @date 2022/3/6 9:34 PM
     */
    public interface UserDao {
           public void update();
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  ```java
   // 创建UserDaoImpl实现类

   package top.withlevi.spring5.dao.impl;

   import top.withlevi.spring5.dao.UserDao;

             /**
    * @author Levi.Zhao
    * @version 1.0
    * @date 2022/3/6 9:36 PM
    */
   public class UserDaoImpl implements UserDao {


       @Override
       public void update() {
           System.out.println("This is update method....");
             }
   }

  ```java




   ```java
  // 创建UserService类

  package top.withlevi.spring5.service;

  import top.withlevi.spring5.dao.UserDao;

  /**
    * @author Levi.Zhao
    * @version 1.0
          * @date 2022/3/6 9:38 PM
    */
         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();
       }
         }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   <--创建配置文件-->
   
   <?xml version="1.0" encoding="UTF-8"?>
   <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd">
   
       <!--1. service和dao对象创建-->
              <bean id="userService" class="top.withlevi.spring5.service.UserService">
           <!--注入userDao对象
               name属性:类里面属性名称
               ref属性: 创建userDao对象bean标签id值
           -->
           <property name="userDao" ref="userDaoImpl"/>
       </bean>
   
       <bean id="userDaoImpl" class="top.withlevi.spring5.dao.impl.UserDaoImpl"/>
   
   </beans>
1
2
3
4
5
6
7
8
   // 测试类
    @Test
   public void test05(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
       UserService userService =  context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }
1
2
3
4
5
   # 输出结果
   top.withlevi.spring5.service.UserService@954b04f
   service add......
   This is update method....
   
7.3、注入属性-内部bean
  1. 一对多关系: 部门和员工

    一个部门有多个员工,一个员工属于一个部门

    部门是一,员工是多

  2. 在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   // Dept 部门类
   package top.withlevi.spring5.entity;
   
   /**
    * @author Levi.Zhao
    * @version 1.0
       * @date 2022/3/6 9:59 PM
    */
   public class Dept {
      private String dname;
   
      public void setDname(String dname){
           this.dname = dname;
       }
   
       @Override
       public String toString() {
           return "Dept{" +
                             "dname='" + dname + '\'' +
                   '}';
       }
   }
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
   // Emp员工类
   
   package top.withlevi.spring5.entity;
   
   /**
    * @author Levi.Zhao
    * @version 1.0
    * @date 2022/3/6 10:00 PM
    */
          public class Emp {
       private String ename;
       private String gender;
   
       private Dept dept;
   
       public void setEname(String ename) {
              this.ename = ename;
       }
   
      public void setGender(String gender) {
           this.gender = gender;
      }
   
       public void setDept(Dept dept) {
           this.dept = dept;
       }
   
       @Override
                 public String toString() {
           return "Emp{" +
                   "ename='" + ename + '\'' +
                   ", gender='" + gender + '\'' +
                   ", dept=" + dept +
                   '}';
             }
   
       public void print(){
           System.out.println("ename: "+ename+"\n"+"gener: "+gender+"\n"+"dept: "+dept);
   
             }
   }
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">


           <!--内部bean-->
    <bean id="emp" class="top.withlevi.spring5.entity.Emp">
        <property name="ename" value="Levi.Zhao"/>
        <property name="gender" value="male"/>
        <property name="dept">
            <bean id="dept" class="top.withlevi.spring5.entity.Dept">
                <property name="dname" value="Microsoft Azure DevOps"/>
               </bean>
        </property>
    </bean>

</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   <!--注入属性一级联赋值-->
       <!--第一种写法-->
   
       <bean id="emp2" class="top.withlevi.spring5.entity.Emp">
           <!--设置两个普通属性-->
           <property name="ename" value="faker"/>
           <property name="gender" value="male"/>
   
           <!--一级联赋值-->
                  <property name="dept" ref="dept2"/>
       </bean>
   
       <bean id="dept2" class="top.withlevi.spring5.entity.Dept">
           <property name="dname" value="T1"/>
       </bean>
   
1
2
3
4
5
6
7
8
9
10
11
12
<!--第二种写法-->
   <bean id="emp3" class="top.withlevi.spring5.entity.Emp">
        <!--设置两个普通属性-->
        <property name="ename" value="ruler"/>
        <property name="gender" value="male"/>
        <property name="dept" ref="dept3"/>

        <property name="dept.dname" value="三星"/>

    </bean>

    <bean id="dept3" class="top.withlevi.spring5.entity.Dept"/>

8、IOC操作Bean管理(xml注入集合属性)

8.1、注入数组类型属性
8.2、注入List集合类型属性
8.3、注入Map集合类型属性
  1. 创建类,定于数组,list,map,set类型属性,生成对应set方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    
    package top.withlevi.spring5.bean;
       
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
       
    /**
     * Created by Levi Zhao on 3/29/2022 3:54 PM
     *
     * @Author Levi
     */
    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> sets;
       
        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;
        }
       
        public void setSets(Set<String> sets) {
            this.sets = sets;
        }
       
       
        @Override
        public String toString() {
            return "Stu{" +
                    "courses=" + Arrays.toString(courses) +
                    ", list=" + list +
                    ", maps=" + maps +
                    ", sets=" + sets +
                    '}';
        }
    }
       
    
  2. 在spring配置文件进行配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--1.集合类型熟悉注入-->
       
        <bean id="stu" class="top.withlevi.spring5.bean.Stu">
            <!--数组类型属性注入-->
            <property name="courses">
                <array>
                    <value>Java课程</value>
                    <value>数据库课程</value>
                </array>
            </property>
       
            <!--list类型属性注入-->
            <property name="list">
                <list>
                    <value>张三</value>
                    <value>李四</value>
                </list>
            </property>
       
            <!--map类型属性注入-->
            <property name="maps">
                <map>
                    <entry key="Java" value="java"></entry>
                    <entry key="PHP" value="php"></entry>
                </map>
            </property>
       
            <!--set类型属性注入-->
            <property name="sets">
                <set>
                    <value>MYSQL</value>
                    <value>Redis</value>
                </set>
            </property>
       
        </bean>
    </beans>
    
8.4、在集合里面设置对象类值
  1. 配置bean.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--创建多个course对象-->
        <bean id="course1" class="top.withlevi.spring5.bean.Course">
            <property name="cname" value="Spring5框架"></property>
        </bean>
       
        <bean id="course2" class="top.withlevi.spring5.bean.Course">
            <property name="cname" value="MyBatis框架"></property>
        </bean>
       
        <bean id="stu2" class="top.withlevi.spring5.bean.Stu">
            <property name="courseList">
                <list>
                    <ref bean="course1"/>
                    <ref bean="course2"/>
                </list>
            </property>
        </bean>
    </beans>
    
  2. Course 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    package top.withlevi.spring5.bean;
    public class Course {
        private String cname;
       
        public void setCname(String cname) {
            this.cname = cname;
        }
       
        @Override
        public String toString() {
            return "Course{" +
                    "cname='" + cname + '\'' +
                    '}';
        }
    }
       
    
8.5、把集合注入部分提取出来
  1. 在spring配置文件中引入名称空间util

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    <?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"
           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">
       
        <!--提取list集合类型属性注入-->
        <util:list id="bookList">
            <value>Java</value>
            <value>Vue</value>
            <value>Python</value>
        </util:list>
       
        <!--提取list集合类型属性注入使用-->
        <bean id="book" class="top.withlevi.spring5.bean.Book">
            <property name="list" ref="bookList"/>
        </bean>
       
    </beans>
    
  2. 创建Book类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    package top.withlevi.spring5.bean;
       
    import java.util.List;
    public class Book {
        private List<String> list;
       
        public void setList(List<String> list) {
            this.list = list;
        }
       
        @Override
        public String toString() {
            return "Book{" +
                    "list=" + list +
                    '}';
        }
    }
       
    

9、IOC操作Bean管理(FactoryBean)

9.1、Spring两种类型bean
  1. 普通bean:在配置文件中定义bean类型就是返回类型

  2. 工厂bean:在配置文件定义bean类型可以和返回类型不一样

    第一步 创建类, 让这个类作为工程bean, 实现接口FactoryBean

    第二步 实现接口里面的方法, 在实现的方法中定义返回的bean类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package top.withlevi.spring5.factory;

import org.springframework.beans.factory.FactoryBean;
import top.withlevi.spring5.bean.Course;
public class MyBean implements FactoryBean<Course> {

    // 定义返回bean
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("Hello Spring5");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

1
    <bean id="myBean" class="top.withlevi.spring5.factory.MyBean"/>
1
2
3
4
5
6
7
@Test
    public void testFactoryBean() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean05.xml");
        Course myBean = context.getBean("myBean", Course.class);
        System.out.println(myBean);

    }
9.2、IOC操作管理(bean作用域)
  1. 在Spring里面,设置创建bean实例是单实例还是多实例

  2. 在Spring里面,默认情况下,bean是单实例对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @Test
        public void testFactoryBean2() {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean05.xml");
            Book book1 = context.getBean("book2", Book.class);
            Book book2 = context.getBean("book2", Book.class);
            System.out.println(book1);
            System.out.println(book2);
        }
       
    

    输出结果:

    1
    2
    3
    
    // 输出结果相同
    top.withlevi.spring5.bean.Book@4b53f538
    top.withlevi.spring5.bean.Book@4b53f538
    
  3. 如何设置单实例还是多实例

    • 在spring配置文件bean标签里面有属性(scope) 用于设置单实例还是多实例
    • scope属性值
      • 第一个值 默认值,singleton,表示是单实例对象
      • 第二个值 prototype,表示是多实例对象
    1
    2
    3
    4
    5
    6
    7
    8
    
    <bean id="book2" class="top.withlevi.spring5.bean.Book" scope="prototype">
            <property name="list">
                <list>
                    <value>Hello Spring5</value>
                    <value>Hello SpringMVC</value>
                </list>
            </property>
        </bean>
    

    输出结果:

    1
    2
    3
    
    // 输出结果不同
    top.withlevi.spring5.bean.Book@134593bf
    top.withlevi.spring5.bean.Book@4bb4de6a
    
    • singleton和prototype区别

      • 第一singleton单实例,prototype多实例

      • 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象

        设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用

        getBean方法的时候创建多实例对象

9.3、IOC操作Bean管理(bean生命周期)
  1. 生命周期

    • 从对象创建等到对象销毁的过程
  2. bean生命周期

    • 通过构造器创建bean实例(无参数构造方法)
    • 为bean的属性设置值和对其他bean引用(调用set方法)
    • 调用bean的初始化的方法(需要进行设置初始化的方法)
    • bean可以使用了(对象获取到了)
    • 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
  3. 演示bean生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    package top.withlevi.spring5.bean;
    public class Orders {
       
        private String oname;
        private String address;
       
        public Orders() {
            System.out.println("First step - Execute a no-argument construct and create bean instance.");
        }
       
        public Orders(String oname, String address) {
            this.oname = oname;
            this.address = address;
       
        }
       
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println("Second - Invoke method and set properties value");
        }
       
        public void setAddress(String address) {
            this.address = address;
        }
       
        public void initMethod(){
            System.out.println("Third - Execute initialize method");
        }
       
        public  void destroyMethod(){
            System.out.println("fifth - Execute destroy method");
        }
        @Override
        public String toString() {
            return "Orders{" +
                    "oname='" + oname + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
       
    }
       
    
    1
    2
    3
    4
    
     <bean id="orders" class="top.withlevi.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
            <property name="oname" value="iPhone"/>
            <property name="address" value="Beijing"/>
        </bean>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @Test
        public void test03() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean05.xml");
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println("Fourth - Get bean instance of creation");
            System.out.println(orders);
            // 手动让bean实例销毁
            context.close();
        }
    

    输出结果:

    1
    2
    3
    4
    5
    6
    
    First step - Execute a no-argument construct and create bean instance.
    Second - Invoke method and set properties value
    Third - Execute initialize method
    Fourth - Get bean instance of creation
    Orders{oname='iPhone', address='Beijing'}
    fifth - Execute destroy method
    
  4. bean的后置处理器,bean生命周期有七步

    • 通过构造器创建bean实例(无参数构造)
    • 为bean的属性设置值和对其他bean引用(调用set方法)
    • 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
    • 调用bean的初始化的方法(需要进行配置初始化的方法)
    • 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
    • bean可以使用了(对象获取到了)
    • 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
  5. 演示添加后置处理器效果

    创建类,实现接口BeanPostProcessor,创建后置处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    package top.withlevi.spring5.bean;
       
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor
       
    public class MyBeanPost implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Method execute before initialization ");
            return bean;
        }
       
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Method execute after initialization ");
            return bean;
        }
    }
       
    
    1
    2
    
     <!--Configure after processor -->
     <bean id="myBeanPost" class="top.withlevi.spring5.bean.MyBeanPost"/>
    

    输出结果:

    1
    2
    3
    4
    5
    6
    7
    8
    
    First step - Execute a no-argument construct and create bean instance.
    Second - Invoke method and set properties value
    Method execute before initialization 
    Third - Execute initialize method
    Method execute after initialization 
    Fourth - Get bean instance of creation
    Orders{oname='iPhone', address='Beijing'}
    fifth - Execute destroy method
    

10、IOC操作Bean管理(xml自动装配)

10.1、什么是自动装配
  • 根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
10.2、演示自动装配过程
  1. 根据属性名称自动注入

    实现自动装配

    bean标签属性autowire,配置自动装配

    autowire属性常用两个值:

    ​ byName 根据属性名称注入,注入值bean的id值和类属性名称一样

    ​ byType根据属性类型注入

    Dept.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    package top.withlevi.spring5.bean;
    public class Dept {
        private String dname;
       
        public Dept() {
        }
       
        public String getDname() {
            return dname;
        }
       
        public void setDname(String dname) {
            this.dname = dname;
        }
       
        @Override
        public String toString() {
            return "Dept{" +
                    "dname='" + dname + '\'' +
                    '}';
        }
    }
       
    

    Emp.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    package top.withlevi.spring5.bean;
    public class Emp {
     private String name;
     private Integer age;
     private Dept dept;
    
     public Emp() {
     }
    
     public void setName(String name) {
         this.name = name;
     }
    
     public void setAge(Integer age) {
         this.age = age;
     }
    
     public void setDept(Dept dept) {
         this.dept = dept;
     }
    
     @Override
     public String toString() {
         return "Emp{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 ", dept=" + dept +
                 '}';
     }
    }
    
    

    Byname

    ```xml <?xml version=”1.0” encoding=”UTF-8”?>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

   byType

   ```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.xsd">

    <bean id="emp" class="top.withlevi.spring5.bean.Emp" autowire="byType">
        <property name="name" value="Levi"/>
        <property name="age" value="29"/>
        <!--<property name="dept" ref="dept"/>-->

    </bean>
    <!--注意 要使用byType方式 这个地方只能有一个此类型的创建 否则会报错-->
    <bean id="dept" class="top.withlevi.spring5.bean.Dept">
        <property name="dname" value="Microsoft Azure"/>
    </bean>
</beans>

11、IOC操作Bean管理(外部属性文件)

11.1、直接配置数据库信息
  • 配置druid连接池

  • 引入druid连接池依赖jar包

    druid-1.1.9.jar

直接在bean.xml配置连接池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc://localhost:3306/test01"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

</beans>
11.2、引入外部属性文件配置数据库连接池
  • 创建外部属性文件,properties格式文件,写数据库信息

    jdbc.properties

    1
    2
    3
    4
    
    prop.driverClass=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/test01
    prop.userName=root
    prop.password=root
    
  • 引入外部属性文件配置数据库连接池

    • 引入context名称空间

      1
      2
      3
      4
      5
      6
      7
      8
      
      <?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
             http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">
      
    • 在spring配置文件使用标签引入外部属性文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      <?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
             http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">
          
          <!--使用外部属性文件-->
          <context:property-placeholder location="classpath:jdbc.properties"/>
          
          <!--配置连接池-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="driverClassName" value="${prop.driverClass}"/>
              <property name="url" value="${prop.url}"/>
              <property name="username" value="${prop.userName}"/>
              <property name="password" value="${prop.password}"/>
          </bean>
          
      </beans>
      
11.3、IOC操作Bean管理(基于注解方式)
  1. 什么是注解

    • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)
    • 使用注解,注解作用在类上面,方法上面,属性上面
    • 使用注解目的:简化xml配置
  2. Spring针对Bean管理中创建对象提供注解

    • @Componet
    • @Service
    • @Controller
    • @Repository

    上面四个注解功能都是一样的,都可以用来创建bean实例

  3. 基于注解方式实现对象创建

    • 引入依赖

      spring-aop-5.2.6.jar

    • 开启扫描组件

      1
      
      <context:component-scan base-package="top.withlevi.spring5"/>
      
    • 创建类,在类上面添加创建对象注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      
      // 在注解里面value属性值可以忽略不写
      // 默认值是类名称,首字母小写 UserService->userService
            
           
      @Component("userService")  // <bean id="userService" class="...">
      public class UserService {
           
          public void add(){
              System.out.println("add......");
          }
      }
      
  4. 开启组件扫描细节配置

    1
    2
    3
    4
    5
    6
    7
    
     <!-- use-default-filters="false 表示现在不使用默认filter 自己配置filter -->
        <context:component-scan base-package="top.withlevi.spring5" use-default-filters="false">
            <!--设置那些内容扫描-->
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
            <!--设置那些内容不扫描-->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        </context:component-scan>
    
  5. 基于注解方式实现属性注入

    1. @Autowired:根据属性类型进行自动装配

      • 第一步 把service和dao对象创建,在service和dao类添加创建对象注解
      • 在service注入dao对象,在service类添加dao类型熟悉,在属性上面使用注解

      UserDao.java

      1
      2
      3
      4
      5
      6
      
      package top.withlevi.spring5.dao;
            
      public interface UserDao {
          public void add();
      }
            
      

      UserDaoImpl.java

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      package top.withlevi.spring5.dao;
            
      import org.springframework.stereotype.Component;
            
      @Component("userDaoImp11")
      public class UserDaoImple implements UserDao{
          @Override
          public void add() {
              System.out.println("UserDao.....");
          }
      }
            
      
    2. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      
      UserService.java
            
        ```java
        package top.withlevi.spring5.service;
              
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Qualifier;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.stereotype.Component;
        import org.springframework.stereotype.Service;
        import top.withlevi.spring5.dao.UserDao;
        import javax.annotation.Resource;
              
        @Component("userService")
        public class UserService {
            @Value(value = "Hell Service")  // 注入普通类型属性
            private String name;
              
           // @Autowired // 根据类型进行注入
            //@Qualifier(value = "userDaoImp11") // 根据名称进行注入
            // @Autowired 和@Qualifier一起使用的
                  
            //@Resource   // 根据类型进行注入
            @Resource(name = "userDaoImp11")
            private UserDao userDao;
              
            public void add(){
                userDao.add();
                System.out.println("add......");
                System.out.println("name: "+name);
            }
        }
              
      

      定义dao类型属性,不需要添加set方法 ```

  6. 完全注解开发

    1. 创建配置类,替代xml配置文件

      1
      2
      3
      4
      5
      6
      7
      8
      
      package top.withlevi.spring5.config;
            
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      @Configuration // 作为配置类,替代xml配置文件
      @ComponentScan(basePackages = {"top.withlevi.spring5"})
      public class MyConfig {
      }
      
    2. 编写测试类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
      package top.withlevi.spring5.test;
            
      import org.junit.Test;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import top.withlevi.spring5.config.MyConfig;
      import top.withlevi.spring5.service.UserService;
            
      public class TestMethod04 {
            
          @Test
          public void test01(){
              AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
              UserService userService = context.getBean("userService", UserService.class);
              System.out.println(userService);
              userService.add();
          }
      }
      

五、AOP

1、什么是AOP

  • 面向切面编程(切面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之前的

    耦合度降低,提供程序的可重用性,同时提高开发效率

  • 通俗描述:不通过修改源码方式,在主干功能里面添加新功能

  • 使用登录例子说明AOP

image-20220331153238439

2、AOP(底层原理)

  1. 有两种情况动态代理

    • 第一种 有接口情况,使用JDK动态代理

      • 创建接口实现类代理对象,增强类的方法

    • 第二种 没有接口情况,使用CGLIB动态代理

      • 创建子类的代理对象,增强类的方法

        image-20220331153845690

3、AOP(JDK动态代理)

  1. 使用JDK动态代理,使用proxy类里面的方法创建代理对象

    Java.lang.reflect

    Class Proxy

    java.lang.Object

    ​ Java.lang.reflect.Proxy

    • 调用newProxyInstance方法

      1
      2
      
      static Object  newProxyInstance(ClassLoader loader<?> interfaces, InvocationHandle h)
          返回指定接口的代理类实例该接口将方法调用分派给指定的调用处理程序
      

      方法有三个参数:

      • 第一个参数,类加载器
      • 第二个参数,增强方法所在的类,这个类实现的接口,支持多个接口
      • 第三个参数,实现这个接口InvocationHandle,创建代理对象,写增强的部分
  2. 编写JDK动态代理代码

    • 创建接口,定义方法

      1
      2
      3
      4
      5
      6
      
      package top.withlevi.spring5.dao;
      public interface HelloDao {
          public int add(int a, int b);
          public String update(String id);
      }
           
      
    • 创建接口实现类,实现方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
      package top.withlevi.spring5.dao;
      public class HelloDaoImple implements HelloDao{
          @Override
          public int add(int a, int b) {
              System.out.println("add method execute...");
              return a + b;
          }
           
          @Override
          public String update(String id) {
              System.out.println("update method execute....");
              return id;
          }
      }
           
      
    • 使用Proxy类创建接口代理对象

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      
      package top.withlevi.spring5.dao;
           
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      import java.util.Arrays;
           
      /**
       * Created by Levi Zhao on 3/31/2022 4:07 PM
       *
       * @Author Levi
       */
      public class JDKProxy {
          public static void main(String[] args) {
              Class[] interfaces = {HelloDao.class};
                   
              HelloDaoImple helloDaoImple = new HelloDaoImple();
           
              HelloDao dao = (HelloDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(helloDaoImple));
              String hello_word = dao.update("Hello Word");
              System.out.println(hello_word);
              //int result = dao.add(3, 5);
              //System.out.println("result: "+result);
           
          }
      }
           
           
      class UserDaoProxy implements InvocationHandler {
          private Object obj;
           
          public UserDaoProxy(Object obj) {
              this.obj = obj;
          }
           
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              // execute before
              System.out.println("before executing method..." + method.getName() + " :Send args..." + Arrays.toString(args));
           
              if (method.getName().equals("add")) {
                  System.out.println("Strengthen add method");
              }else if (method.getName().equals("update")){
                  System.out.println("Strengthen update method");
              }
              // Strengthening method
              Object res = method.invoke(obj, args);
              // method execute after
              System.out.println("After executing method");
              return res;
          }
      }
           
      

4、AOP(术语)

  1. 连接点

    类里面哪些方法可以被增强,这些方法称为连接点

  2. 切入点

    实际被真正增强的方法,称为切入点

  3. 通知(增强)

    • 实际增强的逻辑不发称为通知(增强)
    • 通知有多种类型
      • 前置通知
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
  4. 切面

    是动作

    • 把通知应用到切入点过程

5、AOP操作(准备工作)

  1. spring框架一般都是基于AspectJ实现AOP操作

    • AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行

      AOP操作

  2. 基于AspectJ实现AOP操作

    • 基于xml配置文件实现
    • 基于注解方式实现(实用)
  3. 在项目工程里面引入AOP相关依赖

    image-20220402102047881

  4. 切入点表达式

    1. 切入点表达式作用: 知道对哪个类里面的哪个方法进行增强
    2. 语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])

    举例1:对top.withlevi.bean.User类里面的ad进行增强

    1
    
    execution(* top.withlevi.bean.User.add(..))
    

    举例2:对top.withlevi.bean类里面的所有的方法进行增强

    1
    
    execution(* top.withlevi.bean.User.*(..))
    

    举例3:对top.withlevi.bean包里面所有类,类里面所有方法进行增强

    1
    
    execution(* top.withlevi.bean.User.*.*(..))
    

5、AOP操作(AspectJ注解)

5.1、创建类,在类里面定义方法
1
2
3
4
5
6
7
8
9
10
11
package top.withlevi.bean;

import org.springframework.stereotype.Component;

@Component
public class User {
    public void add(){
        System.out.println("add........");
    }
}

5.2、创建增强类(编写增强逻辑)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 在增强类里面,创建方法,让不同方法代表不同通知类型
package top.withlevi.proxy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/4/2 10:25 AM
 */

@Component
@Aspect  // Generating proxy objects
public class UserProxy {

    @Pointcut(value = "execution(* top.withlevi.bean.User.add(..))")
    public void pointCut(){

    }

    // @Before Notification of annotation mark predecessors
    @Before(value = "pointCut()")
    public void before() {  //Pre notic
        System.out.println("before........");
    }

    // @AfterReturning Annotated logo post notification
    @AfterReturning("execution(* top.withlevi.bean.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning.......");
    }

    // @After annotated of final notification
    @After(value = "execution(* top.withlevi.bean.User.add(..))")
    public void after() {
        System.out.println("after.....");
    }

    // @AfterThrowing Exception notication
    @AfterThrowing(value = "execution(* top.withlevi.bean.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing......");
    }

    @Around(value = "execution(* top.withlevi.bean.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around before.....");

        proceedingJoinPoint.proceed();
        System.out.println("Around after......");
    }


}

5.3、进行通知的配置
  1. 在spring配置文件中,开启注解扫描

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    <?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"
           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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
       
       
        <!--Enable auto scan-->
        <context:component-scan base-package="top.withlevi"/>
       
        <!--Auto aspectj generate proxy object-->
        <aop:aspectj-autoproxy/>
       
       
       
       
    </beans>
    
  2. 使用注解创建User和UserProxy对象

    1
    2
    3
    4
    5
    
    // 被增强的类
    @Component
    Public class User{
         
    }
    

    ```java // 增强类 @Component public class UserProxy{

}

1
2
3
4
5
6
7
8
9
10
11
   

3. 在增强类上面添加注解@Aspect

   ```java
   @Component
   @Aspect // 生成代理对象
   public class UserProxy{
     
   }
  1. 在spring配置文件中开启生成代理对象

    1
    2
    3
    
     <!--Auto aspectj generate proxy object-->
        <aop:aspectj-autoproxy/>
       
    
5.4、配置不同类型的通知
  • 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package top.withlevi.proxy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect  // Generating proxy objects
public class UserProxy {

    @Pointcut(value = "execution(* top.withlevi.bean.User.add(..))")
    public void pointCut(){

    }

    // @Before Notification of annotation mark predecessors
    @Before(value = "pointCut()")
    public void before() {  //Pre notic
        System.out.println("before........");
    }

    // @AfterReturning Annotated logo post notification
    @AfterReturning("execution(* top.withlevi.bean.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning.......");
    }

    // @After annotated of final notification
    @After(value = "execution(* top.withlevi.bean.User.add(..))")
    public void after() {
        System.out.println("after.....");
    }

    // @AfterThrowing Exception notication
    @AfterThrowing(value = "execution(* top.withlevi.bean.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing......");
    }

    @Around(value = "execution(* top.withlevi.bean.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Around before.....");

        proceedingJoinPoint.proceed();
        System.out.println("Around after......");
    }


}

5.5、相同的切入点抽取
1
2
3
4
5
// 相同切入点抽取
@Pointcut(value = "execution(* top.withlevi.bean.User.add(..))")
    public void pointCut(){

    }
1
2
3
4
5
// @Before Notification of annotation mark predecessors
    @Before(value = "pointCut()")
    public void before() {  //Pre notic
        System.out.println("before........");
    }
5.6、有多个增强类同一个方法进行增强,设置增强类优先级
  • 在增强类上面添加注解@Order(数字型值),数字类型值越小优先级越高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package top.withlevi.proxy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(1)
public class PersonProxy {

    @Pointcut(value = "execution(* top.withlevi.bean.User.add(..))")
    public void pointCut(){

    }

    @Before(value = "pointCut()")
    public void before(){
        System.out.println("PersonProxy----before");
    }
}

5.7、完全使用注解开发
  • 创建配置类,不需要创建xml配置文件
1
2
3
4
5
6
7
8
9
10
11
12
package top.withlevi.proxy;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = {"top.withlevi"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MyConfig  {
}

6、AOP操作(AspectJ配置文件)

  1. 创建两个类,增强类和被增强类,创建方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    package top.withlevi.bean;
       
    import com.sun.scenario.effect.impl.sw.java.JSWBlend_SRC_OUTPeer;
    import org.springframework.stereotype.Component;
    public class Book {
        public void buy(){
            System.out.println("buy book");
        }
    }
       
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    package top.withlevi.proxy;
       
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    public class BookProxy {
        public void before(){
            System.out.println("BookProxy.....");
        }
    }
       
    
  2. 在spring配置文件中创建两个类对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    <?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
       
        <!--Create bean object-->
        <bean id="book" class="top.withlevi.bean.Book"></bean>
       
        <bean id="bookProxy" class="top.withlevi.proxy.BookProxy"/>
       
        <aop:config>
            <aop:pointcut id="p" expression="execution(* top.withlevi.bean.Book.buy(..))"/>
       
            <aop:aspect ref="bookProxy">
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
       
       
    </beans>
    
  3. 在spring配置文件中配置切入点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
       
        <!--Create bean object-->
        <bean id="book" class="top.withlevi.bean.Book"></bean>
       
        <bean id="bookProxy" class="top.withlevi.proxy.BookProxy"/>
       
        <aop:config>
            <aop:pointcut id="p" expression="execution(* top.withlevi.bean.Book.buy(..))"/>
       
            <aop:aspect ref="bookProxy">
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
       
    </beans>
    

六、JdbcTemplate(概念和准备)

1、什么是JdbcTemplate

  • Spring框架对JDBC进行封装,使用JdbcTemplate

2、准备工作和配置运行

  1. 引入相关jar包

    Druid-1.1.9.jar

    mysql-connector-java-5.1.7-bin.jar

    spring-jdbc-5.3.15.jar

    spring-orm-5.3.15.jar

    spring-tx-5.3.15.jar

  2. 在外部创建jdbc.properties

    1
    2
    3
    4
    
    prop.driverClassName=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/levi
    prop.username=root
    prop.password=root123456
    
  3. 在spring配置文件配置相关数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    <?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
           http://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="top.withlevi"/>
       	
          <--数据库连接池-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
       
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="driverClassName" value="${prop.driverClassName}"/>
            <property name="url" value="${prop.url}"/>
            <property name="username" value="${prop.username}"/>
            <property name="password" value="${prop.password}"/>
        </bean>
    		<--配置JdbcTemplate对象,注入DataSource-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
       
    </beans>
    
  4. 创建dao类、创建service类、创建daoimple类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    
    package top.withlevi.dao;
       
    import top.withlevi.bean.Order;
       
    import java.util.List;
       
    /**
     * @author Levi.Zhao
     * @version 1.0
     * @date 2022/4/2 9:20 PM
     */
       
    public interface OrderDao  {
        /**
         * Add Order
         * @param order
         */
        public void addOrder(Order order);
       
        /**
         * Update Order
         * @param order
         */
        public void updeteOrder(Order order);
       
        /**
         * Delete Order
         * @param id
         */
        public void deleteOrder(String id);
       
        /**
         * Count All Order Sum
         * @return
         */
        public int countOrder();
       
        /**
         * Query Order
         * @param id
         * @return
         */
        public Order queryOrder(String id);
       
        /**
         * Query all orders
         * @return
         */
        public List<Order> queryAllOrder();
       
        /**
         * Batch Add Orders
         * @param batchArgs
         */
        public void batchAddOrder(List<Object[]> batchArgs);
       
        /**
         * Batch Update Orders
         * @param batchArgs
         */
        public void batchUpdateOrder(List<Object[]> batchArgs);
       
        /**
         * Batch Delete Orders
         * @param batchArgs
         */
        public void batchDeleteOrder(List<Object[]> batchArgs);
       
    }
       
    

    daoimple类

    ```java package top.withlevi.dao;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import top.withlevi.bean.Order;

import java.util.Arrays; import java.util.List;

/**

  • @author Levi.Zhao
  • @version 1.0
  • @date 2022/4/2 9:22 PM */

@Repository public class OrderDaoImple implements OrderDao{

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@Autowired
private JdbcTemplate jdbcTemplate;

@Override
public void addOrder(Order order) {

    String sql = "insert into t_order values(?,?,?)";

    Object[] args = {order.getOrderId(),order.getOrderName(),order.getOrderPrice()};

    int update = jdbcTemplate.update(sql, args);

    if (update>0){
        System.out.println("insert successful....");
    }
    System.out.println(update);

}

@Override
public void updeteOrder(Order order) {
    String sql = "update t_order set ordername = ?, orderprice=? where orderid=?";
    Object[] args = {order.getOrderName(),order.getOrderPrice(),order.getOrderId()};
    int update = jdbcTemplate.update(sql, args);
    if (update>0){
        System.out.println("update successful.");
    }
    System.out.println(update);
}

@Override
public void deleteOrder(String id) {
    String sql = "delete from t_order where orderid=?";
    int update = jdbcTemplate.update(sql, id);
    if (update>0){
        System.out.println("Delete order successful");
    }
    System.out.println(update);
}

@Override
public int countOrder() {
    String sql = "select count(*) from t_order";
    Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
    return count;

}

@Override
public Order queryOrder(String id) {
    String sql = "select * from t_order where orderid=?";
    Order order = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Order>(Order.class),id);
    return order;
}

@Override
public List<Order> queryAllOrder() {
    String sql = "select * from t_order";
    List<Order> queryAll = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Order>(Order.class));
    return queryAll;
}

@Override
public void batchAddOrder(List<Object[]> batchArgs) {
    String sql = "insert into t_order values(?,?,?)";
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));
}

@Override
public void batchUpdateOrder(List<Object[]> batchArgs) {
    String sql = "update t_order set ordername=?,orderprice=? where orderid=?";
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints));

}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

   创建service类

   ```java
package top.withlevi.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.withlevi.bean.Order;
import top.withlevi.dao.OrderDao;

import java.util.List;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/4/2 9:27 PM
 */

@Service
public class OrderService {

    @Autowired
    private OrderDao orderDao;

    public void addOrder(Order order){
        orderDao.addOrder(order);
    }

    public void updateOrder(Order order){
        orderDao.updeteOrder(order);
    }

    public void deleteOrder(String id){
        orderDao.deleteOrder(id);
    }

    public int countOrder(){
       return orderDao.countOrder();
    }

    public Order queryOrder(String id){
        return orderDao.queryOrder(id);
    }

    public List<Order> queryAllOrder(){
        return orderDao.queryAllOrder();
    }

    public void batchAddOrder(List<Object[]> batchArgs){
        orderDao.batchAddOrder(batchArgs);
    }

    public void batchUpdateOrder(List<Object[]> batchArgs){
        orderDao.batchUpdateOrder(batchArgs);
    }

    public void batchDeleteOrder(List<Object[]> batchArgs){
        orderDao.batchDeleteOrder(batchArgs);
    }


}

  1. JdbcTemplate操作数据库(添加)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    package top.withlevi.bean;
       
    /**
     * @author Levi.Zhao
     * @version 1.0
     * @date 2022/4/2 8:30 PM
     */
    public class Order {
        private String orderId;
        private String orderName;
        private double orderPrice;
       
        public Order() {
        }
       
        public Order(String orderId, String orderName, double orderPrice) {
            this.orderId = orderId;
            this.orderName = orderName;
            this.orderPrice = orderPrice;
        }
       
        public String getOrderId() {
            return orderId;
        }
       
        public void setOrderId(String orderId) {
            this.orderId = orderId;
        }
       
        public String getOrderName() {
            return orderName;
        }
       
        public void setOrderName(String orderName) {
            this.orderName = orderName;
        }
       
        public double getOrderPrice() {
            return orderPrice;
        }
       
        public void setOrderPrice(double orderPrice) {
            this.orderPrice = orderPrice;
        }
       
        @Override
        public String toString() {
            return "Order{" +
                    "orderId='" + orderId + '\'' +
                    ", orderName='" + orderName + '\'' +
                    ", orderPrice='" + orderPrice + '\'' +
                    '}';
        }
    }
       
    
  2. 编写测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    
    package top.withlevi.test;
       
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import top.withlevi.bean.Order;
    import top.withlevi.service.OrderService;
       
    import java.util.ArrayList;
    import java.util.List;
       
    /**
     * @author Levi.Zhao
     * @version 1.0
     * @date 2022/4/2 9:30 PM
     */
       
       
    public class OrderTest {
       
       
        @Test
        public void testAdd(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            orderService.addOrder(new Order("7","HomePod",799));
       
        }
       
       
       
        @Test
        public void testUpdate(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            orderService.updateOrder(new Order("3","iPhone13",5999));
        }
       
        @Test
        public void testDelete(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            orderService.deleteOrder("7");
        }
       
       
        @Test
        public void testCount(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            int i = orderService.countOrder();
            System.out.println("Total order: "+i);
        }
       
       
        @Test
        public void testQuery(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            Order order = orderService.queryOrder("2");
            System.out.println(order);
        }
       
       
        @Test
        public void testQueryAllOrder(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            List<Order> orders = orderService.queryAllOrder();
            System.out.println(orders);
        }
       
        @Test
        public void testBatchAddOrder() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            List<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"1","iPhone 13 Pro","8599"};
            Object[] o4 = {"4","HomePod","799"};
            Object[] o8 = {"7","iPhone 13 Pro Max","12999"};
       
            batchArgs.add(o1);
            batchArgs.add(o4);
            batchArgs.add(o8);
       
            orderService.batchAddOrder(batchArgs);
        }
       
       
        @Test
        public void testBatchUpdateOrder() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            List<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"iPhone 13 Pro","8499","1"};
            Object[] o4 = {"HomePod","699","4",};
            Object[] o8 = {"iPhone 13 Pro Max","13899","7"};
       
            batchArgs.add(o1);
            batchArgs.add(o4);
            batchArgs.add(o8);
       
            orderService.batchUpdateOrder(batchArgs);
        }
       
       
       
        @Test
        public void testBatchDeleteOrder() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean03.xml");
            OrderService orderService = context.getBean("orderService", OrderService.class);
            List<Object[]> batchArgs = new ArrayList<>();
            Object[] o1 = {"1"};
            Object[] o4 = {"4",};
            Object[] o8 = {"7"};
       
            batchArgs.add(o1);
            batchArgs.add(o4);
            batchArgs.add(o8);
       
            orderService.batchDeleteOrder(batchArgs);
        }
    }
       
    

七、事务操作(事务概念)

1、什么是事务

  1. 事务是数据库操作最基本单元,逻辑上一组操作,要么成功,如果有一个失败所有操作都失败
  2. 典型场景: 银行转账
    • lucy转账100元给mary
    • lucy账户少100,mary多100

2、事务四个特效(ACID)

  1. 原子性
  2. 一致性
  3. 隔离性
  4. 持久性

3、事务操作(搭建事务操作环境)

Dao层

数据库操作不写业务

创建两个方法

  1. 少钱的方法
  2. 多钱的方法

Service层

业务操作

创建转账的方法

  1. 调用dao两个的方法
3.1、创建数据库,添加记录
mysql> select * from t_transaction;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |  1000 |
|  2 | mary     |  1000 |
+----+----------+-------+
2 rows in set (0.00 sec)
3.2、创建Dao和Service,完成对象创建和注入关系

TransactionDao.java

1
2
3
4
5
6
7
8
9
package top.withlevi.dao;
public interface TransactionDao {

    public void reduceMoney();

    public void addMoney();

}

TransactionDaoImple.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package top.withlevi.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class TransactionDaoImpl implements TransactionDao {


    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void reduceMoney() {
        String sql = "update t_transaction set money=money -? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }

    @Override
    public void addMoney() {
        String sql = "update t_transaction set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"marry");
    }


}

TransactionService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// service注入dao,在dao注入Jdbctemplate 在JdcbTemplate注入DataSource
package top.withlevi.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import top.withlevi.dao.TransactionDao;



@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class TransactionService {
		// 注入Dao
    @Autowired
    private TransactionDao transactionDao;

    public void accountMoney(){
        transactionDao.reduceMoney();

        //int i  = 10/0;

        transactionDao.addMoney();
    }

}

4、事务的操作(Spring事务管理介绍)

  1. 事务添加到JavaEE三层结构里面Service层(业务逻辑层)

  2. 在spring进行事务管理操作

    • 有两种方式: 编程式事务管理和声明式事务管理(使用)
  3. 声明式事务管理

    1. 基于注解方式(使用)
    2. 基于xml配置文件方式
  4. 在spring进行声明式事务管理,底层使用AOP原理

  5. spring事务管理API

    1. 提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

      image-20220405131051684

5、事务操作(注解声明式事务操作)

  1. 在spring配置文件配置事务管理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    <?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" 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/context
           https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
       
    		<--扫描组件-->
        <context:component-scan base-package="top.withlevi"/>
       
       
      <--引入外部数据库配置文件-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
       
        <--创建数据库连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="driverClassName" value="${prop.driverClassName}"/>
            <property name="url" value="${prop.url}"/>
            <property name="username" value="${prop.username}"/>
            <property name="password" value="${prop.password}"/>
        </bean>
       
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
       
        <!--创建事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
           <!--注入数据源-->
            <property name="dataSource" ref="dataSource"/>
        </bean>
       
        <!--开启事务注解-->
       <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
       
       
    </beans>
    
  2. jdbc.properties

    1
    2
    3
    4
    
    prop.driverClassName=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/levi
    prop.username=root
    prop.password=root123456
    
  3. 在service类上面(或者service类里面方法上面)添加事务注解

    • @Transactional,这个注解添加到类上面,也可以添加方法上面
    • 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
    • 如果把这个注解添加方法上面,为这个方法添加事务
    1
    2
    3
    4
    5
    
    @Service
    @Transactional
    public class Transaction{
         
    }
    

6、事务操作(声明式事务管理参数配置)

  1. 在service类上面添加@Transactional,在这个注解里面可以配置事务相关参数

    image-20220405132224873

  2. propagation:事务传播行为

    1. 多事务方法直接进行调用,这个过程中事务是如何进行管理的

      事务传播行为:以下Spring定义了7中传播行为。

      image-20220405132440508

      1
      2
      3
      4
      5
      
      @Service
      @Transactional(propagation = Propagation.REQUIRED)
      public class Transaction(){
              
      }
      
  3. Ioslation: 事务隔离级别

    1. 事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

    2. 有三个读问题:脏读,不可重复读,虚(幻)读

    3. 脏读:一个未提交事务读取到另一个未提交事务的数据

      image-20220405132940672

    4. 不可重复读:一个未提交事务读取到另一个事务修改数据

      image-20220405133021859

    5. 虚读: 一个未提交事务读取到另一提交事务添加数据

    6. 解决:通过设置事务隔离级别,解决读问题

      image-20220405133128521

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
      @Service
      @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
      public class TransactionService {
            
          @Autowired
          private TransactionDao transactionDao;
            
          public void accountMoney(){
              transactionDao.reduceMoney();
            
              //int i  = 10/0;
            
              transactionDao.addMoney();
          }
            
      }
            
      
  4. timeout: 超时时间

    1. 事务需要在一定时间内进行提交,如果不提交进行回滚
    2. 默认值是-1,设置时间以秒单位进行计算
  5. readOnly:是否只读

    1. 读:查询操作,写: 添加修改删除操作
    2. readOnly默认值:false, 表示可以查询,可以添加修改删除操作
    3. 设置readOnly值是true,设置true之后,只能查询
  6. rollbackFor: 回滚

    1. 设置出现哪些异常进行事务回滚
  7. noRollbackFor:不回滚

    1. 设置出现哪些异常不进事务回滚

7、事务操作(XML声明式事务管理)

  1. 在spring配置文件中进行配置

    • 第一步 配置事务管理器
    • 第二步 配置通知
    • 第三步 配置切入点和切面
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    <?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"
           xmlns:tx="http://www.springframework.org/schema/tx" 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 https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
       
        <context:component-scan base-package="top.withlevi"/>
       
        <!--引入外部数据库配置文件-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
       
        <!--数据库连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="driverClassName" value="${prop.driverClassName}"/>
            <property name="url" value="${prop.url}"/>
            <property name="username" value="${prop.username}"/>
            <property name="password" value="${prop.password}"/>
        </bean>
       
        <!--JdbcTemplate对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
       
        <!--注入dataSource-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"/>
        </bean>
       
        <!--配置通知-->
        <tx:advice id="txadvice">
            <!--配置事务参数-->
            <tx:attributes>
                <!--指定哪种规则的方法上面添加事务-->
                <tx:method name="accountMoney" propagation="REQUIRED"/>
       
          <!--      <tx:method name="account*"/>-->
            </tx:attributes>
        </tx:advice>
       
        <!--配置切入点和切面-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="pt" expression=" execution(* top.withlevi.service.TransactionService.*(..))"/>
            <!--配置切面-->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
        </aop:config>
       
    </beans>
    

    TransactionService.java

    ```java package top.withlevi.service;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import top.withlevi.dao.TransactionDao;

@Service // 如果使用xml声明式事务管理就需要把 Transactional注释掉 //@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) public class TransactionService {

1
2
3
4
5
6
7
8
9
10
@Autowired
private TransactionDao transactionDao;

public void accountMoney(){
    transactionDao.reduceMoney();

    //int i  = 10/0;

    transactionDao.addMoney();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


8、事务操作(完全注解声明式事务管理)

```java
package top.withlevi.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * @author Levi.Zhao
 * @version 1.0
 * @date 2022/4/5 11:17 AM
 */
@Configuration  // 配置类
@ComponentScan(basePackages = "top.withlevi") // 组件扫描
@EnableTransactionManagement  // 开启事务
public class TxConfig {

    // Create connect database pool

    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///levi");
        dataSource.setUsername("root");
        dataSource.setPassword("root123456");
        return dataSource;
    }

    // Create JdbcTemplate Object

    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        // Find dataSource in IOC container by type
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    // Create transactional
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }



}

八、spring5框架新功能

  1. 整个spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

  2. Spring5.0框架自带了通用的日志封装

    1. spring5已经移出Log4JConfigListener,官方建议使用Log4j2
    2. spring5框架整合Log4j2

    第一步引入jar包

    image-20220405200517226

    第二步 创建log4j2.xml配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
    <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>
    
  3. spring5框架核心容器支持@Nullable注解

    1. @Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空

      参数值可以为空。

    2. 注解用在方法上面,方法返回值可以为空

    1
    2
    
    @Nullable
    String getId();
    
    1. 注解使用在属性上面,属性值可以为空
    1
    2
    
    @Nullable
    private String bookName;
    
  4. spring5核心容器支持函数式风格GenericApplicationContext

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    // 函数式风格创建对象,交给spring进行管理
        @Test
        public void test04(){
          // 创建GenericApplicationContext对象
            GenericApplicationContext context = new GenericApplicationContext();
          // 调用context的方法对象注册
            context.refresh();
            context.registerBean("user", User.class,()->new User());
          // 获取在spring注册的对象
            User user = (User)context.getBean("user");
            user.add();
            System.out.println(user);
        }
    
  5. spring5支持整合JUnit5

    1. 整合JUnit4

    第一步引入spring相关针对测试依赖

    image-20220405215445610

    第二步创建测试类,使用注解方式完成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    package top.withlevi.testcode;
       
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import top.withlevi.service.TransactionService;
       
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:bean01.xml")
    public class JTest4 {
       
        @Autowired
        private TransactionService transactionService;
       
        @Test
        public void test01(){
            transactionService.accountMoney();
        }
       
    }
       
    
    1. spring5整合Junit5

      • 第一步 引入Junit5的jar包

        import org.junit.jupiter.api.Test;

      • 第二步 创建测试类

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        
        package top.withlevi.testcode;
                
                
                
        import org.junit.jupiter.api.Test;
        import org.junit.jupiter.api.extension.ExtendWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.test.context.ContextConfiguration;
        import org.springframework.test.context.junit.jupiter.SpringExtension;
        import top.withlevi.service.TransactionService;
                
        @ExtendWith(SpringExtension.class)
        @ContextConfiguration("classpath:bean01.xml")
        public class JTest5 {
                
            @Autowired
            private TransactionService transactionService;
                
            @Test
            public void test01(){
                transactionService.accountMoney();
            }
        }
                
        
    2. 使用一个复合注解替代上面两个注解完成整合

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      
      package top.withlevi.testcode;
      import org.junit.jupiter.api.Test;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
      import top.withlevi.service.TransactionService;
            
      @SpringJUnitConfig(locations = "classpath:bean01.xml")
      public class JTest5_1 {
            
          @Autowired
          private TransactionService transactionService;
            
          @Test
          public void test1(){
              transactionService.accountMoney();
          }
      }