• Spring5复习笔记


    0. Spring架构

    Spring5模块

    1. 内容介绍

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

    2. Spring 框架概述

    1. Spring是轻量级开源的JavaEE框架
    2. Spring可以解决企业开发的复杂性
    3. Spring有两个核心部分:IOC和AOP
      • IOC :控制反转,把创建对象的过程交给Spring进行管理
      • Aop :面向切面,不修改代码进行功能增强
    4. Spring 特点
      1. 方便解耦,简化开发
        • IOC控制反转解耦对象对象之间的耦合
      2. Aop编程支持
      3. 方便程序测试
        • 集成的Junit,方便对程序进行单元测试
      4. 方便与其他框架进行整合
      5. 方便进行事务操作
        • 简化了对声明式事务的操作
      6. 降低API开发难度

    3. Spring 入门案例

    3.1 下载Spring5

    1. 使用Spring 最新稳定版本5.2.6

    image-20220719135108157

    1. 下载地址

    image-20220719135204160

    image-20220719135230623

    3.2 打开idea工具,创建java工程

    image-20220719135313530

    image-20220719135327133

    image-20220719135340176

    3.3 导入Spring5相关基本jar包

    image-20220719135421001

    image-20220719135432135

    image-20220719135449002

    3.4 创建普通类,在这个类创建普通方法

    public class User {
        public void add() {
            System.out.println("add......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.5 创建Spring配置文件,在配置文件配置创建对象

    1. Spring 配置文件使用xml格式

    image-20220719135711304

    bean1

    
    <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.xsd">
    
     
     <bean id="user" class="com.atguigu.spring5.User">bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.6 进行测试代码编写

    package com.atguigu.spring5.testdemo;
    
    import com.atguigu.spring5.Book;
    import com.atguigu.spring5.Orders;
    import com.atguigu.spring5.User;
    import org.junit.Test;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestSpring5 {
    
        @Test
        public void testAdd() {
            //1 加载spring配置文件
            BeanFactory context =
                    new ClassPathXmlApplicationContext("bean1.xml");
    
            //2 获取配置创建的对象
            User user = context.getBean("user", User.class);
    
            System.out.println(user);
            user.add();
        }
    }
    
    
    • 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

    测试结果

    image-20220719140249803

    4. IOC容器

    4.1 IOC(概念和原理)

    4.1.1 什么是IOC?

    1. 控制反转,把对象创建和对象之间的调用过程交给Spring进行管理
    2. 使用IOC的目的:为了降低耦合度
    3. 做入门案例就是IOC实现

    4.1.2 IOC底层原理

    • xml解析
      • 使用xml解析解析xml配置文件中的配置信息
    • 工厂模式
      • 使用工厂来创建对象
    • 反射
      • 工厂中实际创建对象的方式,利用反射的Class.forName()方法创建对象

    4.1.3 画图讲解IOC底层原理

    image-20220719140954260

    4.2 IOC(BeanFactory接口)

    1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
    2. Spring提供IOC容器实现两种方式:(两个接口)
      1. BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
        • 加载配置文件时候不会创建对象,在获取对象(使用)时才会去创建对象
      2. ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
        • 加载配置文件时就会把在配置文件对象进行创建-让对象在程序启动时创建,这样只会使程序启动时间较长,如果在获取对象(使用)时才会去创建对象,此时会使用户的等待时间变长不利于交互
    3. ApplicationContext接口有有实现类

    image-20220719142647239

    4.3 IOC操作Bean管理

    4.3.1 概念

    4.3.1.1 什么是Bean管理?

    1. Bean管理值的是两个操作
    2. Spring创建对象
    3. Spring属性注入

    4.3.1.2 Bean管理操作有两种方式

    1. 基于xml配置文件方式实现
    2. 基于注解方式实现

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

    4.3.2.1 基于xml方式创建对象

        
        <bean id="user" class="com.atguigu.spring5.User">bean>
    
    • 1
    • 2
    1. 在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建

    2. 在bean标签有很多,介绍常用的属性

      • id属性: 唯一标识,一般使用类名首字母小写命名
      • class属性: 类的全路径,该属性值用于反射时创建对象
    3. 创建对象时,默认也是执行无参构造方法完成对象创建

    4.3.2.2 基于xml方式注入属性DI

    1. DI:依赖注入,也就是属性注入

    4.3.2.3 注入方式一-使用set方法进行注入

    1. 创建类,定义属性和属性对应的set方法

      package com.atguigu.spring5;
      
      /**
       * 演示使用set方法进行注入属性
       */
      public class Book {
          //创建属性
          private String bname;
          private String bauthor;
          //创建属性对应的set方法
          public void setBname(String bname) {
              this.bname = bname;
          }
          public void setBauthor(String bauthor) {
              this.bauthor = bauthor;
          }
          /打印属性-用于测试属性是否注入成功
          public void testDemo() {
              System.out.println(bname+"::"+bauthor);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    2. 在spring配置文件配置对象创建,配置属性注入

      	
          <bean id="book" class="com.atguigu.spring5.Book">
                      
              <property name="bname" value="易筋经">property>
              <property name="bauthor" value="达摩老祖">property>
          bean>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    3. 测试代码及结果

      @Test
          public void testBook1() {
              //1 加载spring配置文件
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("bean1.xml");
      
              //2 获取配置创建的对象
              Book book = context.getBean("book", Book.class);
      
              System.out.println(book);
              book.testDemo();
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      image-20220719144725664

    4.3.2.4 注入方式二-使用有参构造进行注入

    1. 创建类,定义属性,创建属性对应的有参构造方法

      package com.atguigu.spring5;
      
      /**
       * 使用有参数构造注入
       */
      public class Orders {
          //属性
          private String oname="";
          private String address;
          //有参数构造
          public Orders(String oname,String address) {
              this.oname = oname;
              this.address = address;
          }
      	//打印属性-用于测试属性是否注入成功
          public void ordersTest() {
              System.out.println(oname+"::"+address);
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    2. 在spring配置文件中进行配置

          
          <bean id="orders" class="com.atguigu.spring5.Orders">
              <constructor-arg name="oname" value="电脑">constructor-arg>
              <constructor-arg name="address" value="China">constructor-arg>
          bean>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    3. 测试代码及结果

          @Test
          public void testOrders() {
              //1 加载spring配置文件
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("bean1.xml");
      
              //2 获取配置创建的对象
              Orders orders = context.getBean("orders", Orders.class);
      
              System.out.println(orders);
              orders.ordersTest();
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      image-20220719144956144

    4.3.2.5 p名称空间注入(了解)

    名称空间注入本质上还是set方法注入,只是在xml配置中简化了写法

    1. 使用p名称空间注入,可以简化基于xml配置方式

      1. 第一步: 添加p名称空间在配置文件中

        
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:p="http://www.springframework.org/schema/p"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        • 1
        • 2
        • 3
        • 4
        • 5
      2. 第二步: 进行属性注入,在bean标签里进行操作

            
            <bean id="book" class="com.atguigu.spring5.Book" p:bname="九阳神功" p:bauthor="无名氏">
            bean>
        
        • 1
        • 2
        • 3
      3. 测试代码及结果

            @Test
            public void testBook1() {
                //1 加载spring配置文件
                ApplicationContext context =
                        new ClassPathXmlApplicationContext("bean1.xml");
        
                //2 获取配置创建的对象
                Book book = context.getBean("book", Book.class);
        
                System.out.println(book);
                book.testDemo();
            }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12

        image-20220719145540279

    4.3.2.6 xml注入其他类型属性

    4.3.2.6.1 字面量
    4.3.2.6.1.1 null值
            
            <property name="address">
                <null/>
            property>
    
    • 1
    • 2
    • 3
    • 4
    4.3.2.6.1.2 属性值包含特殊符号
            
            <property name="address">
                <value>>]]>value>
            property>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.3.2.6.2 注入属性-外部bean
    1. 创建两个类service类和dao类
    2. 在service调用dao里面的方法
    3. 在spring配置文件中进行配置

    UserDao

    package com.atguigu.spring5.dao;
    
    public interface UserDao {
        public void update();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    UserDaoImpl

    package com.atguigu.spring5.dao;
    
    public class UserDaoImpl implements UserDao {
    
        @Override
        public void update() {
            System.out.println("dao update...........");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    UserService

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    import com.atguigu.spring5.dao.UserDaoImpl;
    
    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

    配置文件

    
    <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.xsd">
    
        
        <bean id="userService" class="com.atguigu.spring5.service.UserService">
            
            <property name="userDao" ref="userDaoImpl">property>
        bean>
        <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl">bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试类及结果

        @Test
        public void testBean1() {
            //1 加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean2.xml");
    
            //2 获取配置创建的对象
            UserService userService = context.getBean("userService", UserService.class);
    
            userService.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    image-20220719152435023

    4.3.2.6.3 注入属性-内部bean
    1. 一对多关系:部门和员工
      • 一个部门有多个员工,一个员工属于一个部门部门是一,员工是多
    2. 在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

    Dept

    package com.atguigu.spring5.bean;
    
    //部门类
    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

    Emp

    package com.atguigu.spring5.bean;
    
    import java.util.Arrays;
    
    //员工类
    public class Emp {
        private String ename;
        private String gender;
        //员工属于某一个部门,使用对象形式表示
        private Dept dept;
    
        //生成dept的get方法
        public Dept getDept() {
            return dept;
        }
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
        public void setEname(String ename) {
            this.ename = ename;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public void add() {
            System.out.println(ename+"::"+gender+"::"+dept);
        }
    }
    
    • 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

    配置文件

    
    <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.xsd">
    
        
        <bean id="emp" class="com.atguigu.spring5.bean.Emp">
            
            <property name="ename" value="lucy">property>
            <property name="gender" value="">property>
            
            <property name="dept">
                <bean id="dept" class="com.atguigu.spring5.bean.Dept">
                    <property name="dname" value="安保部">property>
                bean>
            property>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    测试类及结果

        @Test
        public void testBean3() {
            //1 加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean3.xml");
    
            //2 获取配置创建的对象
            Emp emp = context.getBean("emp", Emp.class);
    
            emp.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    image-20220719152816338

    4.3.2.6.4 注入属性-级联赋值写法一

    在4.3.2.6.4中的类基础上

    
    <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.xsd">
    
        
        <bean id="emp" class="com.atguigu.spring5.bean.Emp">
            
            <property name="ename" value="lucy">property>
            <property name="gender" value="">property>
            
            <property name="dept" ref="dept">property>
        bean>
        <bean id="dept" class="com.atguigu.spring5.bean.Dept">
            <property name="dname" value="财务部">property>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试类及结果

        @Test
        public void testBean2() {
            //1 加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean4.xml");
    
            //2 获取配置创建的对象
            Emp emp = context.getBean("emp", Emp.class);
    
            emp.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    image-20220719153831833

    4.3.2.6.4 注入属性-级联赋值写法二

    在4.3.2.6.4中的类基础上,需要先生成dept的get方法

    image-20220719153629942

    
    <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.xsd">
    
        
        <bean id="emp" class="com.atguigu.spring5.bean.Emp">
            
            <property name="ename" value="lucy">property>
            <property name="gender" value="">property>
            
            <property name="dept.dname" value="技术部">property>
        bean>
        <bean id="dept" class="com.atguigu.spring5.bean.Dept">
            <property name="dname" value="财务部">property>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试方法及结果(测试方法与4.3.2.6.4一致)

    image-20220719153410870

    4.3.2.7 xml注入集合属性

    4.3.2.7.1 注入数组,list,map,set类型属性

    创建类,定义数组,list,map,set类型属性,生成对应set方法

    package com.atguigu.spring5.collectiontype;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class Stu {
        //1 数组类型属性
        private String[] courses;
        //2 list集合类型属性
        private List<String> list;
        //3 map集合类型属性
        private Map<String,String> maps;
        //4 set集合类型属性
        private Set<String> sets;
    
        public void setSets(Set<String> sets) {
            this.sets = 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 test() {
            System.out.println(Arrays.toString(courses));
            System.out.println(list);
            System.out.println(maps);
            System.out.println(sets);
            System.out.println(courseList);
        }
    }
    
    • 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

    在spring配置文件进行配置

    
    <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.xsd">
    
        
        <bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
            
            <property name="courses">
                <array>
                    <value>java课程value>
                    <value>数据库课程value>
                array>
            property>
            
            <property name="list">
                <list>
                    <value>张三value>
                    <value>小三value>
                list>
            property>
            
            <property name="maps">
                <map>
                    <entry key="JAVA" value="java">entry>
                    <entry key="PHP" value="php">entry>
                map>
            property>
            
            <property name="sets">
                <set>
                    <value>MySQLvalue>
                    <value>Redisvalue>
                set>
            property>
        bean>
    beans>
    
    • 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

    测试类及结果

        @Test
        public void testCollection1() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
            Stu stu = context.getBean("stu", Stu.class);
            stu.test();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20220719154444285

    4.3.2.7.2 在集合中设置自定义对象类型值

    在4.3.2.7.2的Stu类基础上加上courseList属性,并加上set方法

    	//学生所学多门课程
        private List<Course> courseList;
        public void setCourseList(List<Course> courseList) {
            this.courseList = courseList;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Course

    package com.atguigu.spring5.collectiontype;
    
    //课程类
    public class Course {
        private String cname; //课程名称
        public void setCname(String cname) {
            this.cname = cname;
        }
    
        @Override
        public String toString() {
            return "Course{" +
                    "cname='" + cname + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    配置文件

    
    <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.xsd">
    
        
        <bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
            
            <property name="courses">
                <array>
                    <value>java课程value>
                    <value>数据库课程value>
                array>
            property>
            
            <property name="list">
                <list>
                    <value>张三value>
                    <value>小三value>
                list>
            property>
            
            <property name="maps">
                <map>
                    <entry key="JAVA" value="java">entry>
                    <entry key="PHP" value="php">entry>
                map>
            property>
            
            <property name="sets">
                <set>
                    <value>MySQLvalue>
                    <value>Redisvalue>
                set>
            property>
            
            <property name="courseList">
                <list>
                    <ref bean="course1">ref>
                    <ref bean="course2">ref>
                list>
            property>
        bean>
    
        
        <bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
            <property name="cname" value="Spring5框架">property>
        bean>
        <bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
            <property name="cname" value="MyBatis框架">property>
        bean>
    beans>
    
    • 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

    测试类与4.3.2.7.1中一致,结果

    image-20220719155058369

    4.3.2.7.3 把集合注入部分抽取出来

    提取集合的原因是,可能会有多个bean使用到相同的集合

    1. 在spring 配置文件中引入名称空间util

      image-20220719155440073

    2. 使用util标签完成list集合注入提取

      
      <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">
      
          
          <util:list id="bookList">
              <value>易筋经value>
              <value>九阴真经value>
              <value>九阳神功value>
          util:list>
      
          
          <bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype">
              <property name="list" ref="bookList">property>
          bean>
      beans>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

    4.3.2.8 注入工厂bean(FactoryBean)

    1. Spring有两种类型 bean,一种普通bean,另外一种工厂bean (FactoryBean)
    2. 普通bean:在配置文件中定义bean类型就是返回类型
    3. 工厂bean:在配置文件定义bean类型可以和返回类型不一样
    4.3.2.8.1 创建类,让这个类作为工厂bean,实现接口FactoryBean,并实现接口里的方法,在实现的方法中定义返回的bean类型
    package com.atguigu.spring5.factorybean;
    
    import com.atguigu.spring5.collectiontype.Course;
    import org.springframework.beans.factory.FactoryBean;
    
    public class MyBean implements FactoryBean<Course> {
    
        //定义返回bean
        @Override
        public Course getObject() throws Exception {
            Course course = new Course();
            course.setCname("abc");
            return course;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    
    • 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
    4.3.2.8.2 xml方式创建工厂bean
    
    <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">
    
        <bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    4.3.2.8.3 测试类及结果
        @Test
        public void test3() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean3.xml");
            Course course = context.getBean("myBean", Course.class);
            System.out.println(course);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20220719165500243

    4.3.2.9 bean的作用域

    4.3.2.9.1 在Spring中,默认情况下,bean是单例对象(验证)

    image-20220719165707505

        @Test
        public void testCollection2() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean2.xml");
            Book book1 = context.getBean("book", Book.class);
            Book book2 = context.getBean("book", Book.class);
           // book.test();
            System.out.println(book1);
            System.out.println(book2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    4.3.2.9.2 Spring中如何设置对象单例还是多例
    1. 在spring配置文件 bean标签里面有属性(scope)用于设置单实例还是多实例

    2. scope属性值

      • 第一个值默认值,singleton,表示是单实例对象

      • 第二个值prototype,表示是多实例对象

        image-20220719170033108

    4.3.2.9.3 singleton和prototype的区别
    • singleton单实例,prototype多实例
    • 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
    • 设置scope值是prototype时候,不是在加载spring 配置文件时候创建对象,在调用getBean方法时候创建多实例对象

    4.3.2.10 bean的生命周期

    生命周期:从对象创建到对象销毁的过程

    1. 通过构造器创建bean实例(无参数构造)
    2. 为bean的属性设置值和对其他bean引用(调用set方法)
    3. 调用bean的初始化的方法(需要进行配置初始化的方法)
    4. bean可以使用了(对象获取到了)
    5. 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
    4.3.2.10.1 演示bean生命周期
    package com.atguigu.spring5.bean;
    
    public class Orders {
    
        //无参数构造
        public Orders() {
            System.out.println("第一步 执行无参数构造创建bean实例");
        }
    
        private String oname;
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println("第二步 调用set方法设置属性值");
        }
    
        //创建执行的初始化的方法
        public void initMethod() {
            System.out.println("第三步 执行初始化的方法");
        }
    
        //创建执行的销毁的方法
        public void destroyMethod() {
            System.out.println("第五步 执行销毁的方法");
        }
    }
    
    • 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

    配置文件

    init-method配置初始化方法

    destroy-method配置销毁方法

        <bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
            <property name="oname" value="手机">property>
        bean>
    
    • 1
    • 2
    • 3

    测试类及结果

        @Test
        public void testBean3() {
    //        ApplicationContext context =
    //                new ClassPathXmlApplicationContext("bean4.xml");
            ClassPathXmlApplicationContext context =
                    new ClassPathXmlApplicationContext("bean4.xml");
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println("第四步 获取创建bean实例对象");
            System.out.println(orders);
    
            //手动让bean实例销毁
            context.close();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    image-20220720093130755

    4.3.2.10.2 bean的后置处理器,bean的生命周期有七步
    1. 通过构造器创建bean实例(无参数构造)
    2. 为bean的属性设置值和对其他 bean引用(调用set方法)
    3. 把bean 实例传递bean后置处理器的方法postProcessBeforeInitialization
    4. 调用bean的初始化的方法(需要进行配置初始化的方法)
    5. 把bean 实例传递bean后置处理器的方法postProcessAfterInitialization
    6. bean可以使用了(对象获取到了)
    7. 当容器关闭时候,调用bean 的销毁的方法(需要进行配置销毁的方法)

    bean的后置处理器:允许在调用初始化方法前后对 Bean 进行额外的处理。

    4.3.2.10.3 演示添加后置处理器效果

    在4.3.2.10.1的基础上新增了bean的后置处理器

    4.3.2.10.3.1 创建类,实现接口BeanPostProcessor,创建后置处理器
    package com.atguigu.spring5.bean;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.lang.Nullable;
    import org.springframework.util.SocketUtils;
    
    public class MyBeanPost implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("在初始化之前执行的方法");
            return bean;
        }
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("在初始化之后执行的方法");
            return bean;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    4.3.2.10.3.2 配置后置处理器
    
    <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">
    
        <bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
            <property name="oname" value="手机">property>
        bean>
    
        
        <bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost">bean>
    beans>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    4.3.2.10.3.3 测试类及结果

    测试类与4.3.2.10.1中的一致

    image-20220720093921121

    4.3.2.11 xml自动装配

    4.3.2.11.1 什么是自动装配?

    根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

    个人理解自动装配:在属性中依赖于其他bean时,就会自动根据类中定义的属性类型或者属性名称来寻找容器中的bean从而将其注入

    image-20220720152306666

    4.3.2.11.2 演示自动装配过程

    实现自动装配:

    • bean标签属性autowire,配置自动装配
      • autowire属性常用两个值:
        • byName根据属性名称注入 ,注入值bean的id值和类属性名称一样
        • byType根据属性类型注入

    Dept

    package com.atguigu.spring5.autowire;
    
    public class Dept {
        @Override
        public String toString() {
            return "Dept{}";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Emp

    package com.atguigu.spring5.autowire;
    
    public class Emp {
        private Dept dept;
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        @Override
        public String toString() {
            return "Emp{" +
                    "dept=" + dept +
                    '}';
        }
    
        public void test() {
            System.out.println(dept);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    4.3.2.11.3.1 根据属性类型自动注入

    xml配置

    
    <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">
    
        
        <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
            
        bean>
        <bean id="dept" class="com.atguigu.spring5.autowire.Dept">bean>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    测试类及结果

        @Test
        public void test4() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean5.xml");
            Emp emp = context.getBean("emp", Emp.class);
            System.out.println(emp);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20220720153821960

    4.3.2.11.3.2 根据属性名称自动注入

    xml配置

    
    <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">
    
        
        <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
            
        bean>
        <bean id="dept" class="com.atguigu.spring5.autowire.Dept">bean>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    测试类与4.3.2.11.3.1中一致及结果

    image-20220720154150021

    使用名称注入注意事项,注入的属性中的名称必须与bean的id一致不然会注入null

    image-20220720154516019

    错误示例:

    image-20220720154600061

    image-20220720154626215

    4.3.2.12 外部属性文件(以将数据库相关配置抽取至外部文件为例)

    4.3.2.12.1 直接配置数据库信息

    引入德鲁伊连接池依赖jar包

    image-20220720155144187

    直接配置连接池

    
    <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"
           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/util http://www.springframework.org/schema/util/spring-util.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver">property>
            <property name="url" value="jdbc:mysql://localhost:3306/mysql">property>
            <property name="username" value="root">property>
            <property name="password" value="root">property>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    4.3.2.12.2 引入外部属性文件配置数据库连接池
    1. 第一步同样需要引入依赖
    2. 创建外部属性文件,properties格式文件,写数据库信息
    prop.driverClass=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/mysql
    prop.userName=root
    prop.password=root
    
    • 1
    • 2
    • 3
    • 4

    把外部properties属性文件引入到spring配置文件中

    在这之前需要引入context名称空间

    
    <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"
           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/util http://www.springframework.org/schema/util/spring-util.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>
            <property name="url" value="${prop.url}">property>
            <property name="username" value="${prop.userName}">property>
            <property name="password" value="${prop.password}">property>
        bean>
    beans>
    
    • 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

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

    4.3.3.1 什么是注解?注解如何使用?为什么使用注解?

    • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
    • 使用注解,注解作用在类上面方法上面,属性上
    • 使用注解目的:简化 xml 配置

    4.3.3.2 Spring针对Bean管理中创建对象提供的注解

    • @Component
    • @Service
    • @Controller
    • @Repository

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

    @Component,@Service,@Controller,@Repository这几个注解如果Value不填Value的默认值就是类名的首字母小写,如果填了就以填写的值为准

    下面的三个主要用于区分不同层次的代码

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

    4.3.3.3.1 引入依赖

    需要先引入AOP依赖

    image-20220720160420204

    4.3.3.3.2 开启组件扫描
    
    <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"
           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/util http://www.springframework.org/schema/util/spring-util.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        
        <context:component-scan base-package="com.atguigu">context:component-scan>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    4.3.3.3.3 创建类,在类上面创建对象注解

    UserService

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    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.Controller;
    import org.springframework.stereotype.Repository;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    //在注解里面value属性值可以省略不写,
    //默认值是类名称,首字母小写
    //UserService -- userService
    @Component(value = "userService")  //
    public class UserService {
        public void add() {
            System.out.println("service add.......");
            userDao.add();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    UserDao及UserDaoImpl

    image-20220720161417747

    4.3.3.3.4 开启组件扫描细节配置
    
    <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"
           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/util http://www.springframework.org/schema/util/spring-util.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        
    
    
    
    
    
        <context:component-scan base-package="com.atguigu" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        context:component-scan>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.3.3.4 基于注解方式实现属性注入

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

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

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    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.Controller;
    import org.springframework.stereotype.Repository;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    //在注解里面value属性值可以省略不写,
    //默认值是类名称,首字母小写
    //UserService -- userService
    @Component(value = "userService")  //
    public class UserService {
    
        //定义dao类型属性
        //不需要添加set方法
        //添加注入属性注解
        @Autowired  //根据类型进行注入
        private UserDao userDao;
    
        public void add() {
            System.out.println("service add.......");
            userDao.add();
        }
    }
    
    
    • 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

    测试类及结果

        @Test
        public void testService1() {
            ApplicationContext context
                    = new ClassPathXmlApplicationContext("bean1.xml");
            UserService userService = context.getBean("userService", UserService.class);
            System.out.println(userService);
            userService.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20220720162808144

    4.3.3.4.2 @Qualifier:根据名称进行注入

    这个@Qualifier注解需要与@Autowired一起使用

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    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.Controller;
    import org.springframework.stereotype.Repository;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    //在注解里面value属性值可以省略不写,
    //默认值是类名称,首字母小写
    //UserService -- userService
    @Component(value = "userService")  //
    public class UserService {
    
        //定义dao类型属性
        //不需要添加set方法
        //添加注入属性注解
        @Autowired  //根据类型进行注入
        @Qualifier(value = "userDaoImpl") //根据名称进行注入
        private UserDao userDao;
    
        public void add() {
            System.out.println("service add.......");
            userDao.add();
        }
    }
    
    • 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
    4.3.3.4.3 @Resource:可以根据类型注入,也可以根据名称注入
    //    @Resource  //根据类型进行注入
        @Resource(name = "userDaoImpl")  //根据名称进行注入
        private UserDao userDao;
    
    • 1
    • 2
    • 3
    4.3.3.4.4 @Value注入普通类型属性
       @Value(value = "abc")
        private String name;
    
    • 1
    • 2

    4.3.3.5 完全注解开发

    4.3.3.5.1 创建配置类,替代xml配置文件
    package com.atguigu.spring5.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration  //作为配置类,替代xml配置文件
    @ComponentScan(basePackages = {"com.atguigu"})//替代配置文件中的组件扫描
    public class SpringConfig {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试类及结果

    使用AnnotationConfigApplicationContext获取上下文

    	@Test
        public void testService2() {
            //加载配置类
            ApplicationContext context
                    = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = context.getBean("userService", UserService.class);
            System.out.println(userService);
            userService.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20220720164616433

    5. AOP

    5.1 什么是AOP?

    1. 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性,同时提高了开发的效率

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

    3. 使用登录例子说明AOP

      图3

    5.2 AOP底层原理(动态代理)

    AOP地城使用动态代理,有两种动态代理

    • JDK动态代理:被代理的类有接口的情况,使用JDK动态代理

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

        image-20220720170553738

    • CGLIB动态代理:被代理的类没有接口的情况,使用CGLIB动态代理

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

        image-20220720170639202

    5.2.1 JDK动态代理

    使用JDK动态代理,使用Proxy类里面的newProxyInstance方法创建代理对象

    image-20220720170830691

    image-20220720170918118

    该方法有三个参数:

    • 第一个参数:类加载器
    • 第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口
    • 第三个参数:实现这个接口InvocationHandler,创建代理对象,写增强的部分

    5.2.2 编写JDK动态代理

    5.2.2.1 创建接口&实现类,定义方法,

    UserDao

    package com.atguigu.spring5;
    
    public interface UserDao {
        public int add(int a,int b);
        public String update(String id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    UserDaoImpl

    package com.atguigu.spring5;
    
    public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
            System.out.println("add方法执行了.....");
            return a+b;
        }
    
        @Override
        public String update(String id) {
            System.out.println("update方法执行了.....");
            return id;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5.2.2.2 使用Proxy类创建代理对象

    package com.atguigu.spring5;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    
    public class JDKProxy {
    
        public static void main(String[] args) {
            //创建接口实现类代理对象
            Class[] interfaces = {UserDao.class};
    //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        });
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1, 2);
            System.out.println("result:"+result);
        }
    }
    
    //创建代理对象代码
    class UserDaoProxy implements InvocationHandler {
    
        //1 把创建的是谁的代理对象,把谁传递过来
        //有参数构造传递
        private Object obj;
        public UserDaoProxy(Object obj) {
            this.obj = obj;
        }
    
        //增强的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //方法之前
            System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
    
            //被增强的方法执行
            Object res = method.invoke(obj, args);
    
            //方法之后
            System.out.println("方法之后执行...."+obj);
            return res;
        }
    }
    
    • 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

    5.3 术语

    5.3.1 连接点

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

    5.3.2 切入点

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

    5.3.3 通知(增强)

    实际增强的逻辑部分称为通知(增强)

    5.3.3.1 通知的多种类型

    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知

    5.3.4 切面

    是动作,是将通知应用到切入点的过程

    5.4 准备工作

    Spring框架一般都是基于AspectJ实现AOP操作

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

    5.4.1 在项目中引入AOP相关依赖

    image-20220720174139903

    5.4.2 切入点表达式

    5.4.2.1 切入点表达式作用

    字段对哪个类里面的哪个方法进行增强

    5.4.2.2 语法结构

    execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))

    • 权限修饰符可以省略不写
    • *号作为通配符
    • 参数列表可以使用(…)通配
    5.4.2.2.1 举例一:对com.atguigu.dao.BookDao类里面的add方法进行增强
    execution(* com.atguigu.dao.BookDao.add(..))
    
    • 1
    5.4.2.2.2 举例二:对com.atguigu.dao.BookDao类里面的所有方法进行增强
    execution(* com.atguigu.dao.BookDao.*(..))
    
    • 1
    5.4.2.2.3 举例三:对com.atguigu.dao包里面的所有类进行增强
    execution(* com.atguigu.dao.*.*(..))
    
    • 1

    5.4.3 基于AspectJ实现AOP操作

    5.4.3.1 注解方式(推荐&重点)

    5.4.3.1.1 创建类,在类中定义方法
    package com.atguigu.spring5.aopanno;
    
    import org.springframework.stereotype.Component;
    
    //被增强的类
    public class User {
        public void add() {
            System.out.println("add.......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    5.4.3.1.2 创建增强类(编写增强逻辑)

    在增强类里面,创建方法,让不同方法代表不同通知类型

    package com.atguigu.spring5.aopanno;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    //增强的类
    public class UserProxy {
         //前置通知
        //@Before注解表示作为前置通知
    	 @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void before() {//前置通知
            System.out.println("before.........");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    5.4.3.1.3 使用注解创建User和UserProxy对象

    image-20220720180200835

    5.4.3.1.4 进行通知的配置
    5.4.3.1.4.1 在spring配置文件中开启注解扫描自动代理
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <context:component-scan base-package="com.atguigu.spring5.aopanno">context:component-scan>
    
        
        <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    5.4.3.1.5 在增强类上添加注解@Aspect

    image-20220720180318438

    5.4.3.1.6 测试类及结果
        @Test
        public void testAopAnno() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
            User user = context.getBean("user", User.class);
            user.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20220720180647643

    5.4.3.1.7 配置不同类型的通知

    在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

    package com.atguigu.spring5.aopanno;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    //增强的类
    @Component
    @Aspect  //生成代理对象
    public class UserProxy {
    
    
        //前置通知
        //@Before注解表示作为前置通知
        @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void before() {
            System.out.println("before.........");
        }
    
        //后置通知(返回通知)
        @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void afterReturning() {
            System.out.println("afterReturning.........");
        }
    
        //最终通知
        @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void after() {
            System.out.println("after.........");
        }
    
        //异常通知
        @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing.........");
        }
    
        //环绕通知
        @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前.........");
    
            //被增强的方法执行
            proceedingJoinPoint.proceed();
    
            System.out.println("环绕之后.........");
        }
    }
    
    • 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

    测试及结果

        @Test
        public void testAopAnno() {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
            User user = context.getBean("user", User.class);
            user.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    被增强类无异常结果

    image-20220721155151665

    被增强类有异常结果

    image-20220721155251738

    image-20220721155310668

    5.4.3.1.8 相同的切入点抽取

    以前置通知为例

        //相同切入点抽取
        @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
        public void pointdemo() {
    
        }
    
        //前置通知
        //@Before注解表示作为前置通知
        @Before(value = "pointdemo()")
        public void before() {
            System.out.println("before.........");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    5.4.3.1.9 多个增强类对同一方法进行增强,设置增强类优先级

    在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高

    image-20220721155628419

    5.4.3.1.10 完全使用注解开发

    创建配置类,不需要xml配置文件

    package com.atguigu.spring5.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration
    @ComponentScan(basePackages = {"com.atguigu"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    修改测试类,使用AnnotationConfigApplicationContext(配置类.class)获取上下文对象

        @Test
        public void testAopAnno() {
            ApplicationContext context =
                    new AnnotationConfigApplicationContext(ConfigAop.class);
    
            User user = context.getBean("user", User.class);
            user.add();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.4.3.2 xml配置文件方式

    5.4.3.2.1 创建两个类,增强类与被增强类,创建方法
    5.4.3.2.2 在spring配置文件中创建两个对象
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <bean id="book" class="com.atguigu.spring5.aopxml.Book">bean>
        <bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy">bean>
    
        
        <aop:config>
            
            <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
            
            <aop:aspect ref="bookProxy">
                
                <aop:before method="before" pointcut-ref="p"/>
            aop:aspect>
        aop:config>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    5.4.3.2.3 在spring配置文件中配置切入点
    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <bean id="book" class="com.atguigu.spring5.aopxml.Book">bean>
        <bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy">bean>
    
        
        <aop:config>
            
            <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
            
            <aop:aspect ref="bookProxy">
                
                <aop:before method="before" pointcut-ref="p"/>
            aop:aspect>
        aop:config>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    6. JdbcTemplate(了解,后面我们都用mybatis)

    6.1 什么是JdbcTemplate?

    Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

    6.2 准备工作

    6.2.1 引入相关jar包

    image-20220721160833938

    6.2.2 在spring配置文件配置数据连接池

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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 http://www.springframework.org/schema/context/spring-context.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">
    
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              destroy-method="close">
            <property name="url" value="jdbc:mysql:///user_db" />
            <property name="username" value="root" />
            <property name="password" value="root" />
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.2.3 配置JdbcTemplate对象,注入DataSource

        
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.2.4 创建Service类,创建dao类,在dao注入JdbcTemplate

    
    <context:component-scan base-package="com.atguigu">context:component-scan>
    
    • 1
    • 2

    service

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    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 javax.annotation.Resource;
    
    @Service
    public class UserService {
        //注入dao
        @Autowired
        private UserDao userDao;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    dao

    package com.atguigu.spring5.dao;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6.3 JdbcTemplate操作数据库

    6.3.1 添加

    6.3.1.1 对应数据库创建实体类

    image-20220721161936585

    6.3.1.2 编写service和dao的新增方法

    image-20220721163920628

    service

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    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 javax.annotation.Resource;
    
    @Service
    public class UserService {
        //注入dao
        @Autowired
        private UserDao userDao;
        
        public void add(User user){
            userDao.add(user);
        }	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    dao

    package com.atguigu.spring5.dao;
    
    import com.atguigu.spring5.test.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void add(User user) {
            //1 创建sql语句
            String sql="insert into t_user values(?,?,?)";
            //2 构造sql所需参数
            Object[] args={user.getUserId(),user.getUsername(),user.getUstatus()};
            //3 调用方法实现 update方法针对的是增,删,改这三种sql都可以使用
            int update = jdbcTemplate.update(sql, args);
            System.out.println(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

    6.3.1.3 测试类及结果

        @Test
        public void testJdbcTemplate() {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
            UserService userService = context.getBean("userService",UserService.class);
            User user = new User("1","java","a");
            userService.add(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20220721163446006

    6.3.2 修改与删除

    修改与删除的方式与新增一致,只不过sql语句构建有些许差异

    image-20220721163728270

    6.3.3 查询返回某个值

    image-20220721163947703

        @Override
        public void selectCount() {
            //1 创建sql语句
            String sql="select count(*) from t_user";
            //3 调用方法实现
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
            System.out.println(count);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.3.4 查询返回对象

    image-20220721164314229

    	@Override
        public User findUserInfo(String id) {
            //1 创建sql语句
            String sql="select * from t_user where user_id=?";
            //3 调用方法实现
            User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id);
            return user;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.3.5 查询返回集合

    image-20220721164658517

       @Override
        public User findAllUser() {
            //1 创建sql语句
            String sql="select * from t_user";
            //3 调用方法实现
            User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class));
            return user;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.3.6 批量操作(CRUD)

    image-20220721164939332

        @Override
        public void batchAddUser(List<Object[]> batchArgs) {
            //1 创建sql语句
            String sql="insert into t_user values(?,?,?)";
            int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
            System.out.println(Arrays.toString(ints));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    批量添加测试

        @Test
        public void testJdbcTemplate() {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
            UserService userService = context.getBean("userService",UserService.class);
            //批量添加测试
            ArrayList<Object[]> batchArgs = new ArrayList<>();
            Object[] o1={"3","java","a"};
            Object[] o2={"4","c++","b"};
            Object[] o3={"5","mysql","c"};
            batchArgs.add(o1);
            batchArgs.add(o2);
            batchArgs.add(o3);
            调用批量添加方法
            userService.batchAdd(batchArgs);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    批量修改

    image-20220721165828936

    批量删除

    image-20220721165921728

    7. 事务操作

    7.1 什么是事务?

    事务是数据库操作的最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败所有操作都失败

    image-20220721171054102

    7.2 事务的四个特性(ACID)

    • 原子性(Atomicity)

      • 指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败
    • 一致性(Consistency)

      • 官网上事务一致性的概念是:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
      • 换一种方式理解就是:事务按照预期生效,数据的状态是预期的状态。
      • 举例说明:张三向李四转100元,转账前和转账后的数据是正确的状态,这就叫一致性,如果出现张三转出100元,李四账号没有增加100元这就出现了数据错误,就没有达到一致性。

      个人理解就是数据库中的能量(数据)守恒

    • 隔离性(Isolation)

      • 一个事务不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
    • 持久性(Durability)

      • 指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

    7.3 搭建事务操作环境

    图6

    7.3.1 创建数据库表,添加记录

    image-20220721171958761

    7.3.2 创建service,搭建dao,完成对象创建和注入关系

    service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource

    service

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    import com.atguigu.spring5.test.User;
    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 javax.annotation.Resource;
    
    @Service
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    dao

    package com.atguigu.spring5.dao;
    
    import com.atguigu.spring5.test.User;
    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 java.util.Arrays;
    import java.util.List;
    
    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    JdbcTemplate&DataSource&组件扫描

    
    <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"
           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 http://www.springframework.org/schema/context/spring-context.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">
    
        
        <context:component-scan base-package="com.atguigu">context:component-scan>
    
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              destroy-method="close">
            <property name="url" value="jdbc:mysql:///world"/>
            <property name="username" value="root" />
            <property name="password" value="root" />
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        bean>
    
        
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    beans>
    
    • 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

    7.3.3 在dao创建两个方法:多钱与少钱方法,在service创建转账方法

    dao

    package com.atguigu.spring5.dao;
    
    import com.atguigu.spring5.test.User;
    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 java.util.Arrays;
    import java.util.List;
    
    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        //lucy转账100给mary
        //少钱
        @Override
        public void reduceMoney() {
            String sql = "update t_account set money=money-? where username=?";
            jdbcTemplate.update(sql,100,"lucy");
        }
    
        //多钱
        @Override
        public void addMoney() {
            String sql = "update t_account set money=money+? where username=?";
            jdbcTemplate.update(sql,100,"mary");
        }
    }
    
    • 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

    service

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    import com.atguigu.spring5.test.User;
    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 javax.annotation.Resource;
    
    @Service
    @Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
        //转账的方法
        public void accountMoney() {
    		//lucy少100
           userDao.reduceMoney();
           //mary多100
           userDao.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

    测试执行userService.accountMoney发现一切正常

    image-20220721173222530

    7.3.4 模拟在转账accountMoney方法执行中出现异常

    为了查看方便,每次转账演示后我都会将money置为1000

    模拟accountMoney方法执行中出现异常

    package com.atguigu.spring5.service;
    
    import com.atguigu.spring5.dao.UserDao;
    import com.atguigu.spring5.test.User;
    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 javax.annotation.Resource;
    
    @Service
    @Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public class UserService {
    
        //注入dao
        @Autowired
        private UserDao userDao;
    
        //转账的方法
        public void accountMoney() {
    		//lucy少100
           userDao.reduceMoney();
           //模拟异常
           int i = 10/0;
           //mary多100
           userDao.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

    再次启动测试

    发现数据没有一致性了

    image-20220721173558923

    image-20220721173658565

    7.3.5 使用事务解决转账accountMoney方法执行中出现异常

    image-20220721173849131

    7.4 Spring事务管理

    7.4.1 Spring事务管理介绍

    • 事务添加到JavaEE三层结构里的Service层(业务逻辑层)

    • 在Spring进行声明式事务管理,底层使用的是AOP原理

    • 在Spring进行事务管理的两种方式

      • 编程式事务管理
        • 通过代码来管理事务
      • 声明式事务管理(使用)
        • 采用声明的方式来处理事务
        • 使用方法
          • 基于注解方式(使用)
          • 基于xml配置文件方式
    • Spring事务管理API

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

        image-20220721174718640

    7.4.2 声明式事务管理

    7.4.2.1 注解方式声明式事务管理(使用)

    7.4.2.1.1 在spring配置文件引入名称空间tx
    
    <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"
           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 http://www.springframework.org/schema/context/spring-context.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">
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    7.4.2.1.2 在spring配置文件配置事务管理器
        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
            <property name="dataSource" ref="dataSource">property>
        bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    7.4.2.1.3 开启事务注解
        
        <tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
    
    • 1
    • 2
    7.4.2.1.4 在service类上面(或者service类方法上面)添加事务注解
    • @Transactional ,这个注解可以添加到类上面,也可以添加到方法上
    • 如果把这个注解添加到类上,这个类里的所有方法都会添加事务
    • 如果把这个注解添加到方法上,为这个方法服务

    image-20220721175534414

    7.4.2.1.5 声明式事务管理参数配置

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

    image-20220721175943718

    7.4.2.1.6 事务的传播行为(propagation)

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

    image-20220721180147017

    常用的两种

    图7

    7.4.2.1.6.1 使用@Transactional配置事务的传播行为

    image-20220721180417689

    7.4.2.1.7 事务的隔离级别(ioslation)
    7.4.2.1.7.1 没有设置事务隔离级别所存在的读问题
    • 事务有特性为为隔离性,多事务操作之间不会产生影响,不考虑隔离性会产生很多问题

    • 有三个读问题:

      • 脏读

        • 一个未提交事务读取到另一个未提交事务的数据

          image-20220721182701783

      • 不可重复读

        • 一个未提交事务读取到另一个提交事务修改数据

          image-20220721182749433

      • 虚读(幻读)

        • 一个未提交事务读取到另一个提交事务添加数据

      上面的三个读问题只有脏读是最严重的,会影响数据的一致性,剩余的不可重复读与幻读不会影响数据一致性,只是看起来数据来回变化

    7.4.2.1.7.2 设置事务隔离级别,解决读问题
    脏读不可重复读幻读
    READ UNCOMMITTED(读未提交)
    READ COMMITTED(读已提交)
    REPEATABLE READ(可重复读)
    SERIALIZABLE(串行化)
    • 平常开发中尽量不要使用SERIALIZABLE,串行化会使数据库的吞吐性能大幅度下降

    • spring中的默认数据隔离级别为DEFAULT,代表使用数据库默认的事务隔离级别,而mysql默认的事务隔离级别为REPEATABLE READ

      image-20220722094235486

    7.4.2.1.7.3 使用@Transactional配置事务的隔离级别

    image-20220722094452662

    7.4.2.1.8 @Transactional中其他参数配置
    7.4.2.1.8.1 timeout :超时时间
    • 事务需要在一定时间内进行提交,如果不提交则进行回滚
    • 默认值为-1代表没有超时时间,设置时间以秒为单位进行计算
    7.4.2.1.8.2 readOnly:是否只读
    • 读:查询操作;写:添加修改删除操作
    • readOnly默认为false,代表可读可写
    • 设置readOnly为true后,只能进行读操作
    7.4.2.1.8.3 rollbackFor:什么异常回滚
    • 设置出现哪些异常进行事务回滚
    7.4.2.1.8.3 noRollbackFor:什么异常不回滚
    • 设置出现哪些异常不进行事务回滚

    7.4.2.2 xml方式 声明式事务管理

    前两步与7.4.2.1.1,7.4.2.1.2步骤一致

    7.4.2.2.1 配置通知
    	
        <tx:advice id="txadvice">
            
            <tx:attributes>
                
                <tx:method name="accountMoney" propagation="REQUIRED"/>
                
            tx:attributes>
        tx:advice>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以在配置通知时配置其他参数

    image-20220722095802499

    7.4.2.2.2 配置切入点与切面
    	
        <aop:config>
            
            <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
            
            <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
        aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7.4.2.3 完全注解声明式事务管理

    7.4.2.3.1 创建配置类,使用配置类代替xml

    其中@EnableTransactionManagement等价于配置文件中的标签

    	
     <tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
    
    • 1
    • 2
    package com.atguigu.spring5.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;
    
    @Configuration //配置类
    @ComponentScan(basePackages = "com.atguigu") //组件扫描
    @EnableTransactionManagement //开启事务
    public class TxConfig {
    
        //创建数据库连接池
        @Bean
        public DruidDataSource getDruidDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///user_db");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            return dataSource;
        }
    
        //创建JdbcTemplate对象
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            //到ioc容器中根据类型找到dataSource
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            //注入dataSource
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
        //创建事务管理器
        @Bean
        public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
            transactionManager.setDataSource(dataSource);
            return transactionManager;
        }
    }
    
    • 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

    8. spring5 框架新功能

    整个spring5框架代码基于jdk8,运行时兼容jdk9,需对不建议使用的类和方法在代码库中删除

    8.1 日志封装

    spring5 框架自带了通用的日志封装

    • spring5 已经移除看Log4jConfigListener,官方建议使用Log4j2
    • spring5 框架整合Log4j2

    8.1.1 引入依赖

    image-20220725135320826

    8.1.2 创建log4j2.xml配置文件

    调整日志级别以打出不同程度的日志信息

    
    
    
    <configuration status="INFO">
        
        <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>
        
        
        <loggers>
            <root level="info">
                <appender-ref ref="Console"/>
            root>
        loggers>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    image-20220725135549332

    8.1.3 输入用户自定义日志

    package com.atguigu.spring5.test;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class UserLog {
    
        private static final Logger log = LoggerFactory.getLogger(UserLog.class);
    
        public static void main(String[] args) {
    
            log.info("hello log4j2");
            log.warn("hello log4j2");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    效果

    image-20220725140108347

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

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

    8.2.1 方法上使用-返回值可以为空

    image-20220725140426115

    8.2.2 参数上使用-参数可以为空

    image-20220725140557843

    8.2.3 属性上使用-属性值可以为空

    image-20220725140637124

    8.3spring5核心容器支持函数是风格GenericApplicationContext

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

    8.4 spring5支持整合JUnit5

    8.4.1 整合JUnit4

    8.4.1.1 引入spring相关针对测试依赖

    image-20220725141118089

    8.4.1.2 创建测试类,使用注解方式完成

    • @RunWith

    • @ContextConfiguration

      • 加载配置文件

        • @ContextConfiguration("classpath:bean1.xml") //加载配置文件
          
          • 1
      • 加载配置配置类

        • @ContextConfiguration(classes = TxConfig.class) //加载配置类
          
          • 1
    package com.atguigu.spring5.test;
    
    import com.atguigu.spring5.config.TxConfig;
    import com.atguigu.spring5.service.UserService;
    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;
    
    @RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
    @ContextConfiguration("classpath:bean1.xml") //加载配置文件
    //@ContextConfiguration(classes = TxConfig.class) //加载配置类
    public class JTest4 {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void test1() {
            userService.accountMoney();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    8.4.2 spring5整合JUnit5

    8.4.2.1 引入JUnit5依赖

    image-20220725141744917

    8.4.2.2 创建测试类,使用注解完成

    • @ExtendWith: 替换JUnit4中的@RunWith

    • @ContextConfiguration

      • 加载配置文件

        • @ContextConfiguration("classpath:bean1.xml") //加载配置文件
          
          • 1
      • 加载配置配置类

        • @ContextConfiguration(classes = TxConfig.class) //加载配置类
          
          • 1
    • @SpringJUnitConfig: 使用一个复合注解代替上面两个注解完成整合

    package com.atguigu.spring5.test;
    
    import com.atguigu.spring5.service.UserService;
    
    
    
    import org.junit.jupiter.api.DynamicTest;
    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 org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration("classpath:bean1.xml")
    
    //@SpringJUnitConfig(locations = "classpath:bean1.xml")
    public class JTest5 {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void test1() {
            userService.accountMoney();
        }
    }
    
    • 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

    8.5 spring5框架新功能Webflux

    8.5.0 解释什么是异步非阻塞

    • 异步和同步针对调用者
      • 调用者发送请求,如果等待对方回应之后才去做其他事情就是同步;如果发送请求之后不等待对方回应就去做其他事情就是异步
    • 阻塞和非阻塞针对被调用者
      • 被调用者收到请求之后,做完请求任务才给出反馈就阻塞,收到请求后马上给出反馈然后再去做其他的事情就是非阻塞

    image-20220725172327808

    8.5.1 SpringWebflux介绍

    • 是Spring5添加新的模块,用于web开发的,功能与SpringMVC类似的,WebFlux使用当前一种比较流行的响应式编程出现的框架

    • 与SpringMVC对比:

      image-20220725173527713

      • 使用传统web框架,比如SpringMVC,这些基于Servlet容器
      • WebFlux 是一种异步非阻塞的框架,异步非阻塞的框架在Servlet3.1后才支持,核心是基于Reactor的相关API实现的
      • SpringMVC采用命令式编程
      • Webflux采用异步响应式编程
      • 相同点:两个框架都可以使用注解方式,都运行在Tomcat等容器中
    • WebFlux特点:

      • 非阻塞式:在有限资源的情况下,提高系统吞吐量和伸缩性,以Reactor 为基础实现响应式编程
      • 函数式编程: Spring5框架基于JDK8,Webflux使用JDK8函数式编程方式实现路由请求

    8.5.2 响应式编程(Java实现)

    8.5.2.1 什么是响应式编程

    响应式编程是一种面向数据流和变化传播的编程范式.这意味着可以在编程语言中方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播.

    解释:

    电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

    8.5.2.2 Java8及其之前版本(demo)

    实现方法: 提供观察者模式两个类ObserverObservable

    原理:在 Java 中可以直接依靠类 Observable 和 接口 Observer实现观察者模式的功能。

    • Observable: 开启观察者模式
    • Observer:添加观察者
    package com.atguigu.demoreactor.reactor8;
    
    import java.util.Observable;
    
    public class ObserverDemo extends Observable {
    
        public static void main(String[] args) {
            ObserverDemo observer = new ObserverDemo();
            //添加观察者
            observer.addObserver((o,arg)->{
                System.out.println("发生变化");
            });
            observer.addObserver((o,arg)->{
                System.out.println("手动被观察者通知,准备改变");
            });
            observer.setChanged(); //数据变化
            observer.notifyObservers(); //通知
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    总结:

    • 实现的类需要继承Observable类

    • 使用addObserver():方法添加观察者

    • setChanged():方法将此Observable对象标记为已更改

    • notifyObservers():如果该对象发生了变化,则通知其所有观察者

    测试结果:

    image-20220725180715632

    8.5.3 响应式编程(Reactor实现)

    • 响应式编程操作中,Reactor是满足Reactive规范框架

    • Reactor 有两个核心类

      image-20220725182450153

      • Mono
        • Mono实现发布者,返回0个或者1个元素
      • Flux
        • Flux对象实现发布者,返回N个元素
      • 这两个类实现接口Publisher,提供丰富操作符
    • Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号

      • 元素值
        • 将返回结果传递给订阅者
      • 完成信号
        • 完成信号用于告诉订阅者数据流结束了
      • 错误信号
        • 错误信号终止数据流同时把错误信息传递给订阅者
      • 终止信号
        • 错误信号与完成信号都代表终止信号

    8.5.3.1 代码演示Flux和Mono

    1. 引入依赖
            <dependency>
                <groupId>io.projectreactorgroupId>
                <artifactId>reactor-coreartifactId>
                <version>3.1.5.RELEASEversion>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 测试代码
    package com.atguigu.demoreactor.reactor8;
    
    import org.springframework.web.server.WebHandler;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Stream;
    
    public class TestReactor {
    
        public static void main(String[] args) {
    
            //just方法直接声明
            Flux.just(1,2,3,4).subscribe(System.out::print);//接收1个以上,然后逐个发射。
            Mono.just(1).subscribe(System.out::print);//发射单个基础类型数组流,然后发射。
    
            //其他的方法
            Integer[] array = {1,2,3,4};
            Flux.fromArray(array).subscribe(System.out::print);//接收数组类型数据流,然后发射。
    
            List<Integer> list = Arrays.asList(array);
            Flux.fromIterable(list).subscribe(System.out::print);//接收迭代器类型的数据流,然后发射。
    
            Stream<Integer> stream = list.stream();
            Flux.fromStream(stream).subscribe(System.out::print);//接收流类型的数据流,然后发射。
    
        }
    }
    
    
    • 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

    测试结果

    image-20220725182722428

    总结:

    • just方法:用于装填普通数据
    • fromArray方法:接收数组类型数据流,在订阅后发射。
    • fromIterable方法:接收迭代器类型的数据流,在订阅后发射。
    • fromStream方法: 接收流类型的数据流,在订阅后发射。
    • subscribe方法用于接收发射数据

    8.5.3.2 三种信号特点

    • 错误信号与完成信号都是终止信号,不能共存
    • 如果没有发射任何元素值,而是自己发射错误信号或者完成信号,表示空数据流
    • 如果没有错误信号,也没有完成信号,表示是无限数据流

    8.5.3.3 注意事项

    调用just,fromArray或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生

    8.5.3.4 操作符

    对流数据进行一道道操作,成为操作,比如工厂流水线

    8.5.3.4.1 map (元素映射为新元素)

    image-20220726095250346

    8.5.3.4.2 flatMap (元素映射为流)

    把每个元素转换刘,把转换之后多个刘合并大的流

    image-20220726102519456

    8.5.4 SpringWebFlux执行流程和核心API

    SpringWebFlux基于Reactor,默认使用容器时Netty,Netty是高性能NIO框架,异步非阻塞的框架

    8.5.4.1 Netty

    8.5.4.1.1 BIO 同步阻塞IO

    image-20220726103018894

    8.5.4.1.2 NIO 同步非阻塞IO 基于Reactor模型来实现

    image-20220726103046047

    8.5.4.1.3 AIO 异步非阻塞IO,基于Proactor模型实现

    8.5.4.2 SpringWebflux执行过程

    SpringWebflux执行过程与SpringMVC相似

    8.5.4.2.1 WebHandler

    SpringWebflux核心控制器DispatchHandler,实现接口WebHandler

    image-20220726104055340

    DispatchHandler中实现的方法

    image-20220726104141519

    8.5.4.2.2 DispatchHandler 负责请求的处理
    • HandlerMapping: 请求查询到处理的方法
    • HandlerAdaptec: 真正负责请求处理
    • HandlerResultHandler: 响应结果处理
    8.5.4.2.3 SpringWebflux 实现函数式编程两个接口

    基于函数式编程模型实现SpringWebflux会使用到

    • RouterFunction
    • HandlerFunction

    8.5.5 SpringWebflux (基于注解编程模型)

    SpringWebflux实现方式有两种:注解编程模型函数式编程模型

    使用注解编程模型方式和之前SpringMVC使用相似的,只需要把相关依赖配置到项目中SpringBoot自动配置相关运行容器,默认情况下使用Netty服务器

    8.5.5.1 创建SpringBoot工程,引入Webflux依赖,并配置启动端口号

    创建SpringBoot工程

    image-20220726105314561

    引入依赖

            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webfluxartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4

    配置启动端口号

    image-20220726105522757

    8.5.5.2 创建包和相关类

    结构

    image-20220726105636358

    实体类User

    package com.atguigu.webfluxdemo1.entity;
    
    
    //实体类
    public class User {
        private String name;
        private String gender;
        private Integer age;
    
        public User(String name, String gender, Integer age) {
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public String getGender() {
            return gender;
        }
    
        public Integer getAge() {
            return age;
        }
    }
    
    • 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

    创建接口定义操作的方法 UserService

    package com.atguigu.webfluxdemo1.service;
    
    import com.atguigu.webfluxdemo1.entity.User;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    //用户操作接口
    public interface UserService {
        //根据id查询用户
        Mono<User> getUserById(int id);
    
        //查询所有用户
        Flux<User> getAllUser();
    
        //添加用户
        Mono<Void> saveUserInfo(Mono<User> user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    接口实现类 UserServiceImpl

    package com.atguigu.webfluxdemo1.service.impl;
    
    import com.atguigu.webfluxdemo1.entity.User;
    import com.atguigu.webfluxdemo1.service.UserService;
    import org.springframework.stereotype.Repository;
    import org.springframework.web.bind.annotation.ResponseBody;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Repository
    public class UserServiceImpl implements UserService {
    
        //创建map集合存储数据
        private final Map<Integer,User> users = new HashMap<>();
    
        public UserServiceImpl() {
            this.users.put(1,new User("lucy","nan",20));
            this.users.put(2,new User("mary","nv",30));
            this.users.put(3,new User("jack","nv",50));
        }
    
        //根据id查询
        @Override
        public Mono<User> getUserById(int id) {
            return Mono.justOrEmpty(this.users.get(id));
        }
    
        //查询多个用户
        @Override
        public Flux<User> getAllUser() {
            return Flux.fromIterable(this.users.values());
        }
    
        //添加用户
        @Override
        public Mono<Void> saveUserInfo(Mono<User> userMono) {
            return userMono.doOnNext(person -> {
                //向map集合里面放值
                int id = users.size()+1;
                users.put(id,person);
            }).thenEmpty(Mono.empty());
        }
    }
    
    • 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

    创建controller UserController

    package com.atguigu.webfluxdemo1.controller;
    
    import com.atguigu.webfluxdemo1.entity.User;
    import com.atguigu.webfluxdemo1.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    @RestController
    public class UserController {
    
        //注入service
        @Autowired
        private UserService userService;
    
        //id查询
        @GetMapping("/user/{id}")
        public Mono<User> geetUserId(@PathVariable int id) {
            return userService.getUserById(id);
        }
    
        //查询所有
        @GetMapping("/user")
        public Flux<User> getUsers() {
            return userService.getAllUser();
        }
    
        //添加
        @PostMapping("/saveuser")
        public Mono<Void> saveUser(@RequestBody User user) {
            Mono<User> userMono = Mono.just(user);
            return userService.saveUserInfo(userMono);
        }
    }
    
    • 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

    8.5.5.3 接口测试

    • localhost:8081/user/1

      image-20220726110240251

    • localhost:8081/user

      image-20220726110320511

    • http://localhost:8081/saveuser

      应为浏览器只能发生get请求,所有我们使用postman测试

      {"name":"lucy","gender":"nan","age":20}
      
      • 1

      image-20220726110741801

      再次查询所有,发现有两个lucy了

      image-20220726110855865

    8.5.5.4 SpringMVC与SpringWebflux 说明(不同)

    • SpringMVC方式实现,同步阻塞的方式,基于SpringMVC+Servlet+Tomcat
    • SpringWebflux方式实现,异步非阻塞方式,基于SpringWebflux+Reactor+Netty

    8.5.6 SpringWebflux (基于函数式编程模型)

    注意:

    • 在使用函数式编程模型操作时候,需要自己初始化服务器
    • 基于函数式编程模型时候,有两个核心接口:核心任务定义两个函数式接口的实现并且启动需要的服务器。
      • RouterFunction(实现路由功能,请求转发给对应的 handler)
      • HandlerFunction(处理请求生成响应的函数)。
    • SpringWebflux请求和响应不再是 ServletRequest 和 ServletResponse而是ServerRequest和 ServerResponse

    8.5.6.1 构建工程

    复制8.5.5中的项目新建项目,干掉controller,如果没有做8.5.5参照如下结构

    image-20220726112433829

    完整结构

    image-20220726112927439

    8.5.6.2 创建Handler(具体实现方法)

    package com.atguigu.webfluxdemo1.handler;
    
    import com.atguigu.webfluxdemo1.entity.User;
    import com.atguigu.webfluxdemo1.service.UserService;
    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.server.ServerRequest;
    import org.springframework.web.reactive.function.server.ServerResponse;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import static org.springframework.web.reactive.function.BodyInserters.fromObject;
    
    public class UserHandler {
    
        private final UserService userService;
        public UserHandler(UserService userService) {
            this.userService = userService;
        }
    
        //根据id查询
        public Mono<ServerResponse> getUserById(ServerRequest request) {
            //获取id值
           int userId = Integer.valueOf(request.pathVariable("id"));
           //空值处理
            Mono<ServerResponse> notFound = ServerResponse.notFound().build();
    
           //调用service方法得到数据
            Mono<User> userMono = this.userService.getUserById(userId);
            //把userMono进行转换返回
            //使用Reactor操作符flatMap
            return
                    userMono
                            .flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                                    .body(fromObject(person)))
                                    .switchIfEmpty(notFound);
        }
    
        //查询所有
        public Mono<ServerResponse> getAllUsers(ServerRequest request) {
            //调用service得到结果
            Flux<User> users = this.userService.getAllUser();
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class);
        }
    
        //添加
        public Mono<ServerResponse> saveUser(ServerRequest request) {
            //得到user对象
            Mono<User> userMono = request.bodyToMono(User.class);
            return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
        }
    
    }
    
    • 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

    8.5.6.3 初始化服务器,编写Router

    server

    package com.atguigu.webfluxdemo1;
    
    import com.atguigu.webfluxdemo1.handler.UserHandler;
    import com.atguigu.webfluxdemo1.service.UserService;
    import com.atguigu.webfluxdemo1.service.impl.UserServiceImpl;
    import org.springframework.http.server.reactive.HttpHandler;
    import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
    import org.springframework.web.reactive.function.server.RouterFunction;
    import org.springframework.web.reactive.function.server.RouterFunctionDsl;
    import org.springframework.web.reactive.function.server.RouterFunctions;
    import org.springframework.web.reactive.function.server.ServerResponse;
    import reactor.netty.http.server.HttpServer;
    
    import static org.springframework.http.MediaType.APPLICATION_JSON;
    import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
    import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
    import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
    
    public class Server {
        //3 最终调用
        public static void main(String[] args) throws Exception{
            Server server = new Server();
            server.createReactorServer();
            System.out.println("enter to exit");
            System.in.read();
        }
    
        //1 创建Router路由
        public RouterFunction<ServerResponse> routingFunction() {
            //创建hanler对象
            UserService userService = new UserServiceImpl();
            UserHandler handler = new UserHandler(userService);
            //设置路由
            return RouterFunctions.route(
                    GET("/users/{id}").and(accept(APPLICATION_JSON)),handler::getUserById)
                    .andRoute(GET("/users").and(accept(APPLICATION_JSON)),handler::getAllUsers);
        }
    
        //2 创建服务器完成适配
        public void createReactorServer() {
            //路由和handler适配
            RouterFunction<ServerResponse> route = routingFunction();
            HttpHandler httpHandler = toHttpHandler(route);
            ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
            //创建服务器
            HttpServer httpServer = HttpServer.create();
            httpServer.handle(adapter).bindNow();
        }
    }
    
    • 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

    8.5.6.4 调用测试

    启动项目查看端口28778

    注意:每次启动端口都会不一样

    image-20220726113508832

    访问http://localhost:28778/users

    image-20220726113611602

    访问http://localhost:28778/users/1

    image-20220726113646989

    8.5.6.5 使用客户端调用测试

    client

    注意:

    • 需要先启动server,在启动client
    • client中的调用服务器地址中端口需要与server启动后的端口一致
    package com.atguigu.webfluxdemo1;
    
    import com.atguigu.webfluxdemo1.entity.User;
    import org.springframework.http.MediaType;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Flux;
    
    public class Client {
    
        public static void main(String[] args) {
            //调用服务器地址
            WebClient webClient = WebClient.create("http://127.0.0.1:28778");
    
            //根据id查询
            String id = "1";
            User userresult = webClient.get().uri("/users/{id}", id)
                    .accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
                    .block();
            System.out.println(userresult.getName());
    
            //查询所有
            Flux<User> results = webClient.get().uri("/users")
                    .accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class);
    
            results.map(stu -> stu.getName())
                        .buffer().doOnNext(System.out::println).blockFirst();
        }
    }
    
    • 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

    测试结果

    image-20220726114243967

    9. 总结

    9.1 Spring框架概述

    1. 轻量级开源JavaEE框架,为了解决企业复杂性,两个核心组成:IOC 和AOP
    2. Spring5.2.6版本

    9.2 IOC容器

    1. IOC底层原理(xml解析、工厂、反射等)
    2. IOC接口((BeanFactory)
    3. IOC操作 Bean管理(基于xml)
    4. IOC操作Bean管理(基于注解)

    9.3 AOP

    1. AOP底层原理:动态代理,有接口(JDK动态代理),没有接口(CGLIB动态代理)
    2. 术语:切入点、增强(通知)、切面
    3. 基于Aspect]实现AOP操作

    9.4 JdbcTemplate

    1. 使用JdbcTemplate实现数据库curd操作
    2. 使用JdbcTemplate实现数据库批量操作

    9.5 事务管理

    1. 事务概念
    2. 重要概念(传播行为和隔离级别)
    3. 基于注解实现声明式事务管理
    4. 完全注解方式实现声明式事务管理

    9.6 Spring5新功能

    1. 整合日志框架
    2. @Nullable注解
    3. 函数式注册对象
    4. 整合JUnit5单元测试框架
    5. SpringWebflux使用
  • 相关阅读:
    树莓派(七)文件系统及其目录结构、虚拟文件系统
    ESP32-S3上手开发
    【校招VIP】前端项目表达之正则表达
    Java异常try{}catch{}中的return机制
    ubuntu下ftp搭建
    信息安全:网络物理隔离技术原理与应用.
    【云原生之kubernetes实战】在k8s集群下部署portainer-k8s平台
    unity 遮挡剔除的实现
    支付宝小程序唤起签约并支付(周期扣款)
    exe文件运行一半消失
  • 原文地址:https://blog.csdn.net/qq_31745863/article/details/125991950