Spring

发布时间 2023-05-29 21:01:48作者: YxinHaaa

一、Spring简介

优点:

简化开发

框架整合

官网:https://spring.io

image-20230526144213831

发展史

image-20230526144234481

1. Spring Framework系统架构图

image-20230526144327595

image-20230526144337404

2. 目前问题

image-20230526144434401

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

3. 核心概念

  • IOC(Inversion of Control)控制反转 控制权的反转 创建对象的控制权由程序员变为了spring

    使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。通俗的讲就是“将new对象的权利交给Spring,我们从Spring中获取对象使用即可” spring提前把new好的对象存放在一个容器中,这个容器就是核心容器

  • Spring技术对IoC思想进行了实现

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

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

    • DI(Dependency Injection)依赖注入

    • 类要依赖他的属性,所以我们说类的依赖就是他的属性

    • spring在创建对象时给对象的属性赋值 就称为依赖注入

    • spring ioc 容负责创建对象 我们称之为控制反转 创建对象的同时给属性赋值 我们称之为依赖注入

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

        我们从spring ioc容器中要了一个数据访问访问层对象赋给了 bookDao这个变量 ,这个过程就叫依赖注入

image-20230526145707250

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

二、Spring使用

1. IOC实现步骤

【第一步】导入Spring坐标
【第二步】定义Spring管理的类(接口与实现类)
【第三步】创建Spring配置文件,配置对应类作为Spring管理的bean对象
【第四步】初始化IOC容器(Spring核心容器/Spring容器),通过容器获取bean对象

【第一步】导入Spring坐标

 <dependencies>
        <!--spring核心依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.12</version>
        </dependency>

        <!--junit的依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

【第二步】定义Spring管理的类(接口)

BookDao接口和BookDaoImpl实现类

package com.tyhxzy.dao;

/**
 * 书籍的DAO接口
 */
public interface BookDao {
    /**
     添加书籍
     */
    void save();
}
package com.tyhxzy.dao.impl;

import com.tyhxzy.dao.BookDao;

/**
 * 书籍DAO的实现类
 */
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("DAO:添加书籍到数据库");
    }
}

BookService接口和BookServiceImpl实现类

package com.tyhxzy.service;

public interface BookService {
    /**
     添加书籍
     */
    void save();
}
package com.tyhxzy.service.impl;

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

public class BookServiceImpl implements BookService {
    //创建成员对象
    private BookDao bookDao = new BookDaoImpl();

    //实现业务方法
    @Override
    public void save() {
        System.out.println("业务层:调用添加书籍的方法");
        bookDao.save();
    }
}

【第三步】创建Spring配置文件,配置对应类作为Spring管理的bean对象

  • 定义applicationContext.xml配置文件并配置BookServiceImpl
  • 注:如果顶部出现提示信息,选择Disable inspection

image-20230526150630401

<?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标签的作用: 创建制定类的对象并且存储到spring的容器中
        class: 指定你创建的对象所属的类的类全名
        id: 该对象在容器中的唯一标识
        -->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl"/>


</beans>

注意事项:bean定义时id属性在同一个上下文中(IOC容器中)不能重复

【第四步】初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象

package com.tyhxzy.test;

import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.save();

        //3。关闭容器(以后不需要关闭的)
        context.close();
    }
}

运行结果

image-20230526150813849

2. DI实现步骤

【第一步】删除使用new的形式创建对象的代码
【第二步】提供依赖对象对应的setter方法
【第三步】配置service与dao之间的关系

实现代码

【第一步】删除使用new的形式创建对象的代码

package com.tyhxzy.service.impl;

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

public class BookServiceImpl implements BookService {
    //【第一步】删除使用new的形式创建对象的代码,解除对象之间的耦合度
    private BookDao bookDao;

    //实现业务方法
    @Override
    public void save() {
        System.out.println("业务层:调用添加书籍的方法");
        bookDao.save();
    }
}

【第二步】提供依赖对象对应的setter方法

package com.tyhxzy.service.impl;

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

public class BookServiceImpl implements BookService {

    //service需要依赖Dao
    private BookDao bookDao ;

    @Override
    public void save() {
        bookDao.save();
        System.out.println("service:添加书本..");
    }

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

【第三步】配置service与dao之间的关系

在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. 创建Dao的对象,并且把该对象存储到了spring的容器中-->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>



    <!--使用bean标签即可使用spring的ioc的功能,让spring创建BookServiceImpl这个类的对象
        id:  该对象在容器中唯一标示,名字可以随意,但是要确保唯一性。
        class: 通知spring帮我们创建制定类的对象,并且放入spring的容器中。
    -->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl">
          <!--给对象的bookDao的属性赋值
               name: 属性名,属性名是依赖setter方法的。
               ref: 引用,引用另外一个对象给该属性赋值。
          -->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

图解演示

image-20230526161619419

  • 标签
  • name:属性名,属性名依赖setter方法
  • ref: 引入的对象的id

3. Bean的基础配置

配置说明

image-20230526163301811

Bean别名配置

image-20230529143547907

<?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. 创建Dao的对象,并且把该对象存储到了spring的容器中-->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>




    <!--name作用:给对象起一个别名,name与id的区别:id只能配置一个,name可以配置多个,name多个别名是使用,; 空格分隔-->
    <bean id="bookService" name="bookService1,bookService2,bookService4 bookService5" class="com.tyhxzy.service.impl.BookServiceImpl">
          <!--给对象的bookDao的属性赋值
               name: 属性名,属性名是依赖setter方法的。
               ref: 引用,引用另外一个对象给该属性赋值。
          -->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>
package com.tyhxzy.test;

import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookService bookService = context.getBean("bookService2", BookService.class);
        bookService.save();

        //3。关闭容器(以后不需要关闭的)
        context.close();
    }
}

image-20230529150515969

4. Bean作用范围配置

image-20230529150548091

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

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. 创建Dao的对象,并且把该对象存储到了spring的容器中-->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>




    <!--name作用:给对象起一个别名,name与id的区别:id只能配置一个,name可以配置多个,name多个别名是使用,; 空格分隔
        scope作用: 指定对象的作用范围, 常用两种: singleton(单例,默认) , prototype(多例)
    -->
    <bean id="bookService" name="bookService1,bookService2,bookService4 bookService5"
          class="com.tyhxzy.service.impl.BookServiceImpl" scope="prototype">
          <!--给对象的bookDao的属性赋值
               name: 属性名,属性名是依赖setter方法的。
               ref: 引用,引用另外一个对象给该属性赋值。
          -->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>
package com.tyhxzy.test;

import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookService bookService1 = context.getBean("bookService2", BookService.class);
        BookService bookService2 = context.getBean("bookService2", BookService.class);

        System.out.println("两个对象是同一个吗?"+(bookService1==bookService2));

        //3。关闭容器(以后不需要关闭的)
        context.close();
    }
}

image-20230529150645268

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

  • 在<bean>标签上如何配置别名?
    • name属性可以配置
  • 那Bean的默认作用范围是什么?如何修改?
    • 单例,singleton.
    • scope="prototype|singleton"

四、Bean的实例化

Bean的实例化方式有几种

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

1. 实例化Bean的三种方式

1.1 构造方法方式

package com.tyhxzy.dao.impl;

import com.tyhxzy.dao.BookDao;

public class BookDaoImpl implements BookDao {

    public BookDaoImpl() {
        System.out.println("BookDaoImpl的无参构造方法创建了....");
    }

    @Override
    public void save() {
        System.out.println("DAO:添加了图书..");
    }
}

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>
    -->


</beans>

AppTest测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookDao bookDao = context.getBean("bookDao", BookDao.class);
        bookDao.save();

        //3。关闭容器(以后不需要关闭的)
        context.close();
    }
}

image-20230529152606199

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

1.2 静态工厂方式

BookFactoryBean工厂类

package com.tyhxzy.factory;

import com.tyhxzy.dao.BookDao;
import com.tyhxzy.dao.impl.BookDaoImpl;

public class BookFactoryBean {

    /*
    静态的工厂方法
     */
    public static BookDao getBookDao(){
        System.out.println("静态工厂方法...");
        return new BookDaoImpl();
    }

}

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>
    -->


    <!--方式二: 利用静态工厂方法创建对象
        id: 该对象在spring容器中id
        class: 静态工厂类的全类名
        factory-method: 静态工厂的方法名
    -->
    <bean id="bookDao" class="com.tyhxzy.factory.BookFactoryBean" factory-method="getBookDao"/>


</beans>

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>
    -->


    <!--方式二: 利用静态工厂方法创建对象
        id: 该对象在spring容器中id
        class: 静态工厂类的全类名
        factory-method: 静态工厂的方法名
    -->
    <bean id="bookDao" class="com.tyhxzy.factory.BookFactoryBean" factory-method="getBookDao"/>


</beans>

AppTest测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookDao bookDao = context.getBean("bookDao", BookDao.class);
        bookDao.save();

        //3。关闭容器(以后不需要关闭的)
        context.close();
    }
}

运行结果

image-20230529153027404

1.3 实例工厂方法方式

BookFactoryBean工厂类

package com.tyhxzy.factory;

import com.tyhxzy.dao.BookDao;
import com.tyhxzy.dao.impl.BookDaoImpl;

public class BookFactoryBean {

   

    /*
    非静态方法创建BookDaoImpl对象
     */
    public BookDao getBookDao2(){
        System.out.println("非静态工厂方法...");
        return new BookDaoImpl();
    }

}

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl"/>
    -->


    <!--方式二: 利用静态工厂方法创建对象
        id: 该对象在spring容器中id
        class: 静态工厂类的全类名
        factory-method: 静态工厂的方法名

    <bean id="bookDao" class="com.tyhxzy.factory.BookFactoryBean" factory-method="getBookDao"/>
     -->

    <!--方式三:非静态工厂方法创建对象
        步骤:
            1. 创建工厂类的对象
            2. 调用非静态方法创建制定类的对象
    -->

    <!--1. 创建工厂类的对象-->
    <bean id="bookFactoryBean" class="com.tyhxzy.factory.BookFactoryBean"/>

    <!--2. 调用非静态方法创建制定类的对象-->
    <bean id="bookDao" factory-bean="bookFactoryBean" factory-method="getBookDao2"/>
</beans>

image-20230529153132574

Bean的实例化方式有几种?

  • 无参的构造器
  • 工厂静态方法
  • 工厂非静态方法

五、Bean的生命周期

1. 生命周期相关概念介绍

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

2.代码演示

提供生命周期控制方法

package com.tyhxzy.dao.impl;

import com.tyhxzy.dao.BookDao;

public class BookDaoImpl implements BookDao {

    /*
     如果BookDao对象创建的会调用init方法
     */
    public void init(){
        System.out.println("init方法被调用了,该类的对象已经被创建了..");
    }

    /*
        销毁该类的对象前调用方法

     */
    public void destroy(){
        System.out.println("destroy被调用了,马上就要销毁该类对象了...");
    }



    @Override
    public void save() {
        System.out.println("DAO:添加了图书..");
    }
}

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">

    <!--
        init-method:  指定创建对象的时候调用的初始化方法的方法名
        destroy-method: 销毁对象前指定调用的方法
        默认情况spring使用的是饿汉单例设计模式,如果需要修改饿汉单例设计模式,可以lazy-init修改
            lazy-init="true" 懒汉模式
            lazy-init=false  饿汉模式 , 默认
    -->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl" init-method="init" lazy-init="true" destroy-method="destroy" />

</beans>

测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/*

    核心知识点:
        1. 默认情况spring使用的是饿汉单例设计模式,不是懒汉单例设计模式。在容器启动就创建该类的对象了。
        2. 容器关闭的时候才会销毁对象。


 */

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
        //        //1.创建spring的容器,读取配置文件 ,   ApplicationContext  是spring的容器的根接口。
        //ClassPathXmlApplicationContext这个容器特点:根据类路径去读取配置文件的。
        ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("applicationContext.xml");
        context.close();
        //2. 通过id从spring的容器中查找对象
        //BookService bookService = (BookService) context.getBean("bookService");

        //从容器中获取对象的时候,告诉容器对象的类型即可
        BookDao bookDao = context.getBean("bookDao", BookDao.class);
        bookDao.save();

        //3。关闭容器(以后不需要关闭的)
        context.close();
      //  context.registerShutdownHook(); //这种方式是注册到jvm,通知jvm容器关闭的时候调用destroy方法。
    }
}

​ spring的bean对象的生命周期? 与什么周期相关的两个属性?

  • ​ 创建spring容器的时候创建。
  • init-method , destory-method

六、依赖注入(DI配置)

1.1 依赖注入的两种方式

  • setter注入
    简单类型(八种基础数据类型+stirng类型)
    引用类型(很常用)
  • 构造器注入
    简单类型
    引用类型

1.2 setter方式注入

问题导入

setter方式注入使用什么子标签?

引用类型

在bookService中使用ref注入bookDao

image-20230529155627068

<?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.tyhxzy.dao.impl.BookDaoImpl"/>

    <!--依赖注入方式一: 利用setter方法,使用property标签注入-->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>
简单类型
  1. 在BookDaoImpl中添加int connectionNumber
  2. 添加set方法
  3. 在配置文件中注入10
package com.tyhxzy.dao.impl;

import com.tyhxzy.dao.BookDao;

public class BookDaoImpl implements BookDao {

    private int connectionNumber;

    public void setConnectionNumber(int connectionNumber) {
        this.connectionNumber = connectionNumber;
    }

    @Override
    public void save() {
        System.out.println("DAO:添加了图书.."+connectionNumber);
    }
}

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl">
        <property name="connectionNumber" value="100"/>
    </bean>

    <!--依赖注入方式一: 利用setter方法,使用property标签注入-->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    //测试:从spring的容器中获取对象
    @Test
    public void  testGetBean(){
       //1. 获取容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 从容器中获取bookDao对象
        BookDao bookDao = context.getBean("bookDao", BookDao.class);
        bookDao.save();
        //3 关闭容器
        context.close();
    }
}

1.3 构造方式注入

问题导入

构造方式注入使用什么子标签?

引用类型
  1. 给BookServiceImpl添加构造方法,参数是BookDao
  2. 在配置文件中给bookService中使用构造器注入bookDao

image-20230529160318203

BookServiceImpl, 添加构造方法

package com.tyhxzy.service.impl;

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

public class BookServiceImpl implements BookService {

    //service需要依赖Dao
    private BookDao bookDao ;

    //一个带参的构造方法
    public BookServiceImpl(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void save() {
        bookDao.save();
        System.out.println("service:添加书本..");
    }

    //删除setter方法
//    public void setBookDao(BookDao bookDao) {
//        this.bookDao = bookDao;
//    }
}

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="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl">
        <property name="connectionNumber" value="100"/>
    </bean>

    <!--依赖注入方式一: 利用setter方法,使用property标签注入
        <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl">
            <property name="bookDao" ref="bookDao"/>
        </bean>
    -->

    <!--依赖注入方式二:利用构造方法给对象注入成员变量值-->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl">
       <!--
        index:  构造方法的参数的索引值,从0开始
        name: 构造方法的形参的名字

       <constructor-arg index="0" ref="bookDao"/>
       -->
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>



</beans>

测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {

    
    @Test
    public void  testGetServiceBean(){
        //1. 获取容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 从容器中获取bookDao对象
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.save();
        //3 关闭容器
        context.close();
    }
}

简单类型
  1. 给BookDao添加整数类型的构造方法

    package com.tyhxzy.dao.impl;
    
    import com.tyhxzy.dao.BookDao;
    
    

public class BookDaoImpl implements BookDao {

   private int connectionNumber;

   private  String databaseName;

/* public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}*/

   public BookDaoImpl(int connectionNumber) {
    this.connectionNumber = connectionNumber;
   }
   
   public BookDaoImpl(int connectionNumber, String databaseName) {
       this.connectionNumber = connectionNumber;
       this.databaseName = databaseName;
   }

   @Override
   public void save() {
       System.out.println("DAO:添加了图书.."+connectionNumber+" 数据库的名称:"+ databaseName);
   }

}


1. 使用配置通过构造器给BookDao注入属性值

```xml
 <!--利用构造器方式初始化成员变量-->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNumber" value="10"/>
        <constructor-arg name="databaseName" value="spring_db"/>
    </bean>
参数适配【了解】
  1. 按类型的方式匹配
  2. 按位置的方式匹配
步骤
  1. 添加新的成员变量:String databaseName

  2. 创建2个参数的构造方法

  3. 生成toString方法

    package com.tyhxzy.dao.impl;
    
    import com.tyhxzy.dao.BookDao;
    
    /**
     * 书籍DAO的实现类
     */
    public class BookDaoImpl implements BookDao {
    
        //成员变量
        private int connectionNumber;
        private String databaseName;
    
        //无参的构造方法
        public BookDaoImpl() {
        }
    
        //1个参数的构造方法
        public BookDaoImpl(int connectionNumber) {
            this.connectionNumber = connectionNumber;
        }
    
        //2个参数的构造方法
        public BookDaoImpl(int connectionNumber, String databaseName) {
            this.connectionNumber = connectionNumber;
            this.databaseName = databaseName;
        }
    
        @Override
        public String toString() {
            return "BookDaoImpl{" +
                    "connectionNumber=" + connectionNumber +
                    ", databaseName='" + databaseName + '\'' +
                    '}';
        }
    }
    
  4. 分别使用类型匹配和位置匹配的方式注入值

image-20230529160408405

2 依赖自动装配【理解】

问题导入

如何配置按照类型自动装配?

2.1 自动装配概念

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

2.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">


    <!--利用构造器方式初始化成员变量-->
    <bean id="bookDao" class="com.tyhxzy.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNumber" value="10"/>
        <constructor-arg name="databaseName" value="spring_db"/>
    </bean>

    <!--autowire: 创建该类对象的时候成员变量的初始化可以根据类型赋值,自动注入是依赖setter方法
        创建BookServiceImpl对象的时候发现,该类有一个成员变量需要BookDao,那么spring就会自动从容器中去
        查找是否有BookDao这种类型的对象。
    -->
    <bean id="bookService" class="com.tyhxzy.service.impl.BookServiceImpl" autowire="byType"/>



</beans>
package com.tyhxzy.service.impl;

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

public class BookServiceImpl implements BookService {

    //service需要依赖Dao
    private BookDao bookDao ;

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

    @Override
    public void save() {
        bookDao.save();
        System.out.println("service:添加书本..");
    }

}

测试类

package com.tyhxzy.test;

import com.tyhxzy.dao.BookDao;
import com.tyhxzy.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest {


    @Test
    public void  testGetServiceBean(){
        //1. 获取容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 从容器中获取bookDao对象
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.save();
        //3 关闭容器
        context.close();
    }
}

小结

​ 依赖注入有几种方式,分别对应的是哪个标签或者属性

  - 通过setter方法注入    property标签
  - 构造方法注入     constructor-arg

3 集合注入

3.1 注入数组类型数据

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

3.2 注入List类型数据

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

3.3 注入Set类型数据

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

3.4 注入Map类型数据

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

3.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>标签

小结:

​ 数组: array

​ list: list

​ set: set

​ map: map

​ properties: props