Spring完整知识点一

news2025/1/16 14:39:55

Spring简介

  • 额外知识点

    • 在之前的学习中我们在Service业务层创建Dao/Mapper数据访问层(持久层)的对象是通过工具类来获取对应Dao/Mapper数据访问层(持久层)的接口代理对象
    • 在此处我们不用工具类来获取对应Dao/Mapper数据访问层(持久层)的接口代理对象,而是创建一个Dao/Mapper数据访问层(持久层)的接口的实现类,通过创建实现类的对象进而得到接口对象以供使用
      • 讲解程序开发原理以及后续IOC和DI示例均是以此形式讲解
  • 定义

    • Spring是分层的JavaSE/EE应用full-stack轻量级开源框架,以IOC(Inversion of Control:控制反转)AOP(Aspect Oriented Programming:面向切面编程) 为内核
    • 它提供了**web/Controller表现层SpringMVC** 、Service业务层SpringDao/Mapper数据访问层(持久层)MyBatis/Spring JDBCTemplate 等众多企业级应用技术
    • 他整合开源了众多第三方框架和类库,它是使用最多的JavaEE企业级应用开源框架
  • 优点

    • 方便解耦,简化开发,降低企业级开发的复杂性
      • 通过Spring提供的IOC容器 ,可将对象间的依赖关系交由Spring进行控制,避免硬编码造成的过度耦合。
      • 用户可不必再为单例模式类、属性文件解析等这些底层的需求编写代码,可更专注于上层应用
    • 对AOP编程支持
      • 通过Spring的AOP功能,方便进行面向切面编程。许多不易用传统OOP实现的功能可以用AOP轻松实现
    • 对声明式事务的支持
      • 可将开发人员从事务管理代码中解脱出来,通过声明式的方式灵活的进行事务管理,提高开发效率和质量
    • 方便程序测试
      • 可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是可随手做的操作
    • 框架整合,集成了各种优秀框架
      • 比如:StrusHibemateHessianQuartz
    • 降低JavaEE API的使用难度
      • 它对JavaEE API(eg:JDBC、JavaMail、远程调用等)进行了封装,降低其使用难度
  • Spring有一套属于自己的开发生态圈,它提供了若干项目,每个项目对应完成特定的功能,详见官网

    在这里插入图片描述

  • 主要学习

    • Spring Framework:Spring技术基础
    • Spring Boot:提高开发效率
    • Spring Cloud:分布式开发相关技术

Spring体系结构

在这里插入图片描述

  • 第一模块:核心容器(Core Container

    • Spring框架最核心部分
  • 第二模块

    • 面向切面编程(AOP):依赖于核心容器
    • AOP思想实现(Aspects):是对AOP的一个思想实现
  • 第三模块

    • 数据访问(Data Access/Integration
    • 数据集成(Data Integration
  • 第四模块:Web开发

  • 第五模块:单元测试与集成测试(Test

    • 该框架整体均可进行测试
  • 学习线路

    在这里插入图片描述

Spring程序开发原理

  • Spring程序开发步骤

    在这里插入图片描述

  • 开发步骤详解

    • 在之前的学习中,我们在Service业务层创建Dao/Mapper数据访问层(持久层)的对象是通过new Dao/Mapper数据访问层(持久层)的接口实现类实现的,但是这种方式容易造成高耦合问题,所以我们现在舍弃该方式
    • 而是通过配置Spring的xml配置文件来获取到Dao/Mapper数据访问层(持久层)的接口实现类对象
      • 方式是:利用id唯一标识标记Dao/Mapper数据访问层(持久层)接口实现类的全限定名
    • 唯一标识后,在Service业务层就不需要在newDao/Mapper数据访问层接口实现类的对象,而是通过Spring客户端来调用Spring客户端提供的getBean("id标识")方法来获取到Dao/Mapper数据访问层(持久层)的接口实现类的对象
  • 开发步骤详解中Spring客户端获取到对象的原理如下:

    • Spring会先读取XML配置文件,然后根据id标识获取bean全限定名,Spring框架在获得bean全限定名后会通过反射创建bean对象,然后将该对象返回给开发人员

IOC(Inversion of Control:控制反转)

  • 定义

    • 对象的创建控制权由程序内部转移到外部
  • 解释

    • 使用对象时,由主动new产生对象转换为由外部提供对象,在此过程中对象创建控制权由程序内部转移到外部

    • 外部” 指的是IOC容器,它负责象的创建、初始化等一系列工作,被创建或管理的对象在IOC容器中称为bean

    • 示例:

      在原来的学习中我们在Service业务层时会在成员变量的位置new一个共有的数据访问层(持久层)的对象,如图一所示,如果数据层有两个实现类,那么我们在业务层就需要针对不同的场景new不同的对象,只要我们重新new一次对象,那系统就需要重新编译、重新测试、重新部署和发布,造成高耦合问题

      在这里插入图片描述

      为了避免高耦合,我们可以在使用对象的时候,在程序中不主动使用new来产生对象,转换为由外部提供对象。Spring就提供了一个Ioc容器,用来充当Ioc思想中的”外部“,它可以管理对象的创建和初始化的过程,若想用对象就从IOC容器中拿出来使用即可,如图二所示。但是此时就算拿出来使用也不会运行,原因详见DI依赖注入

      在这里插入图片描述

  • IOC容器

    • 它负责象的创建、初始化等一系列工作,被创建或管理的对象在IOC容器中统称为bean
  • .注意

    • IOCIOC容器、bean是三个不同的概念
    • IOC(控制反转)能够避免高耦合,但是并不能降低不同架构层的依赖关系,若想降低依赖关系需依靠DI(依赖注入)

Spring的IOC快速入门

  • 开发步骤

    • 导入Spring坐标

      <!--spring坐标-->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.6</version>
      </dependency>
      
    • 编写Dao/Mapper数据访问层(持久层)接口及其实现类

    • 创建Spring核心配置文件,文件命名为applicationContext.xml

    • 在Spring配置文件中配置用到的接口的实现类

    • 使用Spring的API获取bean实例(即对应接口实现类的对象)

  • 完整步骤示例

    • Step1: 创建Web项目,导入Spring坐标及Tomcat插件,pom.xml文件如下:(在之后的示例中均需要该步,只是省略了)

      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.example</groupId>
        <artifactId>SpringDemo</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemo Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
          </dependency>
      
          <!--spring坐标-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
          </dependency>
      
        </dependencies>
        <build>
          <finalName>SpringDemo</finalName>
          <plugins>
            <!-- Tomcat插件 -->
            <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
            </plugin>
          </plugins>
        </build>
      </project>
      
    • Step2: 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

      • 实现类要写对应架构包的impl包下

      在这里插入图片描述

    • Step3: 右键源代码配置文件目录(即资源文件resources)→NewXML Configuration FileSpring Config,文件名为applicationContext.xml,默认代码如下:

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

      在这里插入图片描述

    • Step4: 配置用到的接口的实现类:在applicationContext.xml文件中利用<bean>标签配置bean,代码如下所示

      该标签用到的属性解释
      idSpring容器中的bean的唯一标识符,可用来引用特定的bean实例
      classbean的实现类的全限定名
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
          <!--等同于
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"></bean>
          -->
      </beans>
      
    • Step5: 使用Spring的API获取bean的实例:创建测试类代码TestOne,代码及使用IOC容器步骤如下:

      • 测试类代码是在测试目录test下进行的测试
      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              //3 方法运行
              userDao.save();
          }
      }
      

      在这里插入图片描述

  • 普通获取IOC容器两种方式

    • 在以上测试代码中我们获取IOC容器是通过加载类路径下的配置文件来获取的。即new ClassPathXmlApplicationContext("applicationContext.xml");
    • 若我们从硬盘上获取则改为new FileSystemXmlApplicationContext("F:\\node\\idea\\ssm\\SpringDemo\\SpringWebTwo\\src\\main\\resources\\applicationContext.xml");
    • 若想获取多个
  • 从IOC容器中获取bean对应的对象

    • 使用bean的idname获取(需要强转):(UserDaoImpl) app.getBean("userDaoImpl");
    • 使用bean的idname获取时并指定类型(不需要强转):app.getBean("userDaoImpl", UserDaoImpl.class);
    • 按类型进行自动装配时(必须保证对应的bean唯一,否则失效):app.getBean(UserDaoImpl.class);
  • ApplicationContext接口及其相关的接口和类如图所示

    • ApplicationContext接口的最顶级父类为BeanFactory接口
    • BeanFactory接口为IOC容器的顶层接口,初始化BeanFactory对象时所有的bean均为延迟加载
    • ApplicationContext接口是Spring容器的核心接口,初始化ApplicationContext对象时所有的bean均为立即加载
    • ApplicationContext接口提供基础的bean操作的相关方法,通过其它接口拓展其功能
    • ApplicationContext的子接口ConfigurableApplicationContext拓展了一个ApplicationContext接口没有的colse()方法(即关闭容器的功能
    • ConfigurableApplicationContext下有常用的初始化实现类ClassPathXmlApplicationContextFileSystemXmlApplicationContext

    在这里插入图片描述

Spring配置文件applicationContext.xml <bean>标签详解一

  • 作用:用于配置对象并交由Spring来创建(即定义Spring核心容器管理的对象)

  • 默认情况下它调用的是类中的无参构造函数 ,若没有无参构造函数则会创建失败

  • 基本属性

    该标签用到的属性解释
    idSpring容器中的bean的个唯一的标识符,可用来引用特定的bean实例
    name定义bean的别名,定义多个别名时可用, ; 或空格分隔。
    classbean的实现类的全限定名
    scope指定对象的作用范围
    init-method指定类中初始化方法的名称
    destory-method指定类中销毁方法的名称
    factory-bean使用指定的工厂bean实例来调用工厂方法创建指定的bean实例
    factory-method使用指定工厂bean的方法来指定的bean实例
    p:propertyName="propertyValue"P命名空间依赖注入时使用的属性,此属性形式只适用于基本数据类型、字符串类型。propertyName: bean 中要设置的属性的名称。propertyValue:是要为该属性设置的值
    p:propertyName-ref="propertyValue"P命名空间依赖注入时使用的属性,此属性形式只适用于引用类型,其中ref代表是引用类型。propertyName: bean 中要设置的属性的名称。propertyValue:是要为该属性设置的值
    autowire自动装配 bean 的依赖关系
    autowire-candidate用于控制一个 bean 是否可以作为其他 bean 自动装配的候选者,默认为true
    lazy-init控制bean的延迟加载,默认为false(非延迟)
    scope属性取值解释
    singleton默认值,单例。即在IOC容器中对应bean的对象只有一个
    prototype多例。即在IOC容器中对应bean的对象有多个,每次在使用app.getBean()方法时都会获得对应bean的新对象
    requestWeb项目中,Spring创建一个bean的对象,将对象存入到request域中
    sessionWeb项目中,Spring创建一个bean的对象,将对象存入到session域中
    global sessionWeb项目中,应用在Portlet环境,若没有Portlet环境则global session相当于session
    autowire属性取值解释
    no默认值,默认不使用自动装配
    byType通过属性的类型进行自动装配
    byName通过属性名称进行自动装配
    constructor通过构造函数进行自动装配

name属性——别名配置

  • 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

    • Step1: 实现类要写对应架构包的impl包下

    在这里插入图片描述

    • Step2: applicationContext.xml文件代码如下
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--配置bean-->
        <bean id="userDaoImpl" name="userDao1 userDao2" class="at.guigu.dao.impl.UserDaoImpl"/>
        <!--等同于
        <bean id="userDaoImpl" name="userDao1 userDao2" class="at.guigu.dao.impl.UserDaoImpl"></bean>
        -->
    </beans>
    
    • Step3: 在测试目录下创建测试类TestTwo,代码如下:
    package at.guigu.dao;
    
    import at.guigu.dao.impl.UserDaoImpl;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestTwo {
        /**
         * 测试name属性
         */
        @Test
        public void Test2() {
            //1 获取IOC容器
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            //2 从IOC容器中获取bean对应的对象
            //利用name属性定义别名后getBean方法的参数不仅可以是id(即对应bean的唯一标识),还可以是对应bean的别名
            UserDaoImpl userDao1 = (UserDaoImpl) app.getBean("userDaoImpl");
            //等同于
            UserDaoImpl userDao2 = (UserDaoImpl) app.getBean("userDao1");
            //等同于
            UserDaoImpl userDao3 = (UserDaoImpl) app.getBean("userDao2");
    
        }
    }
    

    在这里插入图片描述

scope属性——作用范围配置

  • scope = "singleton"示例(以Spring的IOC快速入门代码为例进行讲解)

    • Step1: 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

      • 实现类要写对应架构包的impl包下

      在这里插入图片描述

    • Step2: applicationContext.xml文件代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" scope="singleton" class="at.guigu.dao.impl.UserDaoImpl"/>
          <!--等同于
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"></bean>
          -->
      </beans>
      
    • Step3: 在测试目录下创建测试类TestTwo,代码如下:

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestTwo {
          /**
           * 测试scope = "singleton"
           */
          @Test
          public void Test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao1 = (UserDaoImpl) app.getBean("userDaoImpl");
              UserDaoImpl userDao2 = (UserDaoImpl) app.getBean("userDaoImpl");
              //3 对象地址打印看是否是同一个地址
              System.out.println(userDao1);
              System.out.println(userDao2);
          }
      }
      

      运行该测试用例后,截图如下

      在这里插入图片描述

  • scope = "prototype"示例(以Spring的IOC快速入门代码为例进行讲解)

    • applicationContext.xml文件代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" scope="prototype" class="at.guigu.dao.impl.UserDaoImpl"/>
          
      </beans>
      
    • 测试类TestTwo代码不变,运行结果如下所示

      在这里插入图片描述

  • 注意: scope = "singleton"scope = "prototype"创建bean对象的时机不同

    • scope = "singleton"时(即默认情况下),bean对象随着这句代码ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");的执行就会立即创建并保存到IOC容器中
    • scope = "prototype"时,bean对象会随着getBean()方法的执行被创建
  • scope = "singleton"scope = "prototype"异同

    • scope = "singleton"
      • bean的实例化个数:1
      • bean的实例化时机:当Spring核心文件被加载时
      • bean的生命周期
        • 对象创建:当应用加载,创建容器时对象就被创建了
        • 对象运行:只要容器存在,对象就一直存活
        • 对象销毁:当应用卸载,销毁容器时,对象就会被销毁
    • scope = "prototype"
      • bean的实例化个数:多个
      • bean的实例化时机:当调用getBean()方法时
      • bean的生命周期
        • 对象创建:当使用对象时,就会创建新的对象实例
        • 对象运行:只要对象在使用中就一直存活
        • 对象销毁:当对象长时间不用时,就会被Java的垃圾回收器回收
  • 为什么IOC容器默认为单例?

    • Spring容器管理的对象为单例对象,也就是我们可以复用的对象,这次用完以后下次还会用这个对象,这样可以提高性能和资源利用效率,避免重复创建对象导致的资源浪费,同时简化开发和管理,确保应用中的一致性和数据共享。
  • 适合为单例对象的bean

    • Dao/Mapper数据层(持久层)对象
    • Service业务对象
    • Web/Controller表现层对象
    • util包的工具对象
    • 以上的bean适合交给Spring的IOC容器管理
  • 不适合为单例对象的bean

    • 在pojo包下封装实体的域对象:因为这种对象每次的属性值都不同

init-methoddestory-method属性——初始、销毁

  • init-method:指定类中初始化方法的名称
  • destory-method:指定类中销毁方法的名称
  • 容器关闭前会触发bean的销毁

初始、销毁方式一

  • 步骤如下

    • Step1:Dao/Mapper数据访问层(持久层)接口的实现类UserDaoImpl代码更改如下:

      package at.guigu.dao.impl;
      
      import at.guigu.dao.UserDao;
      
      public class UserDaoImpl implements UserDao {
          public UserDaoImpl () {
              System.out.println("UserDaoImpl被创建...");
          }
          // bean初始化时对应的操作
          public void init() {
              System.out.println("初始化方法");
          }
          // bean销毁前对应的操作
          public void destroy() {
              System.out.println("销毁方法");
          }
          public void save() {
              System.out.println("UserDao save running...");
          }
      }
      

      注意:init()和destroy()只是我们定义的两个方法,我们还需要在Spring配置文件中给其进行配置后,这两个方法才是真正的初始化方法和销毁方法

    • Step2: Spring配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" init-method="init" destroy-method="destroy" class="at.guigu.dao.impl.UserDaoImpl"/>
      
      </beans>
      
    • Step3: 在测试目录下创建测试类TestThree,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestThree {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              System.out.println(userDao);
          }
      }
      

      运行该测试用例后,截图如下

      在这里插入图片描述

  • 注意: 在上述运行截图中可看出该单元测试没有执行destroy()方法原因是:我们现在运行的程序是运行在Java虚拟机上的,当程序执行完毕后虚拟机会立即退出,并不会给bean销毁的机会。所以我们可以通过两种方式来销毁bean

    • 方式一: 在虚拟机退出之前手动释放容器资源,代码做如下更改:

      • 注意:ApplicationContex接口没有释放资源的close()方法,而我们所使用的其子接口的实现类ClassPathXmlApplicationContext有释放资源的close()方法,所以我们要进行强制转换
      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestThree {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              System.out.println(userDao);
              //方式一: 手动关闭
              ((ClassPathXmlApplicationContext) app).close();
          }
      }
      

      运行该测试用例后,截图如下

      在这里插入图片描述

    • 方式二: 设置关闭钩子 ,即允许在 JVM虚拟机 关闭之前执行一些清理操作,如释放资源、保存状态等。代码更改如下

      • 注意:registerShutdownHook()方法是AbstractApplicationContext接口的方法,所以需要先强制转换在调用
      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.AbstractApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestThree {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //方式二: 设置关闭钩子
              ((AbstractApplicationContext) app).registerShutdownHook();
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              System.out.println(userDao);
              /*方式一:手动关闭
              ((ClassPathXmlApplicationContext) app).close();*/
          }
      }
      

      运行该测试用例后,截图如下

      在这里插入图片描述

    • 两种执行销毁方法的方式区别

      • 手动释放容器资源必须在放在最后,属于暴力手段
      • 设置关闭钩子可在任意位置,属于柔软手段

初始、销毁方式二

  • 初始、销毁方式一比较复杂,因为当类比较多时就需要重复配置配置文件,所以就有了初始、销毁方式二

  • 步骤如下

    • Step1: Dao/Mapper数据访问层(持久层)接口的实现类UserDaoImpl代码如下:

      • 该实现类除了要实现UserDao接口外还要实现Initializingbean,和Disposablebean两个接口,并分别重写这两个接口中的afterPropertiesSet()方法和destroy()方法
      package at.guigu.dao.impl;
      
      import at.guigu.dao.UserDao;
      import at.guigu.pojo.User;
      import org.springframework.beans.factory.Disposablebean;
      import org.springframework.beans.factory.Initializingbean;
      
      import java.util.List;
      import java.util.Map;
      import java.util.Properties;
      
      public class UserDaoImpl implements UserDao, Initializingbean, Disposablebean {
          
          public UserDaoImpl () {
              System.out.println("UserDaoImpl被创建...");
          }
          
          /**
           * 初始化方法
           * @throws Exception
           */
          @Override
          public void afterPropertiesSet() throws Exception {
              System.out.println("Dao init...");
          }
          
          /**
           * 销毁方法
           * @throws Exception
           */
          @Override
          public void destroy() throws Exception {
              System.out.println("Dao destroy...");
          }
      
          public void save() {
              System.out.println("UserDao save running...");
          }
      }
      
    • Step2: Service业务层接口及实现类代码如下

      • 接口BookService

        package at.guigu.service;
        
        public interface BookService {
            public void save();
        }
        
      • 接口BookService的实现类BookServiceImpl

        该实现类除了要实现BookService接口外还要实现Initializingbean,和Disposablebean两个接口,并分别重写这两个接口中的afterPropertiesSet()方法和destroy()方法

        package at.guigu.service.impl;
        
        
        import at.guigu.dao.UserDao;
        import at.guigu.dao.impl.UserDaoImpl;
        import at.guigu.service.BookService;
        import org.springframework.beans.factory.Disposablebean;
        import org.springframework.beans.factory.Initializingbean;
        
        public class BookServiceImpl implements BookService, Initializingbean, Disposablebean {
            private UserDao userDao;
        
            /**
             * 属性设置
             * @param userDao
             */
            public void setUserDao(UserDaoImpl userDao) {
                System.out.println("Service对userDao属性设置");
                this.userDao = userDao;
            }
        
            /**
             * 初始化方法
             * @throws Exception
             */
            @Override
            public void afterPropertiesSet() throws Exception {
                System.out.println("Service init...");
            }
        
            /**
             * 销毁方法
             * @throws Exception
             */
            @Override
            public void destroy() throws Exception {
                System.out.println("Service destory...");
            }
        
            @Override
            public void save() {
                System.out.println("BookService save...");
                userDao.save();
            }
        
        }
        
    • Step3: Spring配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--1 配置userDao  bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
          <!--2 配置bookService  bean-->
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl">
              <!--3 绑定依赖关系-->
              <property name="userDao" ref="userDaoImpl"></property>
              <!--等同于
              <property name="userDao">
              	<ref bean="userDaoImpl"/>
              </property>
      		-->
          </bean>
      
      </beans>
      
    • Step4:在测试目录下创建测试类TestThree,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.AbstractApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestThree {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              // 设置关闭钩子
              ((AbstractApplicationContext) app).registerShutdownHook();
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              System.out.println(bookService);
          }
      }
      

      在这里插入图片描述

  • 注意

    • 在使用实现Initializingbean,和Disposablebean两个接口来进行初始化和销毁时,其中初始化方法afterPropertiesSet()在属性设置(即setXXX方法)之后执行,可详见上述运行截图
  • 使用实现接口的方式来执行初始化和销毁时的bean生命周期

    • 初始化容器
      • 创建对象
      • 执行构造方法
      • 执行属性注入(set操作)
      • 执行bean初始化方法
    • 使用bean
      • 执行业务操作
    • 关闭/销毁容器
      • 执行bean销毁方法

bean实例化的三种方式(factory-beanfactory-method

  • factory-bean:使用指定的工厂bean实例来调用工厂方法创建指定的bean实例

  • factory-method:使用指定工厂bean的方法来指定的bean实例

  • bean实例化的三种方式

    • 无参构造方法实例化
    • 工厂静态方法实例化
    • 工厂实例方法实例化
    • 注意:
      • 默认情况下使用第一种方式时,若无参构造方法不存在则会抛出beanCreationException异常
      • 默认情况下用的都是第一种,通过配置可使用后两种实例化方法,此处主要解释后两种

工厂静态方法实例化

  • 工厂静态方法实例化步骤

    • Step1: 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

      • 实现类要写对应架构包的impl包下

      在这里插入图片描述

    • Step2: 在工具类包util下创建工厂类(博主创建名为:StaticFactoryUtils),代码如下

      package at.guigu.util;
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      
      public class StaticFactoryUtil {
      
          //此为静态的
          public static UserDao getUserDao() {
              return new UserDaoImpl();
          }
          
      }
      
    • Step3: Spring配置文件applicationContext.xml 文件代码更改如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" factory-method="getUserDao" class="at.guigu.util.StaticFactoryUtil"/>
      
      </beans>
      

      注意:工厂静态方法实例化时,由于StaticFactoryUtils类中实例化的方法为静态方法,所以直接由类名调用静态方法即可创建UserDao对象

    • Step4: 创建测试类TestFour测试,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestFour {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              System.out.println(userDao);
          }
      }
      

      在这里插入图片描述

工厂实例方法实例化

  • 工厂实例方法实例化方式一,步骤如下

    • Step1: 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

      • 实现类要写对应架构包的impl包下

      在这里插入图片描述

    • Step2: 在工具类包util下创建工厂类(博主创建名为:DynamicFactoryUtils),代码如下

      package at.guigu.util;
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      
      public class DynamicFactoryUtils {
      
          //此为非静态的
          public UserDao getUserDao() {
              return new UserDaoImpl();
          }
      }
      
    • Step3: Spring配置文件applicationContext.xml 文件代码更改如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <!--1 创建工厂对象并存入IOC容器-->
          <bean id="dynamicFactoryUtils"  class="at.guigu.util.DynamicFactoryUtils"/>
          <!--2 调用IOC容器中的工厂对象中的实例化方法实例化对象-->
          <bean id="userDaoImpl" factory-bean="dynamicFactoryUtils" factory-method="getUserDao"/>
      </beans>
      

      注意:DynamicFactoryUtils类中实例化的方法为非静态方法时,必须先获取工厂类的对象再由工厂类的对象来调用getUserDao()方法

    • Step4: 创建测试类TestFive测试,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestFive {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
              System.out.println(userDao);
          }
      }
      

      在这里插入图片描述

  • 工厂实例方法实例化方式一 中有很大的缺点,如图所示,由此衍生出了第二种工厂实例方法实例化的方式

    在这里插入图片描述

    • 第二种工厂实例化方式的工具类继承自Factorybean<T>接口,其源码如下:

      public interface Factorybean<T> {
      
          T getObject() throws Exception;
      
          Class<?> getObjectType();
      
          boolean isSingleton();
      }
      
      方法解释
      T getObject() throws Exception;Factorybean 接口的核心方法。Spring 容器调用这个方法来获取这个工厂生成的 bean 实例。返回类型 T 表示工厂生成的对象类型
      Class<?> getObjectType();返回由 Factorybean 创建的对象的类型。如果在创建对象之前类型未知,则返回 null
      boolean isSingleton();返回这个由 Factorybean 创建的 bean 是否为单例,默认为ture(即单例)
  • 工厂实例方法实例化方式二,步骤如下

    • Step1: 创建三层架构的包结构,并编写Dao/Mapper数据访问层(持久层)接口及其实现类。如图所示

      • 实现类要写对应架构包的impl包下

      在这里插入图片描述

    • Step2: 在工具类包util下创建实现Factorybean接口的工厂类(博主创建名为:DynamicFactoryUtilsTwo),代码如下

      • 接口Factorybean<T>的泛型T为:想通过该工具类获取的对象的类名
      package at.guigu.util;
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.beans.factory.Factorybean;
      
      public class DynamicFactoryUtilsTwo implements Factorybean<UserDaoImpl> {
          /**
           * 代替原始实例工厂中创建对象的方法
           * @return
           * @throws Exception
           */
          @Override
          public UserDaoImpl getObject() throws Exception {
              return new UserDaoImpl();
          }
      
          @Override
          public Class<?> getObjectType() {
              return UserDaoImpl.class;
          }
      }
      
      • Step3: Spring配置文件applicationContext.xml 文件代码更改如下

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!--配置bean-->
            <!--此时id为接口Factorybean<UserDaoImpl>的泛型,即<UserDaoImpl>-->
            <!--此时class为实例工厂的类的全限定名-->
            <bean id="userDaoImpl" class="at.guigu.util.DynamicFactoryUtilsTwo"/>
        </beans>
        
      • Step4: 创建测试类TestFive测试,代码如下

        package at.guigu.dao;
        
        import at.guigu.dao.impl.UserDaoImpl;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestFive {
            public static void main(String[] args) {
                //1 获取IOC容器
                ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
                //2 从IOC容器中获取bean对应的对象
                UserDaoImpl userDao = (UserDaoImpl) app.getBean("userDaoImpl");
                UserDaoImpl userDao2 = (UserDaoImpl) app.getBean("userDaoImpl");
                System.out.println(userDao);
                System.out.println(userDao2);
            }
        }
        

        在这里插入图片描述

  • 工厂实例方法实例化方式二 运行截图中可看出bean作用范围默认为单例,若想改为多例 则有两种方式:

    • 方式一: 利用scope属性(此处省略,可详见作用范围配置部分)

    • 方式二: 重写Factorybean接口中的isSingleton()方法,实现Factorybean接口的工厂类(博主创建名为:DynamicFactoryUtilsTwo),代码如下

      package at.guigu.util;
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.beans.factory.Factorybean;
      
      public class DynamicFactoryUtilsTwo implements Factorybean<UserDaoImpl> {
          /**
           * 代替原始实例工厂中创建对象的方法
           * @return
           * @throws Exception
           */
          @Override
          public UserDaoImpl getObject() throws Exception {
              return new UserDaoImpl();
          }
      
          @Override
          public Class<?> getObjectType() {
              return UserDaoImpl.class;
          }
      
          /**
           * 设置bean的作用范围
           * @return
           */
          @Override
          public boolean isSingleton() {
              return false;
          }
      }
      

      此时在运行测试类TestFive,截图如下

      在这里插入图片描述


DI(Dependency Injection:依赖注入)

  • 定义

    • 在容器中建立bean与bean之间的依赖关系的整个过程就叫做依赖注入
    • 它是Spring框架核心IOC的具体实现
  • 解释

    • 示例:

      图二中就算由外部提供对象也不可能成功运行,因为就算得到了Service对象,但由于Service接口的BookServiceImpl实现类内部需要一个Dao/Mapper对象供其使用,也就是说Service的实现类依赖于Dao/Mapper对象才能运行,因为此时ServiceDao/Mapper对象之间并没有建立依赖关系,所以程序无法运行,所以就会报错,如图三所示

      若想成功运行就需要给两者绑定依赖关系,此时只要Service实现类得到Service对象,就会连带着得到Dao/Mapper对象,此时即可成功运行

      在这里插入图片描述

  • 它是基于IOC管理bean而实现的DI ,使用DI(依赖注入)后,Spring框架会自动把Dao/Mapper数据访问层(持久层)对象传入Service业务层,而不需要我们自己去获取

  • 注意

    • Service业务层实现类BookServiceImpl中不能在使用new的形式创建Dao/Mapper数据层实现类的对象
    • Service业务层中需要的Dao/Mapper数据层对象是通过Service业务层提供的方法进入到Service业务层中的
    • Service业务层与Dao/Mapper数据层通过配置文件来进行依赖关系的绑定

Spring配置文件applicationContext.xml <bean>标签详解二

  • <bean>标签的内嵌标签

    <bean>标签中用到的内嵌标签解释
    <property>在 XML 配置文件中为 bean 的属性赋值,从而完成依赖注入和配置管理
    <constructor-arg>在 XML 配置文件中指定 bean 的构造函数参数。它允许我们在创建 bean 实例时通过构造函数注入依赖,而不是通过 setter 方法进行属性注入。
  • <property>中用到的属性

    <property>标签用到的属性解释
    name指定要设置的 bean 属性的名称
    ref用于指定一个 引用类型 的属性值,引用另一个 bean 的实例
    value用于直接设置基本数据类型或字符串数据类型的属性值
  • <constructor-arg>中用到的属性

    <constructor-arg>标签用到的属性解释
    name指定构造函数的参数名称
    type指定构造函数的参数类型。构造器参数若为对象,则属性值为对象的全类名;若为字符串类型,则为java.lang.String
    index指定构造函数的参数索引位置(以0为第一个参数索引位置)
    refIOC容器中可获取到依赖对象的bean的id值(即唯一标识)
  • <property>标签的内嵌标签

    <property>标签中用到的内嵌标签解释
    <value>设置基本数据类型、字符串类型的属性值
    <ref>引用其他 bean
    <list>配置List集合的属性值
    <map>配置Map集合的属性值
    <prop>配置Properties集合的属性值

Spring的DI(依赖注入)的三种方式

  • 依赖注入方式选择

    • setter方法注入
      • 可选依赖:即该bean对这个属性依赖不强,可有可无,不注入时也不会影响程序的运行
    • P命名空间注入
    • 有参构造方法注入
      • 强制依赖:即该bean必须依赖的属性,若为给该属性进行依赖注入,程序就无法运行
  • 注意

    • 使用有参构造方法注入时若不进行注入则配置文件就会报错,程序就无法运行
    • Spring框架倡导使用构造器注入,第三方框架内部大多采用构造器注入的形式进行数据初始化,这样相对严谨
    • 若有必要时setter方法注入和有参构造方法注入可同时使用。即使用setter方法注入完成可选依赖的注入;使用有参构造方法注入完成强制依赖的注入
    • 自己开发的模块推荐使用setter方法注入
    • 实际开发过程中还要根据实际情况分析,若受控对象未提供setter方法时就必须使用构造器注入

Spring的DI快速入门——setter方法注入

  • <property>标签:在 XML 配置文件中为 bean 的属性赋值,从而完成依赖注入和配置管理
<property>标签用到的属性解释
name指定要设置的 bean 属性的名称
ref用于指定一个引用类型的属性值,引用另一个 bean 的实例
  • set方法注入步骤如下:

    • Step1: Service业务层创建接口BookService及其实现类BookServiceImpl

      • 接口BookService
      package at.guigu.service;
      
      public interface BookService {
          public void save();
      }
      
    • Step2: 给所依赖的对象提供对应的setter方法:即在 Service业务层BookServiceImpl类中创建一个SetXXX方法,将BookDaoImpl对象给到我们定义的bookDao

      package at.guigu.service.impl;
      
      
      import at.guigu.dao.UserDao;
      import at.guigu.service.BookService;
      
      public class BookServiceImpl implements BookService {
          private UserDao userDao;
          @Override
          public void save() {
              System.out.println("BookService save...");
              userDao.save();
          }
          // 给所依赖的对象提供对应的setter方法
          public void setUserDao(UserDao userDao) {
              this.this.userDao = userDao;
          }
      }
      
    • Step3: 配置依赖关系:在Spring容器中将BookDaoImpl绑定到BookServiceImpl内部,Spring配置文件applicationContext.xml 代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--1 配置userDao  bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
          <!--2 配置bookService  bean-->
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl">
              <!--3 绑定依赖关系-->
              <property name="userDao" ref="userDaoImpl"></property>
              <!--等同于
              <property name="userDao">
              	<ref bean="userDaoImpl"/>
              </property>
      		-->
          </bean>
      </beans>
      

      注意:

      name属性值:Service业务层中给所依赖的对象提供对应的setXXX方法中的XXX,开头字母变小写即可,比如setUserDao(),此时name=userDao

      ref属性值:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)

    • 创建测试类TestSix,代码如下:

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.BookService;
      import at.guigu.service.impl.BookServiceImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestSix {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      在这里插入图片描述

Spring的DI快速入门——P命名空间注入

  • 该方式本质上也是setter方法注入,但要比setter方法更方便

  • 注意:

    • 由于其本质也是setter方法注入,所以也要给所依赖的对象提供对应的setter方法 ,所BookServiceImpl类代码与 setter方法注入 中的一样
    • P命名空间注入只能用于基本数据类型、字符串类型和引用类型,不支持集合类型(如 ListSetMap)的配置。对于集合类型,仍需要使用传统的 <property> 标签及相关子元素(如 <list><set><map>)进行配置。
  • P命名空间注入步骤如下

    • Step1: 在Spring配置文件applicationContext.xml 中引入P命名空间,即xmlns:p="http://www.springframework.org/schema/p"

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:p="http://www.springframework.org/schema/p"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
         
      </beans>
      
    • Step2: 引入P命名空间后Spring配置文件applicationContext.xml 代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:p="http://www.springframework.org/schema/p"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
      
          <bean id="bookServiceImpl" p:userDao-ref="userDaoImpl" class="at.guigu.service.impl.BookServiceImpl"/>
      
      </beans>
      
    • 测试类TestSix代码如下:

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.BookService;
      import at.guigu.service.impl.BookServiceImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestSix {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      在这里插入图片描述

Spring的DI快速入门——有参构造方法注入

  • 注意

    • 有参构造方法注入不需要BookServiceImpl类中的setter方法
  • 有参构造方法注入步骤如下

    • Step1: Service业务层BookServiceImpl类代码如下

      package at.guigu.service.impl;
      
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.BookService;
      
      public class BookServiceImpl implements BookService {
          private UserDao userDao;
      
          public BookServiceImpl() {
          }
      
          public BookServiceImpl(UserDaoImpl userDao) {
              this.userDao = userDao;
          }
      
          @Override
          public void save() {
              System.out.println("BookService save...");
              userDao.save();
          }
          
      }
      
    • **Step2: ** Spring配置文件applicationContext.xml 代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
      
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl">
              <!--name属性值为:有参构造器的参数名-->
              <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
              <constructor-arg name="userDao" ref="userDaoImpl"></constructor-arg>
          </bean>
      
      </beans>
      

      注意:

      name属性值:为BookServiceImpl类中有参构造器的参数名

      ref属性值:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)

    • 测试类TestSix代码如下:

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.BookService;
      import at.guigu.service.impl.BookServiceImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestSix {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      在这里插入图片描述

有参构造方法注入弊端

  • 若构造器参数名改变 ,对应配置文件中<constructor-arg>标签的name属性值就需要随之改变,则解决办法如下

    • type标签代替name标签 ,此时配置文件中代码如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
      
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl">
              <!--type属性值为:有参构造器的参数对象对应的全限定名-->
              <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
              <constructor-arg type="at.guigu.dao.impl.UserDaoImpl" ref="userDaoImpl"></constructor-arg>
          </bean>
      
      </beans>
      
    • index标签代替name标签

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
      
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImplTwo">
              <!--index属性值为:有参构造器参数的索引位置-->
              <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
              <constructor-arg index="0" ref="userDaoImpl"></constructor-arg>
          </bean>
      
      </beans>
      
  • 若构造器参数为基本数据类型和字符串类型

    • BookServiceImpl代码如下

      package at.guigu.service.impl;
      
      
      import at.guigu.dao.UserDao;
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.BookService;
      
      public class BookServiceImpl implements BookService {
          private String aaa;
          private int bbb;
          private boolean ccc;
      
          public BookServiceImpl() {
          }
      
          public BookServiceImpl(String aaa, int bbb, boolean ccc) {
              this.aaa = aaa;
              this.bbb = bbb;
              this.ccc = ccc;
          }
      
          @Override
          public void save() {
              System.out.println(aaa + "===" + bbb + "===" + ccc);
          }
          
      }
      
    • 此时配置文件中代码如下:

      • 采用name属性配置

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        
            <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImplTwo">
                <!--name属性值为:有参构造器的参数名-->
                <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
                <constructor-arg name="aaa" value="zhangsan"></constructor-arg>
                <constructor-arg name="bbb" value="2"></constructor-arg>
                <constructor-arg name="ccc" value="false"></constructor-arg>
            </bean>
        
        </beans>
        
      • 采用type属性配置

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        
            <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImplTwo">
                <!--type属性值为:构造函数的参数类型-->
                <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
                <constructor-arg type="java.lang.String" value="zhangsan"></constructor-arg>
                <constructor-arg type="int" value="2"></constructor-arg>
                <constructor-arg type="boolean" value="false"></constructor-arg>
            </bean>
        
        </beans>
        
      • 采用index属性配置

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        
            <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImplTwo">
                <!--index属性值为:有参构造器参数的索引位置-->
                <!--ref属性值为:IOC容器中可获取到依赖对象的bean的id值(即唯一标识)-->
                <constructor-arg index="0" value="zhangsan"></constructor-arg>
                <constructor-arg index="1" value="2"></constructor-arg>
                <constructor-arg index="2" value="false"></constructor-arg>
            </bean>
        
        </beans>
        
  • 注意

    • 当有参构造器的参数中有多个引用型参数时,nametypeindex三个属性均可使用,自行选择(尽量选择低耦合的方式)
    • 当有参构造器的参数中有多个基本数据类型及字符串类型时
      • 若基本数据类型无重复且只有一个字符串类型时,以上三种属性均可使用,自行选择(尽量选择低耦合的方式)
      • 若基本数据类型中存在重复情况且字符串类型也有重复,则此时type属性就无法使用,只能从nameindex两个属性中自行选择(尽量选择低耦合的方式)

依赖自动装配

  • 定义
    • IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean的过程即为自动装配
  • 自动装配的方式有三种
    • 按类型autowire="byType":通过属性的类型进行自动装配
    • 按名称autowire="byName":通过属性名称进行自动装配
    • 按构造方法autowire="constructor":通过构造函数进行自动装配
    • 默认情况下autowire="no":即不适用自动装配
  • 注意
    • 依赖自动装配只能用于引用类型的依赖注入,不能对基本数据类型以及字符串类型进行操作
    • 按类型或名称自动装配时必须有setter方法存在,且只能通过setter方法进行自动装配
    • 按构造方法自动装配时必须有有参构造器的存在,且只能通过有参构造器进行自动装配
    • 使用按类型自动装配时,必须保障IOC容器中相同类型的bean唯一
    • 使用按名称自动装配时,必须保障容器中具有指定名称的bean
      • 不推荐使用按名称自动装配,因为变量名与配置完全耦合
    • 依赖自动装配优先级低于依赖注入的三种方式 ,若同时出现则依赖自动装配会自动失效

按类型自动装配

  • 注意

    • 按类型自动装配 必须setter方法的存在,且只能通过setter方法进行自动装配
    • 使用按类型进行自动装配时,对应bean的id唯一标识或name别名可以不存在
      • 因为按类型进行自动装配依赖于 Spring 容器中 bean 的类型匹配,而不是依赖于 bean 的 idname
    • 按类型自动装配时,必须保障IOC容器中相同类型的bean唯一
      • Spring 容器会查找与属性类型匹配的 bean。如果有多个相同类型的 bean,Spring 会抛出NoUniquebeanDefinitionException异常,因为它无法确定应该注入哪个 bean。
  • 属性类型对应IOC容器中的bean唯一

    • Dao/Mapper数据访问层(持久层)、Service业务层的接口及实现类如下

      在这里插入图片描述

    • 配置文件代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
      
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl" autowire="byType"/>
      
      </beans>
      
    • 测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

  • 属性类型对应IOC容器中的bean不唯一

    • Dao/Mapper数据访问层(持久层)、Service业务层的实现类及配置文件代码如下

      在这里插入图片描述

    • 测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

  • 属性类型对应IOC容器中的bean不唯一的解决方式

    • 可以使用autowire-candidate=falser将对应的bean设置成不可作为其它bean自动装配的候选者
    • 可以使用按名称自动装配

按名称自动装配

  • 注意

    • 按名称自动装配必须有setter方法的存在,且只能通过setter方法进行自动装配
    • 使用按名称自动装配时,必须保障容器中具有指定名称的bean
      • 即要进行自动装配的属性名必须与对应bean的id唯一标识或name别名完全一致
  • 未使用别名方式

    • Dao/Mapper数据访问层(持久层)、Service业务层的实现类及配置文件代码如下

      在这里插入图片描述

      测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

  • 使用别名方式

    • Dao/Mapper数据访问层(持久层)、Service业务层的实现类及配置文件代码如下

      在这里插入图片描述

    • 测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

按构造方法自动装配

  • 注意

    • 按构造方法自动装配时必须有有参构造器的存在,且只能通过有参构造器进行自动装配
    • Spring 的IOC容器会根据构造函数的参数类型来自动装配相应的 bean。
    • 确保构造函数参数的类型在容器中有且只有一个匹配的 bean。如果有多个匹配的 bean,Spring 会抛出 NoUniquebeanDefinitionException 异常。
  • 构造器参数对象对应IOC容器中的bean唯一

    • Dao/Mapper数据访问层(持久层)、Service业务层的实现类及配置文件代码如下

      在这里插入图片描述

    • 测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

  • 构造器参数对象对应IOC容器中的bean不唯一

    • Dao/Mapper数据访问层(持久层)、Service业务层的实现类及配置文件代码如下
      在这里插入图片描述

    • 测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      运行结果如下

      在这里插入图片描述

  • 构造器参数类型对应IOC容器中的bean不唯一的解决方式

    • 可以使用autowire-candidate=falser将对应的bean设置成不可作为其它bean自动装配的候选者
    • 可以使用按名称自动装配

bean的依赖注入的数据类型

  • 在之前的学习中都是注入的引用bean、除了对象的引用可以注入,普通数据类型的注入以及集合等都可以在容器中进行注入

  • 注入数据的三种数据类型

    • 普通数据类型(即基本数据类型与字符串类型)
    • 引用数据类型(此处不在举例,之前均为对象的引用注入,可详见依赖注入的三种方式的示例)
    • 集合数据类型

普通数据类型注入

  • setter方法进行注入 ——其它两种绑定依赖注入的方式可自行练习

    • Step1: 重新编写Dao/Mapper数据访问层(持久层)接口及其实现类,并在Dao/Mapper数据访问层(持久层)的UserDaoImpl实现类中添加普通数据类型的setter方法,如图所示

      在这里插入图片描述

    • Step2: Spring配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl">
              <property name="name" value="zhangsan"/>
              <property name="age" value="18"/>
              <!--等同于
              <property name="name">
              	<value>zhangsan</value>
              </property>
      		-->
          </bean>
      
      </beans>
      
    • Step3: 创建测试用例TestSeven,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import at.guigu.service.impl.BookServiceImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestSeven {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDaoImpl = (UserDaoImpl) app.getBean("userDaoImpl");
              userDaoImpl.save();
          }
      }
      

      在这里插入图片描述

数组类型注入

  • setter方法进行注入 ——其它两种绑定依赖注入的方式可自行练习

    • Step1: 重新编写Dao/Mapper数据访问层(持久层)接口及其实现类,并在Dao/Mapper数据访问层(持久层)的UserDaoImpl实现类中添加数组数据类型的setter方法,如图所示

      在这里插入图片描述

    • Step2: Spring配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <bean id="bookServiceImpl" class="at.guigu.service.impl.BookServiceImpl">
              <property name="array">
                  <array>
                      <value>100</value>
                      <value>200</value>
                      <value>300</value>
                  </array>
              </property>
          </bean>
      </beans>
      
    • Step3:测试代码如下

      package at.guigu.service;
      
      import at.guigu.service.impl.BookServiceImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestOne {
          @Test
          public void test1() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              BookServiceImpl bookService = (BookServiceImpl) app.getBean("bookServiceImpl");
              bookService.save();
          }
      }
      

      在这里插入图片描述

集合数据类型注入

  • setter方法进行注入 ——其它两种绑定依赖注入的方式可自行练习

    • Step1: 重新编写Dao/Mapper数据访问层(持久层)接口及其实现类,并在Dao/Mapper数据访问层(持久层)的UserDaoImpl实现类中添加集合数据类型的setter方法,如图所示

      • 注意:Map集合传入了User对象,所以此处需要一个User实体类

      在这里插入图片描述

    • Step2: Spring配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="user1" class="at.guigu.pojo.User">
              <property name="name" value="Tom"/>
              <property name="addr" value="美国"/>
          </bean>
          <bean id="user2" class="at.guigu.pojo.User">
              <property name="name" value="Jerry"/>
              <property name="addr" value="英国"/>
          </bean>
      
      
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl">
              <property name="strList">
                  <list>
                      <value>aaa</value>
                      <value>bbb</value>
                      <value>ccc</value>
                  </list>
              </property>
              
              <property name="userMap">
                  <map>
                      <entry key="userr1" value-ref="user1"></entry>
                      <entry key="userr2" value-ref="user2"></entry>
                  </map>
              </property>
              
              <property name="properties">
                  <props>
                      <prop key="p1">ppp1</prop>
                      <prop key="p2">ppp2</prop>
                  </props>
              </property>
          </bean>
      
      </beans>
      
    • Step4: 创建测试用例TestEight,代码如下

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestEight {
          public static void main(String[] args) {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDaoImpl = (UserDaoImpl) app.getBean("userDaoImpl");
              userDaoImpl.save();
          }
      }
      

      在这里插入图片描述

  • P命名空间注入步骤

  • 有参构造方法注入步骤

Spring配置文件中引入其它配置文件

引入Spring拆分配置文件applicationContext-xxx.xml

  • 在实际开发中,Spring的配置内容很多,这会导致Spring配置很繁琐且体积偏大。所以我们可以将部分配置拆解到其它配置文件中,然后在Spring主配置文件中通过<import>标签进行加载

  • 拆解方式

    • 可根据三层架构进行拆解:比如拆解为ServiceDao/MapperWeb
    • 也可根据不同类型进行拆解:比如拆解为用户和商品
  • 引入其它配置文件的代码格式:<import resource="applicationContext-xxx.xml"/>

  • 示例:此处以集合数据类型注入 中的配置文件为例

    • 原Spring主配置文件applicationContext.xml代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="user1" class="at.guigu.pojo.User">
              <property name="name" value="Tom"/>
              <property name="addr" value="美国"/>
          </bean>
          <bean id="user2" class="at.guigu.pojo.User">
              <property name="name" value="Jerry"/>
              <property name="addr" value="英国"/>
          </bean>
      
      
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl">
              <property name="strList">
                  <list>
                      <value>aaa</value>
                      <value>bbb</value>
                      <value>ccc</value>
                  </list>
              </property>
              
              <property name="userMap">
                  <map>
                      <entry key="userr1" value-ref="user1"></entry>
                      <entry key="userr2" value-ref="user2"></entry>
                  </map>
              </property>
              
              <property name="properties">
                  <props>
                      <prop key="p1">ppp1</prop>
                      <prop key="p2">ppp2</prop>
                  </props>
              </property>
          </bean>
      
      </beans>
      
    • 将User拆解出来以后,分配置文件名为applicationContext-user.xml,代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="user1" class="at.guigu.pojo.User">
              <property name="name" value="Tom"/>
              <property name="addr" value="美国"/>
          </bean>
          <bean id="user2" class="at.guigu.pojo.User">
              <property name="name" value="Jerry"/>
              <property name="addr" value="英国"/>
          </bean>
      
      </beans>
      
    • Spring主配置文件applicationContext.xml引入拆解后的分配置文件的代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--引入拆解后的分配置文件-->
          <import resource="applicationContext-user.xml"/>
      
      
          <!--配置bean-->
      
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl">
              <property name="strList">
                  <list>
                      <value>aaa</value>
                      <value>bbb</value>
                      <value>ccc</value>
                  </list>
              </property>
      
              <property name="userMap">
                  <map>
                      <entry key="userr1" value-ref="user1"></entry>
                      <entry key="userr2" value-ref="user2"></entry>
                  </map>
              </property>
      
              <property name="properties">
                  <props>
                      <prop key="p1">ppp1</prop>
                      <prop key="p2">ppp2</prop>
                  </props>
              </property>
          </bean>
      
      </beans>
      

引入properties配置文件

  • 详见Spring通过配置文件配置数据源(连接池)

引入多个配置文件(以properties配置文件为例)

  • 加载一个properties配置文件:<context:property-placeholder location="jdbc1.properties"/>

  • 加载多个properties配置文件(只能读取当前工程目录下的配置文件),如图所示

    在这里插入图片描述

    • 方式一:<context:property-placeholder location="jdbc1.properties, jdbc2.properties, ..."/>
    • 方式二:<context:property-placeholder location="*.properties"/>
    • 方式三(标准格式)<context:property-placeholder location="classpath:*.properties"/>
  • 加载多个properties配置文件(读取所有的配置文件):<context:property-placeholder location="classpath*:*.properties"/>

  • 注意:加载配置文件时可根据需要选择使用classpath:还是classpath*:

Spring相应API

ApplicationContext的实现类

ApplicationContext接口的实现类使用情形
ClassPathXmlApplicationContext从类的根路径下加载配置文件(即)
FileSystemXmlApplicationContext从磁盘路径上加载配置文件
AnnotationConfigApplicationContext当使用注解配置容器对象时,为了能够读取注解,就需要使用该类来创建Spring容器。
  • 前两种使用方式如下,第三种实现类后续会详细讲解

    package at.guigu.dao;
    
    import at.guigu.dao.impl.UserDaoImpl;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    
    public class TestEight {
        public static void main(String[] args) {
            //1 获取IOC容器
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            // 等同于
            FileSystemXmlApplicationContext app2 = new FileSystemXmlApplicationContext("F:\\node\\idea\\ssm\\SpringDemo\\src\\main\\resources\\applicationContext.xml");
        }
    }
    

getBean()方法的使用

getBean()方法解释
public Object getBean(String name) throws beansException从 Spring 容器中获取 bean 实例,传入的参数为Spring配置文件中对应bean的id(即唯一标识)
public <T> T getBean(Class<T> requiredType) throws beansException从 Spring 容器中获取 bean 实例,传入的参数为对应bean的类类对象即bean.Class
  • 第一种getBean方法需要类型强制转换,而第二种不需要,如下所示
package at.guigu.dao;

import at.guigu.dao.impl.UserDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestEight {
    public static void main(String[] args) {
        //1 获取IOC容器
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 等同于
        FileSystemXmlApplicationContext app2 = new FileSystemXmlApplicationContext("F:\\node\\idea\\ssm\\SpringDemo\\src\\main\\resources\\applicationContext.xml");
        //2 从IOC容器中获取bean对应的对象
        UserDaoImpl userDaoImpl = (UserDaoImpl) app.getBean("userDaoImpl");
        // 等同于
        UserDaoImpl userDaoImpl2 = app.getBean(UserDaoImpl.class);

    }
}

  • 若对应的bean在Spring配置文件中为单例(即只有一个)时,则以上两种getBean方法都可使用(建议使用第二种);若在Spring配置文件中有多个时,则使用第一个getBean方法

    • 最好不同情况用不同的getBean方法,这样更能区分开

    • 对应的bean在Spring配置文件中只有一个的代码示例如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"/>
          <!--等同于
          <bean id="userDaoImpl" class="at.guigu.dao.impl.UserDaoImpl"></bean>
          -->
      </beans>
      
    • 对应的bean在Spring配置文件中有多个的代码示例如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--配置bean-->
          <bean id="userDaoImpl1" class="at.guigu.dao.impl.UserDaoImpl"/>
         
          <bean id="userDaoImpl2" class="at.guigu.dao.impl.UserDaoImpl"></bean>
      
      </beans>
      
  • 注意:使用第一种方法来获取对应bean的对象时,若无法获取到将会抛出NoSuchbeanDefinitionException异常,即NoSuchbeanDefinitionException: No bean named 'userDaoImpll' available

    • 抛出该异常的原因:getBean方法参数与id(即唯一标识)或name(即别名)不一致

    • 代码示例

      package at.guigu.dao;
      
      import at.guigu.dao.impl.UserDaoImpl;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestTwo {
          /**
           * 测试NoSuchbeanDefinitionException异常
           */
          @Test
          public void Test3() {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象
              UserDaoImpl userDao1 = (UserDaoImpl) app.getBean("userDaoImpll");
              System.out.println(userDao1);
          }
      }
      

      在这里插入图片描述

数据源(连接池)

  • 定义

    • 数据源(DataSource)是一个抽象的概念,主要用于提供对数据库的连接(可详见JDBC部分内容)
  • 作用

    • 提高程序性能
    • 事先实例化数据源,初始化部分连接资源
    • 使用连接资源时可从数据源中获取,使用完毕后将连接资源归还给数据源
  • 常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等

数据源(连接池)配置步骤

  • 数据源(连接池)的配置步骤

    • 在pom.xml文件中导入数据源(连接池)的坐标和数据库驱动坐标
    • 创建数据源对象并设置数据源的基本连接数据
    • 使用数据源获取连接资源和归还资源
  • 完整代码示例

    • Step1: 在pom.xml文件中导入数据源(连接池)的坐标和数据库mysql驱动坐标,代码如下

      • 博主测试C3P0、Druid两个数据库连接池,所以它俩的坐标均会导入
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.example</groupId>
        <artifactId>SpringDemoo</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemoo Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
          </dependency>
      
          <!--mysql坐标-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
          </dependency>
      
          <!--druid坐标-->
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.18</version>
          </dependency>
      
          <!--c3p0坐标-->
          <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
          </dependency>
      
          <!--spring坐标-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
          </dependency>
            
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
          </dependency>
        </dependencies>
        <build>
          <finalName>SpringDemoo</finalName>
          <plugins>
            <!-- Tomcat插件 -->
            <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
            </plugin>
          </plugins>
        </build>
      </project>
      
    • Step2: 创建数据源对象并设置数据源的基本连接数据。然后使用数据源获取连接资源和归还资源

      package at.guigu.datasource;
      
      import com.alibaba.druid.pool.DruidDataSource;
      import com.mchange.v2.c3p0.ComboPooledDataSource;
      import org.junit.Test;
      
      import java.sql.Connection;
      
      public class TestOne {
          /**
           * 测试CP30数据源对象
           */
          @Test
          public void test1() throws Exception {
              // 创建数据源对象
              ComboPooledDataSource dataSource = new ComboPooledDataSource();
              // 设置数据源基本连接数据
              dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
              dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
              dataSource.setUser("root");
              dataSource.setPassword("123456");
              // 使用数据源获取数据库连接资源
              Connection connection = dataSource.getConnection();
              System.out.println(connection);
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      
          /**
           * 测试Druid数据源对象
           */
          @Test
          public void test2() throws Exception {
              // 创建数据源对象
              DruidDataSource dataSource = new DruidDataSource();
              // 设置数据源基本连接数据
              dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
              dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
              dataSource.setUsername("root");
              dataSource.setPassword("123456");
              // 使用数据源获取数据库连接资源
              Connection connection = dataSource.getConnection();
              System.out.println(connection);
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      }
      

      在这里插入图片描述

通过加载配置文件配置数据源(连接池)

  • 若使用 数据源开发步骤 中的代码来获取数据库连接资源的话则会造成高耦合问题,为了降低耦合度我们也利用properties配置文件进行数据源(连接池)的配置

  • 步骤如下

    • Step1: 在pom.xml文件中导入数据源(连接池)的坐标和数据库mysql驱动坐标,代码省略

      • 博主测试C3P0、Druid两个数据库连接池,所以它俩的坐标均会导入
    • Step2: 右键源代码配置文件目录(即资源文件resources)→NewFile,创建properties配置文件,博主文件名为jdbc.properties,该配置文件代码如下

      • properties配置文件中配置的各个属性前最好添加个id.(即id.属性,比如:属性url就设置为id.url,博主设置的为jdbc.url),防止系统中有与properties文件中的属性名一致的情况
      #driverClassName代表数据库驱动,后跟驱动全类名(在MySQL驱动jar包下的META-INF下的services文件夹下的java.sql.Driver文件内)
      jdbc.driverClassName=com.mysql.cj.jdbc.Driver
      # 数据库连接URL
      jdbc.url=jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
      # 数据库用户名
      jdbc.username=root
      # 数据库密码
      jdbc.password=123456
      # 初始化连接数量---即容器中初始的数据库连接数量
      jdbc.initialSize=5
      # 最大活跃连接数量---容器中初始为5个,但若5个用完了,此时可以在申请5个数据库连接数量
      #也就是说容器中最多存放10个数据库连接
      jdbc.maxActive=10
      # 获取连接时的最大等待时间,单位:毫秒。---与数据库进行连接时若超过3s仍未连接成功,则会报错
      jdbc.maxWait=3000
      #最小空闲连接数量---minIdle=5
      # 配置检测连接是否有效的SQL,可以是一个查询语句,如果不指定则默认为"SELECT 1"---validationQuery=SELECT 1
      # 是否开启自动提交事务---defaultAutoCommit=true
      
    • Step3: 读取properties配置文件并创建数据源对象,设置数据源的基本连接数据。然后使用数据源获取连接资源和归还资源

      package at.guigu.datasource;
      
      import com.alibaba.druid.pool.DruidDataSource;
      import com.mchange.v2.c3p0.ComboPooledDataSource;
      import org.junit.Test;
      
      import java.sql.Connection;
      import java.util.ResourceBundle;
      
      public class TestTwo {
          /**
           * 测试CP30数据源对象 (通过加载properties配置文件形式)
           */
          @Test
          public void test1() throws Exception {
              // 读取配置文件
              ResourceBundle rb = ResourceBundle.getBundle("jdbc");
      
              String driverClassName = rb.getString("jdbc.driverClassName");
              String url = rb.getString("jdbc.url");
              String username = rb.getString("jdbc.username");
              String password = rb.getString("jdbc.password");
              // 创建数据源对象
              ComboPooledDataSource dataSource = new ComboPooledDataSource();
              dataSource.setDriverClass(driverClassName);
              dataSource.setJdbcUrl(url);
              dataSource.setUser(username);
              dataSource.setPassword(password);
              // 使用数据源获取数据库连接资源
              Connection connection = dataSource.getConnection();
              System.out.println(connection);
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      
          /**
           * 测试Druid数据源对象 (通过加载properties配置文件形式)
           */
          @Test
          public void test2() throws Exception {
              // 读取配置文件
              ResourceBundle rb = ResourceBundle.getBundle("jdbc");
      
              String driverClassName = rb.getString("jdbc.driverClassName");
              String url = rb.getString("jdbc.url");
              String username = rb.getString("jdbc.username");
              String password = rb.getString("jdbc.password");
      
              // 创建数据源对象
              DruidDataSource dataSource = new DruidDataSource();
      
              // 设置数据源基本连接数据
              dataSource.setDriverClassName(driverClassName);
              dataSource.setUrl(url);
              dataSource.setUsername(username);
              dataSource.setPassword(password);
      
              // 使用数据源获取数据库连接资源
              Connection connection = dataSource.getConnection();
              System.out.println(connection);
      
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      }
      

      在这里插入图片描述

  • ResourceBundle类是专门用来通过键值对的形式存储和检索本地化的资源(如消息、标签等)。它的主要作用是根据不同的语言和区域设置加载相应的资源文件,从而实现应用程序的多语言支持。

    • 它所能加载的资源文件只有两种:即以.class.properties结尾的文件
    • 利用ResourceBundle类中的静态方法getBundle()加载配置文件时,它会自动在源代码配置文件目录(即资源文件resources)下查找所需的配置文件
      • 注意:使用该方法时,其参数只需给出配置文件的基名即可,它会自动匹配对应的后缀

Spring配置数据源(连接池)

  • 以上两种数据源配置方法耦合度还是很高,所以引入了Spring配置数据源(连接池)

  • 步骤如下

    • Step1: 在pom.xml文件中导入Spring、数据源(连接池)的坐标和数据库mysql驱动坐标。pom.xml文件完整代码如下

      • 博主测试C3P0、Druid两个数据库连接池,所以它俩的坐标均会导入
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.example</groupId>
        <artifactId>SpringDemoo</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemoo Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
          </dependency>
      
          <!--mysql坐标-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
          </dependency>
      
          <!--druid坐标-->
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.18</version>
          </dependency>
      
          <!--c3p0坐标-->
          <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
          </dependency>
      
          <!--spring坐标-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
          </dependency>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
          </dependency>
        </dependencies>
        <build>
          <finalName>SpringDemoo</finalName>
          <plugins>
            <!-- Tomcat插件 -->
            <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
            </plugin>
          </plugins>
        </build>
      </project>
      
    • Step2: 右键源代码配置文件目录(即资源文件resources)→NewXML Configuration FileSpring Config,文件名为applicationContext.xml,默认代码如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      </beans>
      
    • Step3: 配置数据源(连接池)的bean,Spring配置文件代码如下

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--Cp30对应的bean-->
          <bean id="dataSourceCp30" class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
              <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"/>
              <property name="user" value="root"/>
              <property name="password" value="123456"/>
          </bean>
      
          
          <!--Druid对应的bean-->
          <bean id="dataSourceDruid" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
          </bean>
      </beans>
      
    • Step4: 测试代码如下

      package at.guigu.datasource;
      
      import at.guigu.service.impl.BookServiceImpl;
      import com.alibaba.druid.pool.DruidDataSource;
      import com.mchange.v2.c3p0.ComboPooledDataSource;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import javax.sql.DataSource;
      import java.sql.Connection;
      
      public class TestThree {
          /**
           * 测试CP30数据源对象(通过Spring容器的方式)
           */
          @Test
          public void test1() throws Exception {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象(即数据源对象)
              DataSource dataSourceCp30 = (DataSource) app.getBean("dataSourceCp30");
              //等同于ComboPooledDataSource bean = app.getBean(ComboPooledDataSource.class);
      
              // 使用数据源获取数据库连接资源
              Connection connection = dataSourceCp30.getConnection();
              System.out.println(connection);
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      
          /**
           * 测试Druid数据源对象(通过Spring容器的方式)
           */
          @Test
          public void test2() throws Exception {
              //1 获取IOC容器
              ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
              //2 从IOC容器中获取bean对应的对象(即数据源对象)
              DataSource dataSourceDruid = (DataSource) app.getBean("dataSourceDruid");
              //等同于ComboPooledDataSource bean = app.getBean(DruidDataSource.class);
      
              // 使用数据源获取数据库连接资源
              Connection connection = dataSourceDruid.getConnection();
              System.out.println(connection);
              // 使用数据库资源,代码省略
      
              //归还数据库连接资源
              connection.close();
          }
      }
      

      在这里插入图片描述

Spring通过配置文件配置数据源(连接池)

  • 利用以上三种方式配置数据源(连接池)时耦合度仍然较高,所以就有了最优方案

  • 步骤如下所示

    • Step1: 在pom.xml文件中导入Spring、数据源(连接池)的坐标和数据库mysql驱动坐标。pom.xml文件完整代码如下

      • 博主测试C3P0、Druid两个数据库连接池,所以它俩的坐标均会导入
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.example</groupId>
        <artifactId>SpringDemoo</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemoo Maven Webapp</name>
        <url>http://maven.apache.org</url>
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
          </dependency>
      
          <!--mysql坐标-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
          </dependency>
      
          <!--druid坐标-->
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.18</version>
          </dependency>
      
          <!--c3p0坐标-->
          <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
          </dependency>
      
          <!--spring坐标-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
          </dependency>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
          </dependency>
        </dependencies>
        <build>
          <finalName>SpringDemoo</finalName>
          <plugins>
            <!-- Tomcat插件 -->
            <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
            </plugin>
          </plugins>
        </build>
      </project>
      
    • Step2: 右键源代码配置文件目录(即资源文件resources)→NewFile,创建properties配置文件,博主文件名为jdbc.properties,该配置文件代码如下

      • 注意: properties配置文件中配置的各个属性前必须添加个id.(即id.属性,比如:属性url就设置为id.url,博主设置的为jdbc.url)的原因
        • 配置数据库连接池的规定变量名与系统变量名冲突,若不加id.时:Spring配置文件利用属性占位符${} 调用来的就会默认为系统变量的值
    #driverClassName代表数据库驱动,后跟驱动全类名(在MySQL驱动jar包下的META-INF下的services文件夹下的java.sql.Driver文件内)
    jdbc.driverClassName=com.mysql.cj.jdbc.Driver
    # 数据库连接URL
    jdbc.url=jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    # 数据库用户名
    jdbc.username=root
    # 数据库密码
    jdbc.password=123456
    # 初始化连接数量---即容器中初始的数据库连接数量
    jdbc.initialSize=5
    # 最大活跃连接数量---容器中初始为5个,但若5个用完了,此时可以在申请5个数据库连接数量
    #也就是说容器中最多存放10个数据库连接
    jdbc.maxActive=10
    # 获取连接时的最大等待时间,单位:毫秒。---与数据库进行连接时若超过3s仍未连接成功,则会报错
    jdbc.maxWait=3000
    #最小空闲连接数量---minIdle=5
    # 配置检测连接是否有效的SQL,可以是一个查询语句,如果不指定则默认为"SELECT 1"---validationQuery=SELECT 1
    # 是否开启自动提交事务---defaultAutoCommit=true
    
    • Step3: 右键源代码配置文件目录(即资源文件resources)→NewXML Configuration FileSpring Config,文件名为applicationContext.xml,默认代码如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      </beans>
      
      • Step4: 在Spring配置文件中引入context命名空间和context约束路径然后使用context命名空间加载 properties 文件(加载 properties 文件成功后,Spring配置文件就可以使用属性占位符${} 语法来引用这些属性了)。Spring配置文件代码如下

        • 命名空间:xmlns:context="http://www.springframework.org/schema/context"
        • 约束路径:http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:context="http://www.springframework.org/schema/context"
               xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context.xsd">
        
            <!--使用`context`命名空间加载 `properties` 文件-->
            <context:property-placeholder location="classpath:jdbc.properties"/>
            <!--
        		若properties配置文件中没有加`id.`,则需变为如下形式使其系统属性失效
            <context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="NEVER"/>
           -->
        
        </beans>
        
      • Step5: 引入properties配置文件后配置数据源(连接池)的bean,Spring配置文件代码如下

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:context="http://www.springframework.org/schema/context"
               xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context.xsd">
        
            <!--使用`context`命名空间加载 `properties` 文件-->
            <context:property-placeholder location="classpath:jdbc.properties"/>
            
            <!--Cp30对应的bean-->
            <bean id="dataSourceCp30" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <!--使用属性占位符`${}`语法引用properties文件中的属性-->
                <property name="driverClass" value="${jdbc.driverClassName}"/>
                <property name="jdbcUrl" value="${jdbc.url}"/>
                <property name="user" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </bean>
        
            <!--Druid对应的bean-->
            <bean id="dataSourceDruid" class="com.alibaba.druid.pool.DruidDataSource">
                <!--使用属性占位符`${}`语法引用properties文件中的属性-->
                <property name="driverClassName" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </bean>
        
        </beans>
        
      • Step6: 测试代码如下

        package at.guigu.datasource;
        
        import at.guigu.service.impl.BookServiceImpl;
        import com.alibaba.druid.pool.DruidDataSource;
        import com.mchange.v2.c3p0.ComboPooledDataSource;
        import org.junit.Test;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        import javax.sql.DataSource;
        import java.sql.Connection;
        
        public class TestThree {
            /**
             * 测试CP30数据源对象(通过Spring容器的方式)
             */
            @Test
            public void test1() throws Exception {
                //1 获取IOC容器
                ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
                //2 从IOC容器中获取bean对应的对象(即数据源对象)
                DataSource dataSourceCp30 = (DataSource) app.getBean("dataSourceCp30");
                //等同于ComboPooledDataSource bean = app.getBean(ComboPooledDataSource.class);
        
                // 使用数据源获取数据库连接资源
                Connection connection = dataSourceCp30.getConnection();
                System.out.println(connection);
                // 使用数据库资源,代码省略
        
                //归还数据库连接资源
                connection.close();
            }
        
            /**
             * 测试Druid数据源对象(通过Spring容器的方式)
             */
            @Test
            public void test2() throws Exception {
                //1 获取IOC容器
                ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
                //2 从IOC容器中获取bean对应的对象(即数据源对象)
                DataSource dataSourceDruid = (DataSource) app.getBean("dataSourceDruid");
                //等同于ComboPooledDataSource bean = app.getBean(DruidDataSource.class);
        
                // 使用数据源获取数据库连接资源
                Connection connection = dataSourceDruid.getConnection();
                System.out.println(connection);
                // 使用数据库资源,代码省略
        
                //归还数据库连接资源
                connection.close();
            }
        }
        

        在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jupyter Notebook认识、安装和启动以及使用

Jupyter Notebook认识、安装和启动以及使用 Jupyter Notebook认识、安装和启动以及使用 Jupyter Notebook认识、安装和启动以及使用一、认识Jupyter Notebook1.1 Jupyter Notebook概述1.2 Jupyter Notebook 重要特性(1)交互式代码执行(2)支持多种编程语言(3)富文本编辑(4)代码高…

React 组件中 State 的定义、使用及正确更新方式

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;React篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容React 组件中 State 的定义、使用及正确更新方式 前言 在 React 应用开发中&#xff0c;state …

AIDD-人工智能药物设计-化学自然语言引导的扩散式类药分子编辑:DiffIUPAC的魔法之旅

J. Pharm. Anal. | 化学自然语言引导的扩散式类药分子编辑&#xff1a;DiffIUPAC的魔法之旅 AIDD药研. 制药工程和生命科学背景&#xff0c;重点关注于计算机辅助药物设计&#xff08;CADD&#xff09;/药物筛选、分子动力学模拟MD&#xff0c;兽药信息学VetInformatics&…

服务器数据恢复—硬盘掉线导致热备盘同步失败的RAID5阵列数据恢复案例

服务器存储数据恢复环境&#xff1a; 华为S5300存储中有12块FC硬盘&#xff0c;其中11块硬盘作为数据盘组建了一组RAID5阵列&#xff0c;剩下的1块硬盘作为热备盘使用。基于RAID的LUN分配给linux操作系统使用&#xff0c;存放的数据主要是Oracle数据库。 服务器存储故障&#…

2024年12月HarmonyOS应用开发者基础认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同 更新时间&#xff1a;2024年12月3日 这是基础认证题库&#xff0c;不是高级认证题库注意看清楚标…

docker修改并迁移存储至数据盘

文章目录 前言一、操作步骤&#xff08;需要root权限&#xff09;1. 查看磁盘占用&#xff0c;查看当前docker目录占用的空间2. 查看正在运行的容器&#xff0c;并停止容器及服务3. 拷贝数据、修改配置&#xff08;关键步骤&#xff09;4. 加载配置&#xff0c;启动服务及容器 …

n的阶乘(c++)

#include<stdio.h> int jiecheng(int n) { if(n1||n0) { return 1; } return(n*jiecheng(n-1)); } int main(void){ int n 0; printf("请输入您要计算的数字\n"); scanf("%d",&n); printf("%d\n",jiecheng(n)); return 0; }

MyBatis系列之自定义TypeHandler实现字段加密解密

文章目录 前言一、TypeHandler接口二、实现总结 前言 今天简单介绍利用MyBatis的TypeHandler接口实现字段的加解密。 字段的加密和解密&#xff0c;实现方式确实有好几种。比如&#xff0c;在业务层实现、在数据库层面实现等等&#xff0c;但是这些相对来说&#xff0c;耦合性…

C总结(C语言知识点,深化重难点)

C语言 1.使用C语言的7个步骤2.ASCII码3.提高程序可读性的机巧4.如何使用多种整形5.打印多种整形6.课移植类型&#xff1a;stdint.h和inttypes.h7.浮点数常量8.浮点值的上溢和下溢9.使用数据类型11.常量和C预处理器12.转换说明的意义12.1转换不匹配13.副作用和序列点14.数组简介…

JavaScript编写css自定义属性

一、自定义属性 是在 CSS 中定义的变量&#xff0c;以 --开头。它们可以存储颜色、尺寸、字体等任何 CSS 值&#xff0c;并且可以在整个文档中重复使用。 :root {--primary-color: #3498db;--font-size: 16px; }body {color: var(--primary-color);font-size: var(--font-siz…

【机器学习】任务十一:Keras 模块的使用

1.Keras简介 1.1 什么是Keras&#xff1f; Keras 是一个开源的深度学习框架&#xff0c;用 Python 编写&#xff0c;构建于 TensorFlow 之上。它以简单、快速和易于使用为主要设计目标&#xff0c;适合初学者和研究者。 Keras 提供了高层次的 API&#xff0c;帮助用户快速构…

02_Node.js模块化

02_Node.js模块化 知识点自测 以下代码运行的结果是多少&#xff1f; const arr [10, 20, 30] const result arr.map(val > val 1).reduce((sum, val) > sum val, 0) console.log(result) A&#xff1a;60 B&#xff1a;63 <details><summary>答案</…

故障识别 | GADF-CNN-SSA-XGBoost数据分类预测/故障识别(Matlab)

故障识别 | GADF-CNN-SSA-XGBoost数据分类预测/故障识别&#xff08;Matlab&#xff09; 目录 故障识别 | GADF-CNN-SSA-XGBoost数据分类预测/故障识别&#xff08;Matlab&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 格拉姆角场差&#xff08;GADF&#…

OPenCV 图片局部放大

m_image cv::imread("C:/Code/JPG/1.jpg");if (m_image.empty()) return;cv::imshow("原始图像", m_image); // TODO: 在此添加控件通知处理程序代码int width m_image.cols;int height m_image.rows;// 确定要放大的区域&#xff08;这里是图像中心部分…

【C++】变长参数

文章目录 1. 定义&#xff1a;2. C代码示例:2.1 实现方式一&#xff1a;2.2 实现方式二&#xff1a;2.3 实现方式三&#xff1a; 3. 总结3.1 使用...语法&#xff1a;3.2 使用 std::initializer_list3.3 使用变长模板参数&#xff08;Variadic Templates&#xff09; 1. 定义&a…

内网穿透 natapp安装与使用

前言 NATAPP是一款基于ngrok的内网穿透工具。以下是对NATAPP的详细概述&#xff1a; 基本概念 定义&#xff1a;内网穿透&#xff08;NAT穿透&#xff09;是一种技术&#xff0c;它允许具有特定源IP地址和端口号的数据包能够绕过NAT设备&#xff0c;从而被正确地路由到内网主机…

TPAMI 2023:When Object Detection Meets Knowledge Distillation: A Survey

摘要 目标检测&#xff08;Object Detection&#xff0c;OD&#xff09;是计算机视觉中的一项关键任务&#xff0c;多年来涌现出了众多算法和模型。尽管当前 OD 模型的性能有所提升&#xff0c;但它们也变得更加复杂&#xff0c;由于参数规模庞大&#xff0c;在工业应用中并不…

怎么样能使Ubuntu的文件浏览器显示当前目录的路径,而不是只显示一个文件名?

默认情况下Ubuntu的文件浏览器是只显示当前目录的目录名的&#xff0c;这很不便我们查看路径或直接利用路径进行定位&#xff0c;那么怎么样能使Ubuntu的文件浏览器显示当前目录的路径呢&#xff1f; 两种方法&#xff1a; 第1种-临时方法 按下快捷键 Ctrl L&#xff0c;导航…

Uniapp Android SpringBoot3 对接支付宝支付(最新教程附源码)

Uniapp Android SpringBoot3 对接支付宝支付&#xff08;最新教程附源码&#xff09; 1、效果展示2、后端实现2.1 引入支付宝SDK依赖 pom.xml2.2 配置 application.yml2.3 支付宝相关代码2.3.1 AlipayConfig.java2.3.2 ZfbPayConfig.java2.3.3 支付接口2.3.4 支付回调处理接口&…

阿里云ECS服务器域名解析

阿里云ECS服务器域名解析&#xff0c;以前添加两条A记录类型&#xff0c;主机记录分别为www和&#xff0c;这2条记录都解析到服务器IP地址。 1.进入阿里云域名控制台&#xff0c;找到域名 ->“解析设置”->“添加记录” 2.添加一条记录类型为A,主机记录为www&#xff0c…