spring笔记

106 阅读19分钟

1.学习目标

  • 能够说出 Spring 的体系结构
  • 能够编写 IOC 入门案例
  • 能够编写 DI 入门案例
  • 能够配置 setter 方式注入属性值
  • 能够配置构造方式注入属性值
  • 能够理解什么是自动装配

2.Spring简介

2.1 Spring课程介绍

1、问题导入

  • 我们为什么要学习 Spring 框架?

2、为什么要学

  • Spring 技术是 JavaEE 开发必备技能,企业开发技术选型命中率>90%

  • 专业角度:

    • ==简化开发==:降低企业级开发的复杂性
    • ==框架整合==:高效整合其他技术,提高企业级应用开发与运行效率

图片转存失败,建议将图片保存下来直接上传

3、学什么

  • 简化开发:

    • IOC(反转控制)
    • AOP(面向切面编程)
      • 事务处理
  • 框架整合:

    • MyBatis
    • MyBatis-plus
    • Struts
    • Struts2
    • Hibernate
    • ……

4、怎么学

  • 学习 Spring 框架设计思想
  • 学习基础操作,思考操作与思想间的联系
  • 学习案例,熟练应用操作的同时,体会思想

2.2 初识Spring

1、Spring家族

  • 官网:spring.io
  • Spring 发展到今天已经形成了一种开发的生态圈,Spring 提供了若干个项目,每个项目用于完成特定的功能

图片转存失败,建议将图片保存下来直接上传

2、Spring发展史

图片转存失败,建议将图片保存下来直接上传

2.3 Spring体系结构

1、Spring Framework系统架构图

  • Spring FrameworkSpring 生态圈中最基础的项目,是其他项目的根基
  • 4.x 版本的架构图

2、Spring Framework课程学习路线

2.4 Spring核心概念

1、问题导入

  • 问题1:目前我们的代码存在什么问题以及怎么解决这些问题?

  • 问题2:请描述什么是IOC,什么是DI?

2、目前我们代码存在的问题

  • 代码书写现状:耦合度偏高
  • 解决方案:使用对象时,在程序中不要主动使用 new 产生对象,转换为由外部提供对象

3、核心概念

  • IOC(Inversion of Control):控制反转

    • 使用对象时,由主动 new 产生对象转换为由==外部==提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
    • 通俗的讲就是:将 new 对象的权利交给 Spring,我们从 Spring 中获取对象使用即可
  • Spring 技术对 IoC 思想进行了实现:

    • Spring 提供了一个容器,称为==IOC容器==,用来充当 IoC 思想中的“外部”
    • IOC 容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在 IoC 容器中统称为==Bean==
  • DI(Dependency Injection):依赖注入

    • 在容器中建立 beanbean 之间的依赖关系的整个过程,称为依赖注入

4、Spring核心思想小结

  • 目标:充分解耦
    • 使用 IoC 容器管理 bean(IOC)
    • IoC 容器内将有依赖关系的 bean 进行关系绑定(DI
  • 最终效果:
    • 使用对象时不仅可以直接从 IoC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系

3.IoC入门案例

3.1 思路分析

  1. 管理什么?(ServiceDao
  2. 如何将被管理的对象告知 IoC 容器?(配置)
  3. 被管理的对象交给 IoC 容器,如何获取到 IoC 容器?(接口)
  4. IoC 容器得到后,如何从容器中获取 bean?(接口方法)
  5. 使用 Spring 导入哪些坐标?(pom.xml

3.2 原始方式创建对象

1、说明

  • 创建对象是我们自己手动通过 new 关键字创建的

2、dao层

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

3、service层

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao=new BookDaoImpl();

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

4、main方法中

package com.itheima;

import com.itheima.service.BookService;
import com.itheima.service.impl.BookServiceImpl;

public class App {
    public static void main(String[] args) {
        BookService bookService = new BookServiceImpl();
        bookService.save();
    }
}

5、效果

3.3 IoC方式创建对象

1、导包

  • pom.xml 文件中导入 spring 框架的坐标
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>
  • 刷新一下,然后才能创建 spring 的配置文件

2、创建配置文件

  • resources 目录下创建配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1. 导入spring的坐标spring-context,对应版本是5.2.10.RELEASE -->

    <!-- 2. 配置bean: -->
    <!--
        bean标签:表示配置bean
        id属性:表示给bean起名字
        class属性:表示给bean定义类型
    -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl2"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl2" />

</beans>

问题:spring配置文件提示:application context not configured for this file

解决方案:www.cnblogs.com/clouds666/p…

3、dao层

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl2 implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

4、service层

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl2 implements BookService {
    private BookDao bookDao=new BookDaoImpl();

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

5、main方法中

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        // 3. 获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 4. 获取bean(根据bean配置id获取)
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

6、效果

图片转存失败,建议将图片保存下来直接上传

7、总结

  1. 导入 Spring 坐标
  2. 定义 Spring 管理的类(接口)
  3. 创建 Spring 配置文件,配置对应类作为 Spring 管理的 bean注意事项:bean定义时id属性在同一个上下文中不能重复
  4. 初始化 IoC 容器(Spring 核心容器/ Spring 容器),通过容器获取 bean

4.DI入门案例

4.1 思路分析

  1. 基于 IoC 管理 bean
  2. Service 中使用 new 形式创建的 Dao 对象是否保留?(否)
  3. Service 中需要的 Dao 对象如何进入到 Service 中?(提供方法)
  4. ServiceDao 间的关系如何描述?(配置)

4.2 Dao层

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl3 implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

4.3 service层

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;

public class BookServiceImpl3 implements BookService {
    // 5. 删除业务层中使用new的方式创建的dao对象
    // private BookDao bookDao=new BookDaoImpl();
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    // 6. 提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

4.4 配置文件

  • 默认通过 setXX 方法进行引用对象的赋值
<?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. 导入spring的坐标spring-context,对应版本是5.2.10.RELEASE -->

    <!-- 2. 配置bean: -->
    <!--
        bean标签:表示配置bean
        id属性:表示给bean起名字
        class属性:表示给bean定义类型
    -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl3"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl3">
        <!-- 7. 配置server与dao的关系 -->
        <!--
            property标签:表示配置当前bean的属性
            name属性:表示配置哪一个具体的属性
            ref属性:表示参照哪一个bean,即对应的 bean 标签的 id
        -->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

4.5 图解

图片转存失败,建议将图片保存下来直接上传

4.6 效果

4.7 总结

  1. 删除使用 new 的形式创建对象的代码
  2. 提供依赖对象对应的 setter 方法
  3. 配置 servicedao 之间的关系

5.Bean的基础配置

5.1 问题导入

  • 问题1:在 <bean> 标签上如何配置别名?

  • 问题2:Bean 的默认作用范围是什么?如何修改?

5.2 Bean基础配置

5.3 Bean别名配置

1、语法

2、Dao层

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

3、service层

  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

4、配置文件

  • 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、name 属性:为bean指定别名,别名可以有多个,可以使用逗号、分号、空格进行分隔 -->
    <!-- 2、ref 属性的值可以是一个 bean 的 id 值,也可以是一个 bean 的 name 值  -->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" />
</beans>

5、测试

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForName {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 1、传入 name 值获取对象
        BookService bookService = (BookService) ctx.getBean("service");
        bookService.save();
        System.out.println("----------------");

        bookService = (BookService) ctx.getBean("service4");
        bookService.save();
        System.out.println("----------------");

        bookService = (BookService) ctx.getBean("bookEbi");
        bookService.save();
    }
}

6、效果

图片转存失败,建议将图片保存下来直接上传

7、图解

  • ==代码演示==:
  • ==打印结果==:

5.4 Bean作用范围配置

1、语法

扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。

2、Dao层

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

3、service层

  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

4、配置文件

  • 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、name 属性:为bean指定别名,别名可以有多个,可以使用逗号、分号、空格进行分隔 -->
    <!-- 2、ref 属性的值可以是一个 bean 的 id 值,也可以是一个 bean 的 name 值  -->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

    <!-- 3、scope:为bean设置作用范围,可选值为单例singloton,非单例prototype -->
    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
</beans>

5、测试

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForScope {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
        BookDao bookDao2 = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao1);
        System.out.println(bookDao2);
    }
}

6、效果

  • 默认情况下为单例:

图片转存失败,建议将图片保存下来直接上传

  • 修改后为多例:

图片转存失败,建议将图片保存下来直接上传

7、图解

  • ==代码演示==:
  • ==打印结果==:

最后给大家说明一下:在我们的实际开发当中,绝大部分的 Bean 是单例的,也就是说绝大部分 Bean 不需要配置 scope 属性

5.5 bean作用范围说明

  • 为什么 bean 默认为单例?
  • 适合交给容器进行管理的 bean
    • 表现层对象
    • 业务层对象
    • 数据层对象
    • 工具对象
  • 不适合交给容器进行管理的 bean
    • 封装实体的域对象

6.Bean的实例化

6.1 Bean是如何创建的

  • bean 本质上就是对象,创建 bean 使用构造方法完成

6.2 实例化Bean的三种方式

  • 构造方法方式【重点】
  • 静态工厂方式
  • 实例工厂方式

6.3 构造方法方式

1、Dao层实现类

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }

    public void save() {
        System.out.println("book dao save ...");
    }
}

2、配置文件

  • 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、方式一:构造方法实例化bean -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

</beans>

3、测试

package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceBook {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}
  • 运行结果:

注意:无参构造方法如果不存在,将抛出异常 BeanCreationException

6.4 静态工厂方式

1、Dao层实现类

  • OrderDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.OrderDao;

public class OrderDaoImpl implements OrderDao {

    public void save() {
        System.out.println("order dao save ...");
    }
}

2、工厂类

  • OrderDaoFatory 中的代码:
package com.itheima.factory;

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;

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

3、配置文件

  • applicationContext.xml 配置文件:
    <!-- 2、方式二:使用静态工厂实例化bean -->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

图片转存失败,建议将图片保存下来直接上传

4、测试

  • AppForInstanceOrder.java 中的代码:
package com.itheima.factory;

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;

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

图片转存失败,建议将图片保存下来直接上传

6.5 实例工厂方式

1、Dao层实现类

  • UserDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {

    public void save() {
        System.out.println("user dao save ...");
    }
}

2、工厂类

  • OrderDaoFatory 中的代码:
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;

// 实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

3、配置文件

  • applicationContext.xml 配置文件:
    <!-- 3、方式三:使用实例工厂实例化bean -->
    <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

图片转存失败,建议将图片保存下来直接上传

4、测试

  • AppForInstanceOrder.java 中的代码:
package com.itheima;

import com.itheima.dao.OrderDao;
import com.itheima.dao.UserDao;
import com.itheima.factory.OrderDaoFactory;
import com.itheima.factory.UserDaoFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceUser {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao1 = (UserDao) ctx.getBean("userDao");
        UserDao userDao2 = (UserDao) ctx.getBean("userDao");
        System.out.println(userDao1);
        System.out.println(userDao2);
        userDao1.save();
    }
}
  • 运行结果:

图片转存失败,建议将图片保存下来直接上传

6.6 实现FactoryBean<T>方式

  • 定义 UserDaoFactoryBean 实现 FactoryBean\<UserDao>
    • UserDaoFactoryBean 中实例化什么类型的对象泛型就是该类型
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;

// FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    // 代替原始实例工厂中创建对象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    public Class<?> getObjectType() {
        return UserDao.class;
    }

}
  • 修改 applicationContext.xml 配置文件
    <!-- 4、方式四:使用FactoryBean实例化bean -->
    <bean id="userDao1" class="com.itheima.factory.UserDaoFactoryBean"/>
  • 测试:
package com.itheima;

import com.itheima.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceUser1 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao1 = (UserDao) ctx.getBean("userDao1");
        UserDao userDao2 = (UserDao) ctx.getBean("userDao1");
        System.out.println(userDao1);
        System.out.println(userDao2);
        userDao1.save();
    }
}
  • 效果:

图片转存失败,建议将图片保存下来直接上传

7.Bean的生命周期

7.1 问题导入

  • 问题1:多例的 Bean 能够配置并执行销毁的方法?

  • 问题2:如何做才执行 Bean 销毁的方法?

7.2 生命周期相关概念介绍

  • 生命周期:从创建到消亡的完整过程
  • bean 生命周期:bean 从创建到销毁的整体过程
  • bean 生命周期控制:在 bean 创建后到销毁前做一些事情

7.3 Bean生命周期控制:方式一

  • ==第一步==:提供生命周期控制方法
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }

    // 1、表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }

    // 2、表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }
}
  • ==第二步==:修改 applicationContext.xml 配置文件
    <!-- 1、init-method:设置bean初始化生命周期回调函数 -->
    <!-- 2、destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象 -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
  • ==第三步==:测试
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

        // 2、关闭容器
        ctx.close();
    }
}
  • ==效果==:

图片转存失败,建议将图片保存下来直接上传

7.4 Bean生命周期控制:方式二

  • 实现 InitializingBean, DisposableBean 接口,重写 afterPropertiesSetdestroy 方法
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");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}
  • 修改 applicationContext.xml 配置文件:
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>
  • 效果:

图片转存失败,建议将图片保存下来直接上传

7.5 Bean生命周期过程

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

7.6 Bean销毁时机

  • 容器关闭前触发 bean 的销毁
  • 关闭容器方式:
    • 手工关闭容器:ConfigurableApplicationContext接口close()操作
    • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机:ConfigurableApplicationContext接口registerShutdownHook()操作
public class AppForLifeCycle {
    public static void main( String[] args ) {
        //此处需要使用实现类类型,接口类型没有close方法
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
        ctx.registerShutdownHook();
        //关闭容器
        //ctx.close();
    }
}

8.依赖注入(DI配置)

8.1 问题导入

  • 思考:向一个类中传递数据的方式有几种?
    • 普通方法(set 方法)
    • 构造方法
  • 思考:依赖注入描述了在容器中建立 beanbean 之间依赖关系的过程,如果 bean 运行需要的是数字或字符串呢?
    • 引用类型
    • 简单类型(基本数据类型与 String

8.2 依赖注入的两种方式

  • setter 注入

    • 简单类型
    • 引用类型(很常用)
  • 构造器注入

    • 简单类型
    • 引用类型

8.3 setter方式注入

1、图解

  • ==引用类型==:

图片转存失败,建议将图片保存下来直接上传

  • ==简单类型==:

2、示例

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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);
    }
}
  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

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();
    }
}
  • 配置文件:
<?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">

    <!-- 2、注入简单类型 -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--
            property标签:设置注入属性
            name属性:设置注入的属性名,实际是set方法对应的名称
            value属性:设置注入简单类型数据值
        -->
        <property name="connectionNum" value="100"/>
        <property name="databaseName" value="mysql"/>
    </bean>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!-- 1、注入引用类型 -->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--
            property标签:设置注入属性
            name属性:设置注入的属性名,实际是set方法对应的名称
            ref属性:设置注入引用类型bean的id或name
        -->
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>
  • 测试:
package com.itheima;

import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForDISet {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}
  • 效果:

图片转存失败,建议将图片保存下来直接上传

8.4 构造方式注入

1、图解

  • ==引用类型==:
  • ==简单类型==:

2、示例

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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);
    }
}
  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

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();
    }
}
  • 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 1、根据构造方法参数名称注入 -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--
            name 属性:形参的名称
            value 属性:形参的值
        -->
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

</beans>
  • 测试:
public class AppForDIConstructor {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}
  • 效果:

图片转存失败,建议将图片保存下来直接上传

3、参数适配:图解

4、参数适配:示例

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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);
    }
}
  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

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();
    }
}
  • 配置文件:
<?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">

    <!--  2、根据构造方法参数类型注入,解决形参名称的问题,与形参名不耦合 -->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--
            type 属性:形参的类型
            value 属性:形参的值
        -->
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

</beans>
  • 测试:
public class AppForDIConstructor {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

5、位置适配

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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);
    }
}
  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.UserDao;
import com.itheima.service.BookService;

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();
    }
}
  • 配置文件:
<?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">

    <!-- 3、根据构造方法参数位置注入,解决参数类型重复问题,使用位置解决参数匹配-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg index="0" value="mysql"/>
        <constructor-arg index="1" value="100"/>
    </bean>
    
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

</beans>
  • 测试:
public class AppForDIConstructor {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

8.5 依赖注入方式选择

  1. 强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致 null 对象出现
  2. 可选依赖使用 setter 注入进行,灵活性强
  3. Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入
  6. 自己开发的模块推荐使用 setter 注入

8.6 依赖自动装配

1、自动装配概念

  • IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配
  • 自动装配方式
    • ==按类型(常用)==
    • 按名称
    • 按构造方法
    • 不启用自动装配

2、自动装配类型

  • 配置中使用 bean 标签 autowire 属性设置自动装配的类型
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

3、示例

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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);
    }
}
  • BookServiceImpl.java 中的代码:
package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService{
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}
  • 配置文件:
<?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 class="com.itheima.dao.impl.BookDaoImpl"/>
    <!-- autowire属性:开启自动装配,通常使用按类型装配 -->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

</beans>
  • 测试:
public class AppForDIConstructor {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

4、依赖自动装配特征

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

8.7 集合注入

1、注入数组类型数据

<property name="array">
    <array>
        <value>100</value>
        <value>200</value>
        <value>300</value>
    </array>
</property>

2、注入List类型数据

<property name="list">
    <list>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>chuanzhihui</value>
    </list>
</property>

3、注入Set类型数据

<property name="set">
    <set>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>boxuegu</value>
    </set>
</property>

4、注入Map类型数据

<property name="map">
    <map>
        <entry key="country" value="china"/>
        <entry key="province" value="henan"/>
        <entry key="city" value="kaifeng"/>
    </map>
</property>

5、注入Properties类型数据

<property name="properties">
    <props>
        <prop key="country">china</prop>
        <prop key="province">henan</prop>
        <prop key="city">kaifeng</prop>
    </props>
</property>

说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签

6、示例

  • BookDaoImpl.java 中的代码:
package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

import java.util.*;

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 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="com.itheima.dao.impl.BookDaoImpl">
        <!-- 1、数组注入 -->
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>

        <!-- 2、list集合注入 -->
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
            </list>
        </property>

        <!-- 3、set集合注入 -->
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
            </set>
        </property>

        <!-- 4、map集合注入 -->
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
            </map>
        </property>

        <!-- 5、Properties注入 -->
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>
    </bean>
</beans>
  • 测试:
package com.itheima;

import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForDICollection {
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}
  • 效果:

图片转存失败,建议将图片保存下来直接上传