Spring 学习笔记全系列传送门:

目录

1、学习概述

  • Spring的优点:

    • 简化开发

      • IOC
      • AOP
        • 事务处理
    • 框架整合
      • MyBatis
      • MyBatis-plus
      • Struts
      • Struts2
      • Hibernate
      • ......
  • 主要的学习内容
    • IOC
    • 整合Mybatis(IOC的具体应用)
    • AOP
    • 声明式事务(AOP的具体应用)
  • 学习重心
    • Spring的思想
    • Spring的基础操作
    • 案例练习

2、Spring相关概念

2.1 Spring概述

官网:https://spring.io

2.1.1 Spring能做的工作

  • Web
  • 微服务
  • 分布式
  • ......

2.1.2 重点学习的内容

  • Spring Framework:是Spring中最早最核心的技术,也是所有其他技术的基础。
  • SpringBoot:简化开发,而SpringBoot是来帮助Spring在简化的基础上能更快速进行开发。
  • SpringCloud:用来做分布式之微服务架构的相关开发。
  • SpringData、SpringSecurity 等目前也是流行的技术

2.1.3 Spring发展史

随着时间推移,版本不断更新维护,目前最新的是Spring5

  • Spring1.0是纯配置文件开发
  • Spring2.0为了简化开发引入了注解开发,此时是配置文件加注解的开发方式
  • Spring3.0已经可以进行纯注解开发,使开发效率大幅提升
  • Spring4.0根据JDK的版本升级对个别API进行了调整
  • Spring5.0已经全面支持JDK8,现在Spring最新的是5系列

2.2 Spring系统架构

2.2.1 系统架构及其图示

  • 说明

    • 核心层

      • Core Container :核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块
    • AOP层
      • AOP :面向切面编程,它依赖核心层容器,目的是在不改变原有代码的前提下对其进行功能增强
      • Aspects :AOP是思想,Aspects是对AOP思想的具体实现
    • 数据层
      • Data Access :数据访问,Spring全家桶中有对数据访问的具体实现技术
      • Data Integration :数据集成,Spring支持整合其他的数据层解决方案,比如Mybatis
      • Transactions :事务,Spring中事务管理是Spring AOP的一个具体实现,将在后续内容中详细说明
    • Web层
      • 这一层的内容将在SpringMVC框架部分进行详细说明
    • Test层
      • Spring主要整合了Junit来完成单元测试和集成测试
  • 图示 ( Spring Framework 4.x )

2.2.2 课程学习路线

  1. 核心容器

    • 核心概念( IoC / DI )
    • 容器基本操作
  2. AOP

    • 核心概念
    • AOP基础操作
    • AOP使用开发
  3. 事务

    • 事务实用开发
  4. 整合

    • 整合数据层技术MyBatis
  5. 家族

    • SpringMVC
    • SpringBoot
    • SpringCloud

2.3 Spring核心概念

2.3.1 目前项目中的问题

  • 存在问题:按照原先的JavaWeb开发,耦合度偏高

    如:Dao层更改了内容,将使用新的函数进行数据处理,此时Service层也要修改,并且需要重新编译

  • 解决方案

    • 使用对象时,避免主动new创建对象,转为由外部提供对象

2.3.2 IOC、IOC容器、Bean、DI —— 充分解耦

  • IOC(Inversion of Control)控制反转:使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想(对象的创建控制权的转移)称为控制反转。

  • IoC容器:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"

  • Bean:IOC容器负责对象的创建、初始化等一系列工作(其中包含了数据层和业务层的类对象),被创建或被管理的对象在IOC容器中都被成为称为Bean对象

  • DI(Dependency Injection)依赖注入:IoC容器为了解决Bean对象之间的依赖关系而自动建立bean对象绑定的过程

    如:Service需要依赖Dao,IoC容器会将两个bean对象进行绑定

3、入门案例

3.1 IOC入门案例

3.1.1 入门案例思路分析

3.1.2 入门案例代码实现

  1. 创建Maven项目

  2. 添加Spring依赖jar包

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.10.RELEASE</version>
    </dependency>
  3. 添加需要的类

    • Dao

      • 接口

        package priv.dandelion.dao;
        
        public interface BookDao {
        public void save();
        }
      • 实现类

        package priv.dandelion.dao.Impl;
        
        import priv.dandelion.dao.BookDao;
        
        public class BookDaoImpl implements BookDao {
        public void save() {
        System.out.println("book dao save ...");
        }
        }
    • Service

      • 接口

        package priv.dandelion.service;
        
        public interface BookService {
        public void save();
        }
      • 实现类

        package priv.dandelion.service.Impl;
        
        import priv.dandelion.dao.BookDao;
        import priv.dandelion.dao.Impl.BookDaoImpl;
        import priv.dandelion.service.BookService; public class BookServiceImpl implements BookService {
        private BookDao bookDao = new BookDaoImpl(); public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        }
        }
    • Main

      package priv.dandelion;
      
      import priv.dandelion.service.BookService;
      import priv.dandelion.service.Impl.BookServiceImpl; public class App {
      public static void main(String[] args) {
      BookService bookService = new BookServiceImpl();
      bookService.save();
      /**
      * 控制台输出:
      * book service save ...
      * book dao save ...
      */
      }
      }
  4. resources目录下添加Spring配置文件:applicationContext.xml,在配置文件中完成bean的配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置Bean-->
    <!--
    id : 给Bean命名
    class : 给Bean定义类型
    -->
    <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl"/>
    <bean id="bookService" class="priv.dandelion.service.Impl.BookServiceImpl"/> </beans>
  5. 获取IOC容器,从容器中获取对象进行方法调用

    package priv.dandelion;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import priv.dandelion.service.BookService; public class App2 {
    public static void main(String[] args) {
    // 获取IOC容器
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 获取Bean
    BookService bookService = (BookService) context.getBean("bookService");
    bookService.save();
    /**
    * 控制台输出:
    * book service save ...
    * book dao save ...
    */
    }
    }

3.2 DI ( 依赖注入 )入门案例

IoC入门案例中,Service层仍然使用了new的方式创建对象,耦合度依然高

3.2.1 入门案例思路分析

3.2.2 入门案例代码实现

  • 修改被依赖类的成员属性中创建对象部分,并为其添加set方法

    package priv.dandelion.service.Impl;
    
    import priv.dandelion.dao.BookDao;
    import priv.dandelion.service.BookService; public class BookServiceImpl implements BookService {
    // 删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao; public void save() {
    System.out.println("book service save ...");
    bookDao.save();
    }
    // 提供所要创建成员对象的对应的set方法
    public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
    }
    }
  • 修改配置文件,配置其和被依赖类的关系

    <?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 : 给Bean命名
    class : 给Bean定义类型
    -->
    <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl"/>
    <bean id="bookService" class="priv.dandelion.service.Impl.BookServiceImpl">
    <!-- 配置Service 与Dao的关系-->
    <!--
    property标签 : 表示配置当前Bean的属性
    name属性 : 表示配置参照哪一个具体的属性名称,注意需要实现其set方法
    ref属性 : 表示参照(引用)哪一个Bean
    -->
    <property name="bookDao" ref="bookDao"/>
    </bean> </beans>

4、IOC相关内容

4.1 Bean基础配置

4.1.1 bean基础配置( id 与 class )

类别 描述
名称 bean
类型 标签
所属 beans标签
功能 定义 Spring 核心容器管理的对象
格式 <beans> <bean/> <bean></bean> <beans>
属性列表 id:bean 的 id ,使用容器可以通过 id 值获取对应的 bean ,在一个容器中id唯一
class:bean 的类型,即配置的 bean 的全路径名 (不能是接口,接口不能实例化)
示例 <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl"/>
<bean id="bookService" class="priv.dandelion.service.Impl.BookServiceImpl"></bean>

4.1.2 bean 的别名 name 属性

  1. 配置别名

    • 使用 bean 标签的 name 属性为 bean 设置别名

    • 一个 bean 可以有多个别名,使用逗号或空格分隔

    • bean 的 ref 属性可以参照(引用)对应 bean 的 name 属性值,不过建议还是引用 id,保持一致

      <!--
      id : 给Bean命名
      class : 给Bean定义类型
      -->
      <bean id="bookDao" name="dao" class="priv.dandelion.dao.Impl.BookDaoImpl"/>
      <bean id="bookService" name="service,service2 bookEbi" class="priv.dandelion.service.Impl.BookServiceImpl">
      <!-- 配置Service 与Dao的关系-->
      <!--
      property标签 : 表示配置当前Bean的属性
      name属性 : 表示配置参照哪一个具体的属性名称,注意需要实现其set方法
      ref属性 : 表示参照(引用)哪一个Bean
      -->
      <property name="bookDao" ref="dao"/>
      </bean>
  2. 根据名称从容器中获取bean对象

    与使用 id 从容器中获取 bean 对象方法相同

4.1.3 bean 的作用范围 scope 配置

  • 多次创建 Bean 对象默认为单例,使用 scope 属性可以配置其不为单例

    • 核心配置文件

      <!-- bookDao 配置了属性 scope="prototype" -->
      <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl" scope="prototype"/> <bean id="bookService" name="service,service2 bookEbi" class="priv.dandelion.service.Impl.BookServiceImpl">
      <property name="bookDao" ref="bookDao"/>
      </bean>
    • 执行

      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      // 单例
      BookService bookService1 = (BookService) context.getBean("service");
      BookService bookService2 = (BookService) context.getBean("service");
      System.out.println(bookService1); // priv.dandelion.service.Impl.BookServiceImpl@25bbe1b6
      System.out.println(bookService2); // priv.dandelion.service.Impl.BookServiceImpl@25bbe1b6
      // 非单例
      BookDao bookDao1 = (BookDao) context.getBean("bookDao");
      BookDao bookDao2 = (BookDao) context.getBean("bookDao");
      System.out.println(bookDao1); // priv.dandelion.dao.Impl.BookDaoImpl@5702b3b1
      System.out.println(bookDao2); // priv.dandelion.dao.Impl.BookDaoImpl@69ea3742
  • 整理

    类别 描述
    名称 scope
    类型 属性
    所属 bean 标签
    功能 定义 bean 的作用范围,默认为单例(默认单例,节约资源),可进行配置
    * singletion:单例
    * prototype:非单例
    示例 <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl" scope="prototype"/>
  • 拓展

    • 适合交给容器进行管理的 bean

      • Dao 层对象
      • Service 层对象
      • Controller 层对象
      • Utils 对象
    • 不适合交给容器管理的 bean

      • 封装实体的域对象,各自带有不同的数据

4.2 bean实例化

bean 的本质就是对象,创建 bean 使用无参构造方法完成(底层采用暴力反射)

bean的三种实例化方法:

  • 构造方法
  • 静态工厂
  • 实例工厂

4.2.1 环境准备

4.2.2 构造方法实例化

  1. 准备需要被创建的类

    • Dao

      public class BookDaoImpl implements BookDao {
      
          // 验证:bean的实例化本质上是调用了无参构造方法,手动实现并在控制台输出内容
      // 验证:底层使用暴力反射机制,当构造方法使用private时,也不会影响bean的实例化
      private BookDaoImpl() {
      System.out.println("book dao constructor is running ....");
      } public void save() {
      System.out.println("book dao save ...");
      }
  2. 将类配置到Spring容器

    <bean id="bookDao" class="priv.dandelion.dao.Impl.BookDaoImpl"/>
  3. 编写运行程序

    public class AppForInstanceBook {
    public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); /**
    * 控制台输出:
    * book dao constructor is running ....
    * book dao save ...
    *
    * Process finished with exit code 0
    */ }
    }

4.2.3 静态工厂实例化

4.2.3.1 工厂方式创建 bean

使用工厂方式创建对象,在一定程度上进行解耦,但不如将工厂交给Spring来管理(见4.2.3.2)

  • Dao

    public class OrderDaoImpl implements OrderDao {
    
        public void save() {
    System.out.println("order dao save ...");
    }
    }
  • Factory

    //静态工厂创建对象
    public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
    System.out.println("factory setup....");
    return new OrderDaoImpl();
    }
    }
  • Main

    public class AppForInstanceOrder {
    public static void main(String[] args) {
    // 通过静态工厂创建对象
    OrderDao orderDao = OrderDaoFactory.getOrderDao();
    orderDao.save();
    /**
    * 控制台输出:
    * factory setup....
    * order dao save ...
    */
    }
    }
4.2.3.2 静态工厂实例化

将工厂交给Spring来管理,实例化 bean

  • 核心配置文件

    <!-- property标签 : 表示配置当前Bean的属性 -->
    <!-- class属性 : 所使用的工厂的全类名 -->
    <!-- factory-method属性 : 工厂中创建bean的方法名 -->
    <bean id="orderDao" class="priv.dandelion.factory.OrderDaoFactory" factory-method="getOrderDao"/>
  • Main

    public class AppForInstanceOrder {
    public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); OrderDao orderDao = (OrderDao) ctx.getBean("orderDao"); orderDao.save();
    /**
    * 控制台输出:
    * factory setup....
    * order dao save ...
    */
    }
    }

4.2.4 实例工厂(非静态)与 FactoryBean

4.2.4.1 环境准备
  • Dao

    public class UserDaoImpl implements UserDao {
    
        public void save() {
    System.out.println("user dao save ...");
    }
    }
  • Factory

    //实例工厂创建对象
    public class UserDaoFactory {
    public UserDao getUserDao(){
    return new UserDaoImpl();
    }
    }
4.2.4.2 实例工厂实例化
  • 核心配置文件

    <!-- 工厂中获取Dao的方法是非静态的,必须拿到工厂对象 -->
    <bean id="userFactory" class="priv.dandelion.factory.UserDaoFactory"/> <!-- 指定工厂,并使用工厂对应方法获取所需的bean对象 -->
    <!-- factory-bean:指定工厂bean -->
    <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>
  • Main

    public class AppForInstanceUser {
    public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) ctx.getBean("userDao"); userDao.save();
    /**
    * 控制台输出:
    * user dao save ...
    */
    }
    }
4.2.4.3 FactoryBean 的使用(改良:实例工厂实例化)

4.2.4.2 实例工厂实例化中存在问题,需要进行改进:

  1. 工厂的bean对象只是为了配合使用,毫无意义
  2. 对于每个需要的bean,其中factory-method属性值不固定,每次都需要配置

使用FactoryBean对其进行改进

  • FactoryBean 工厂类

    // FactoryBean创建对象,需要实现FactoryBean<T>接口并指定泛型
    public class UserDaoFactoryBean implements FactoryBean<UserDao> { // 代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
    return new UserDaoImpl();
    } // 指定Object的类型,返回对应的类的字节码文件
    public Class<?> getObjectType() {
    return UserDao.class;
    } // 创建出的 bean 是否为单例,返回 true 为单例,不覆写该方法时默认为为单例
    public boolean isSingleton() {
    return true;
    }
    }
  • 核心配置文件

    <!-- <bean id="userFactory" class="priv.dandelion.factory.UserDaoFactory"/> -->
    <!-- <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/> -->
    <bean id="userDao" class="priv.dandelion.factory.UserDaoFactoryBean"/>
  • Main

    与 4.2.4.2 一致,无需修改

4.3 bean的生命周期

bean 的生命周期有以下几个阶段:

  • 初始化容器

    1. 创建对象(分配内存)
    2. 执行构造方法
    3. 执行属性注入(set 操作)
    4. 执行 bean 的初始化方法
  • 使用 bean
    1. 执行业务操作
  • 关闭 / 销毁容器
    1. 执行 bean 销毁方法

4.3.1 环境准备

  • Dao

    public class BookDaoImpl implements BookDao {
    public void save() {
    System.out.println("book dao save ...");
    }
    }
  • 核心配置文件

    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
  • Main

    public class AppForLifeCycle {
    public static void main( String[] args ) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    /**
    * book dao save ...
    */
    }
    }

4.3.2 生命周期设置

  1. 类中添加初始化和销毁方法

    public class BookDaoImpl implements BookDao {
    public void save() {
    System.out.println("book dao save ...");
    }
    // 表示bean初始化对应的操作
    public void init(){
    System.out.println("init...");
    }
    // 表示bean销毁前对应的操作
    public void destroy(){
    System.out.println("destroy...");
    }
    }
  2. 在核心配置文件中进行配置

    <!--init-method:设置bean初始化生命周期回调函数-->
    <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/><bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
  3. 运行程序,控制台输出仅包含init

    如运行情况中所示,控制台没有输出destroy...,说明销毁方法未被执行,该问题将在 4.3.3 和 4.3.4 得到解决

    /**
    * init...
    * book dao save ...
    */

4.3.3 close关闭容器

  • 销毁方法未执行原因与解决方案分析

    • 原因:程序运行结束时,JVM虚拟机直接被关闭,销毁方法来不及执行
    • 解决方案:在关闭JVM虚拟机之前手动关闭容器,可以执行销毁方法
  • 实现

    存在问题:ApplicationContext中没有实现close()

    解决方案:其实现类ClassPathXmlApplicationContext对其进行了实现

    public class AppForLifeCycle {
    public static void main( String[] args ) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    //关闭容器
    ctx.close();
    /**
    * init...
    * book dao save ...
    * destroy...
    */
    }
    }

4.3.4 注册钩子关闭容器

  • 使用该方式的原因

    • close关闭容器相对而言比较暴力,如果在 close 之后还有未执行的语句,可能会发生问题
    • 注册钩子关闭容器语句可以写在任何位置,且仅在JVM虚拟机关闭前执行销毁
  • 注册钩子关闭容器的使用方法

    • Main中

      //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
      ctx.registerShutdownHook();

4.3.5 生命周期管理的接口方式

Spring为生命周期控制提供了接口,在上述代码的基础上添加以下代码进行演示

  • 核心配置文件(不需要写 init-method 和 destroy-method 属性)

    <bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl">
    <property name="bookDao" ref="bookDao"/>
    </bean>
  • Service

    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao; public void setBookDao(BookDao bookDao) {
    System.out.println("set .....");
    this.bookDao = bookDao;
    } public void save() {
    System.out.println("book service save ...");
    bookDao.save();
    } public void destroy() throws Exception {
    System.out.println("service destroy");
    } // 如方法名所述,该方法运行在set方法之后
    public void afterPropertiesSet() throws Exception {
    System.out.println("service init");
    }
    }
  • Main

    public class AppForLifeCycle {
    public static void main( String[] args ) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
    ctx.registerShutdownHook();
    /**
    * init...
    * set .....
    * service init
    * book dao save ...
    * service destroy
    * destroy...
    */
    }
    }

5、DI(依赖注入)相关内容

  • 向一个类中传递数据的方式

    • 普通方法(setter)
    • 构造方法(构造器)
  • 容器中的 bean 可能是什么类型的数据
    • 引用类型
    • 简单类型(基本数据类型和 String)

5.1 setter注入 (推荐,使用简单)

5.1.1 注入引用数据类型

  1. 类中给出成员变量并实现其setter

    public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;
    //setter注入需要提供要注入对象的set方法
    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    //setter注入需要提供要注入对象的set方法
    public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
    } public void save() {
    System.out.println("book service save ...");
    bookDao.save();
    userDao.save();
    }
    }
  2. 核心配置文件

    <!-- 被注入的需要配置,定义成bean -->
    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="priv.dandelion.dao.impl.UserDaoImpl"/> <!-- 注入引用类型 -->
    <bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl">
    <!--property标签:设置注入属性-->
    <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
    <!--ref属性:设置注入引用类型bean的id或name-->
    <property name="bookDao" ref="bookDao"/>
    <property name="userDao" ref="userDao"/>
    </bean>

5.1.2 注入简单数据类型

  1. 在类中定义成员变量并实现其 setter

    public class BookDaoImpl implements BookDao {
    
        private String databaseName;
    private int connectionNum;
    //setter注入需要提供要注入对象的set方法
    public void setConnectionNum(int connectionNum) {
    this.connectionNum = connectionNum;
    }
    //setter注入需要提供要注入对象的set方法
    public void setDatabaseName(String databaseName) {
    this.databaseName = databaseName;
    } public void save() {
    System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
    }
  2. 核心配置文件

    <!-- 注入简单类型 -->
    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
    <!--property标签:设置注入属性-->
    <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
    <!--value属性:设置注入简单类型数据值,Spring内部会自动进行类型转换-->
    <property name="connectionNum" value="100"/>
    <property name="databaseName" value="mysql"/>
    </bean>

5.2 构造器注入

5.2.1 构造器注入引用数据类型

  1. 类中给出成员变量并使用有参构造对需要注入的成员进行初始化操作

    public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao; public BookServiceImpl(BookDao bookDao, UserDao userDao) {
    this.bookDao = bookDao;
    this.userDao = userDao;
    } public void save() {
    System.out.println("book service save ...");
    bookDao.save();
    userDao.save();
    }
    }
  2. 核心配置文件

    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="priv.dandelion.dao.impl.UserDaoImpl"/> <bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl">
    <!-- 注意此处的 ref 属性值为:构造方法的形参名 -->
    <constructor-arg name="userDao" ref="userDao"/>
    <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

5.2.2 构造器注入简单数据类型

  1. 类中给出成员变量并使用有参构造对需要注入的成员进行初始化操作

    public class BookDaoImpl implements BookDao {
    private String databaseName;
    private int connectionNum; public BookDaoImpl(String databaseName, int connectionNum) {
    this.databaseName = databaseName;
    this.connectionNum = connectionNum;
    } public void save() {
    System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
    }
  2. 核心配置文件

    <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
    <!-- 根据构造方法参数名称注入 -->
    <constructor-arg name="connectionNum" value="10"/>
    <constructor-arg name="databaseName" value="mysql"/>
    </bean>

5.2.3 【补充】不同场景构造器注入简单数据类型的其他写法 —— 用于解耦

<!-- 1. 标准书写 -->
<bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean> <!-- 2. 解决形参名称的问题,与形参名不耦合 -->
<bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean> <!-- 3. 解决参数类型重复问题,使用位置解决参数匹配 -->
<bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
<constructor-arg index="0" value="mysql"/>
<constructor-arg index="1" value="100"/>
</bean>

5.3 自动配置

  • IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配

  • 自动装配的方式:

    • 按类型(常用)

    • 按名称(耦合度高)

    • 按构造器(不推荐)

    • 不启用自动装配

  • 依赖自动装配特征

    • 自动装配用于引用类型依赖注入,不能对简单类型进行操作
    • 使用按类型装配时(byType)必须保障容器中相同类型(class)的 bean 唯一,推荐使用
    • 使用按名称装配时(byName)必须保障容器中具有指定名称(id)的 bean,因变量名与配置耦合,不推荐使用
    • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
  • 按类型(推荐)

    • 注意事项

      1. 被注入的 bean 所在的类必须实现 setter
      2. 被注入的 bean(按照全类名,即 class 属性)有且仅有一个
      3. 按类型注入时,被注入的 bean 可以没有 id
    • 配置

      <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl" autowire="byType"/>
  • 按名称

    • 注意事项

      1. 被注入的 bean 所在的类必须实现 setter
      2. 被注入的 bean 的 id 属性必须和类中的成员名称,准确说是 setter 名称保持一致,否则会给一个空对象,导致空指针异常
      3. 变量名与配置耦合
    • 配置代码

      <bean id="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl"/>
      <bean id="bookService" class="priv.dandelion.service.impl.BookServiceImpl" autowire="byName"/>

5.4 集合注入

  • List 和 Array 可以相互通用

  • 如果集合的元素是引用类型则不使用 <value></value>

    <ref bean="bean的id"/>
  • Dao

    public class BookDaoImpl implements BookDao {
    
        private int[] array;
    
        private List<String> list;
    
        private Set<String> set;
    
        private Map<String,String> map;
    
        private Properties properties;
    
        public void setArray(int[] array) {
    this.array = array;
    } public void setList(List<String> list) {
    this.list = list;
    } public void setSet(Set<String> set) {
    this.set = set;
    } public void setMap(Map<String, String> map) {
    this.map = map;
    } public void setProperties(Properties properties) {
    this.properties = properties;
    } public void save() {
    System.out.println("book priv.dandelion.dao save ..."); System.out.println("遍历数组:" + Arrays.toString(array)); System.out.println("遍历List" + list); System.out.println("遍历Set" + set); System.out.println("遍历Map" + map); System.out.println("遍历Properties" + properties);
    }
    }
  • 核心配置文件

    <?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="bookDao" class="priv.dandelion.dao.impl.BookDaoImpl">
    <!--数组注入-->
    <property name="array">
    <array>
    <value>100</value>
    <value>200</value>
    <value>300</value>
    </array>
    </property>
    <!--list集合注入-->
    <property name="list">
    <list>
    <value>dande</value>
    <value>dandel</value>
    <value>dandelio</value>
    <value>dandelion</value>
    </list>
    </property>
    <!--set集合注入-->
    <property name="set">
    <set>
    <value>dande</value>
    <value>dandel</value>
    <value>dandelio</value>
    <value>dandelio</value>
    </set>
    </property>
    <!--map集合注入-->
    <property name="map">
    <map>
    <entry key="country" value="china"/>
    <entry key="province" value="henan"/>
    <entry key="city" value="kaifeng"/>
    </map>
    </property>
    <!--Properties注入-->
    <property name="properties">
    <props>
    <prop key="country">china</prop>
    <prop key="province">henan</prop>
    <prop key="city">kaifeng</prop>
    </props>
    </property>
    </bean>
    </beans>
  • Main

    public class AppForDICollection {
    public static void main( String[] args ) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save();
    }
    /**
    * book priv.dandelion.dao save ...
    * 遍历数组:[100, 200, 300]
    * 遍历List[dande, dandel, dandelio, dandelion]
    * 遍历Set[dande, dandel, dandelio]
    * 遍历Map{country=china, province=henan, city=kaifeng}
    * 遍历Properties{province=henan, city=kaifeng, country=china}
    */
    }

Spring学习笔记 - 第一章 - IoC(控制反转)、IoC容器、Bean的实例化与生命周期、DI(依赖注入)的更多相关文章

  1. Spring框架学习笔记(1)——控制反转IOC与依赖注入DI

    Spring框架的主要作用,就是提供了一个容器,使用该容器就可以创建并管理对象.比如说Dao类等,又或者是具有多依赖关系的类(Student类中包含有Teacher类的成员变量) Spring有两个核 ...

  2. Spring学习笔记--环境搭建和初步理解IOC

    Spring框架是一个轻量级的框架,不依赖容器就能够运行,像重量级的框架EJB框架就必须运行在JBoss等支持EJB的容器中,核心思想是IOC,AOP,Spring能够协同Struts,hiberna ...

  3. 《跟我学Shiro》学习笔记 第一章:Shiro简介

    前言 现在在学习Shiro,参照着张开涛老师的博客进行学习,然后自己写博客记录一下学习中的知识点,一来可以加深理解,二来以后遗忘了可以查阅.没有学习过Shiro的小伙伴,也可以和我一起学习,大家共同进 ...

  4. JavaScript高级程序设计学习笔记第一章

    作为学习javascript的小白,为了督促自己读书,写下自己在读书时的提炼的关键点. 第一章: 1.JavaScript简史:Netscape Navigator中的JavaScript与Inter ...

  5. Java学习笔记 第一章 入门<转>

    第一章 JAVA入门 一.基础常识 1.软件开发 什么是软件? 软件:一系列按照特定顺序组织的计算机数据和指令的集合 系统软件:DOS,Windows,Linux 应用软件:扫雷.QQ.迅雷 什么是开 ...

  6. c#高级编程第七版 学习笔记 第一章 .NET体系结构

    第一章      .NET体系结构 本章内容: 编译和运行面向.NET的代码 Microsoft中间语言(Microsoft Intermediate Language,MSIL或简称IL)的优点 值 ...

  7. C语言学习笔记第一章——开篇

    本文章B站有对应视频 (本文图片.部分文字引用c primer plus) 什么是C语言 顾名思义,c语言是一门语言,但是和我们所讲的话不同,它是一门编程语言,是为了让机器可以听懂人的意思所以编写的一 ...

  8. [HeadFirst-JSPServlet学习笔记][第一章:前言与概述]

    第一章 前言与概述 web服务器做什么? 答:接收客户请求,然后向客户返回结果 web客户做什么? 答:此处客户指浏览器,web客户允许用户请求服务器上的某个资源,并向用户展现请求的结果. html ...

  9. GIT学习笔记——第一章

    git之vim编辑器退出命令 # 学习笔记 张文军微博主页  张文军码云主页   张文军新浪云主页  张文军博客主页 ## 刚学习git,好多东西没接触过,进入vim后不知道如何出来了,网上找了很多都 ...

  10. Java 学习笔记 第一章:Java语言开发环境搭建

    第一章:Java语言开发环境搭建 第二章:常量.变量和数据类型 第三章:数据类型转换.运算符和方法入门 1.Java虚拟机——JVM JVM(Java Virtual Machine ):Java虚拟 ...

随机推荐

  1. KingbaseES V8R6 维护管理案例之---Kstudio在CentOS 7启动故障

    ​ 案例说明: 在CentOS 7上安装KingbaseES V8R6C006数据库后,启动Kstudio图形界面启动失败,gtk动态库加载失败,安装gtk相关动态库后,问题解决. 适用版本: Kin ...

  2. C#,使用FindWindow和FindWindowEx查找窗体和控件

    函数: // Find Window // 查找窗体 // @para1: 窗体的类名 例如对话框类是"#32770" // @para2: 窗体的标题 例如打开记事本 标题是&q ...

  3. [机器学习]-分类问题常用评价指标、混淆矩阵及ROC曲线绘制方法

    分类问题 分类问题是人工智能领域中最常见的一类问题之一,掌握合适的评价指标,对模型进行恰当的评价,是至关重要的. 同样地,分割问题是像素级别的分类,除了mAcc.mIoU之外,也可以采用分类问题的一些 ...

  4. 输入法词库解析(三)紫光拼音词库.uwl

    详细代码:https://github.com/cxcn/dtool 前言 .uwl 是紫光拼音输入法(现在叫华宇拼音输入法)使用的词库. 解析 紫光的词库有点复杂,拼音用的索引,但是拼音表没有写在词 ...

  5. Markdowm基础语法的使用(typora)

    Mackdown学习 一级标题:一个#加空格 回车 二级标题:两个#加空格 回车 以此类推... 一级标题(Ctrl+1) 二级标题(Ctrl+2) 三级标题(Ctrl+3) 四级标题(Ctrl+4) ...

  6. 使用docker-compose.yml安装rabbitmq集群

    1.拉取镜像 集群中每个节点都需要执行 docker pull rabbitmq:3.8.3-management 2.上传docker-compose文件,设置可执行权限 相关文地址:https:/ ...

  7. centos7.5升级系统内核版本

    1.yum update curl nss 2.yum install wget 3.rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.or ...

  8. C#高级特性(反射)

    今天来讲解反射的应用: 一.反射是什么? 简诉一下,反射就是.Net Framework 的一个帮助类库,可以获取并使用metadata(元数据清单):说的通俗易懂点,就是不用通过引用,仍然可以使用其 ...

  9. 记录一次Bitbucket鉴权的坑

    目录 发生了什么 什么原因 如何解决 总结 发生了什么 今天首次在Fedora上使用git,因为没有小王八(TortoiseGit)帮助,其过程异常焦灼-- 反正经过一系列折腾,我在本地新建了一个项目 ...

  10. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(25)-Fiddler如何优雅地在正式和测试环境之间来回切换-下篇

    1.简介 在开发或者测试的过程中,由于项目环境比较多,往往需要来来回回地反复切换,那么如何优雅地切换呢?宏哥今天介绍几种方法供小伙伴或者童鞋们进行参考. 2.实际工作场景 2.1问题场景 (1)已发布 ...