spring01:IOC控制反转、DI依赖注入


一、什么是spring框架

spring是一个高度灵活的轻量级框架,其目的是降低企业级应用开发的复杂度。spring在javaEE项目中应用广泛,采用Java语言开发,免费开源。

二、spring概述

在程序中由某几个包实现某个功能,这几个包就是一个模块,不同的包由不同的模块构成。Spring、Spring MVC、MyBatis分属于不同的模块。

1. spring功能介绍

1.1 IOC机制

IOC可以创建对象以及管理对象之间的调用关系。IOC机制用来整合其他框架,降低模块间的耦合性/依赖性。

1.2 AOP面向切面编程

将一些方法中的具有相同功能的部分抽取出来,设置为切面。降低代码的冗余性和提高代码的可维护性。

1.3 事务控制

1.4 对jdbc做了轻量级封装

这一部分内容,可以由MyBatis来实现

1.5 提供了上传下载、定时器等工具

2. spring功能模块划分

在这里插入图片描述

3. jar包说明

在这里插入图片描述


第一部分内容:IOC控制反转


三、IOC介绍

介绍IOC之前,先讲解一下Tomcat服务器。spring和Tomcat都是容器。容器就是装载程序文件的存储器。之前学到了Servlet和jsp都是存储在Tomcat这个容器里的。Servlet和jsp都是Tomcat容器的组件,之所以称为组件,是因为它们只有在Tomcat这个服务器里才可以运行。Servlet和jsp就是由Tomcat这个容器来创建和维护的。

1. 什么是IOC

IOC(Inversion of Control)叫做控制反转。前面我们说道,IOC可以创建对象以及管理对象之间的调用关系。原来类里的对象是由我们自己创建和管理的,现在我们要让spring这个容器来创建和维护对象,我们将控制权交给spring来管理,这就是控制反转。

那我们如何获取对象呢?我们需要先获取spring容器,然后用容器来获取对象;由spring来创建对象并赋值;类写好后,由spring来进行配置。

2. IOC实现控制反转的两种方式

  1. 使用配置文件将类转为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" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

	<!--将Cat类创建为bean组件,通过id可获取该bean组件-->
    <bean id="cat2" class="com.bean.Cat"></bean>
</beans>    
  1. 使用注解将类转为bean组件
    ①在要转为组件的类上添加注解
    ②为注解添加配置文件,通过扫描将注解添加到spring容器中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

	<!--使用注解的方式为类配置成spring的bean组件,前提是需要启动扫描写注解的包-->
	<context:component-scan base-package="com"></context:component-scan>

四. 使用配置文件将类转为bean组件

1. 创建文件,引入jar包

在这里插入图片描述

2. 添加配置文件

这是个JavaSE项目,在src下创建 spring.xml 配置文件
在这里插入图片描述
添加spring配置信息:

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

</beans>

3. spring入门程序——无参/带参构造方法

3.1 Dog类

package com.bean;

public class Dog {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Dog() {
        System.out.println("无参构造方法,创建了对象");
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //初始化方法
    public void init() {
        System.out.println(this.name + "dog被初始化");
    }

    //销毁方法
    public void destroy() {
        System.out.println(this.name + "dog被销毁");
    }
}

3.2 spring.xml

相关介绍:

标签/属性含义或作用
bean标签配置文件里所有的bean都是spring容器管理的bean组件,也就是类对象
id用来获取bean组件
class对象的数据类型
scope用来设置单例模式,不写默认为单例
init-method设置初始化方法
destroy-method设置销毁方法(单例模式下起作用)
constructor-arg设置带参构造方法,不写默认为无参构造方法
index参数索引(从0开始)
value自定义的参数值
<?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="dog1" class="com.bean.Dog" scope="singleton" init-method="init" destroy-method="destroy"></bean>

    <bean id="dog2" class="com.bean.Dog">
    	<!--需要做参数对应,参数索引从0开始-->
        <constructor-arg index="0" value="小黄"></constructor-arg>
        <constructor-arg index="1" value="3"></constructor-arg>
    </bean>

</beans>

3.3 DogTest类

测试类:通过无参或带参方法,创建一个狗对象,并输出对象的信息。

package com.test;

import com.bean.Dog;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DogTest {
    //这里创建静态容器对象
    //ApplicationContext是spring对象,这个对象不能调用close方法
    //private static ApplicationContext ac = null;
    //ClassPathXmlApplicationContext是spring实现类对象,可以调用close方法关闭容器
    private static ClassPathXmlApplicationContext ac = null;
    static {
        ac = new ClassPathXmlApplicationContext("spring.xml");
    }
    @Test
    public void dogTest() {
    	// bean组件是Object类型
    	// spring容器通过无参或带参方法创建对象
        Dog dog1 = (Dog) ac.getBean("dog1");
        dog1.setName("小黑");
        dog1.setAge(7);
        System.out.println(dog1);
        //关闭spring容器
        ac.close();
    }
}

4. 单例、多例模式

同一个bean组件,默认是单例模式,对应的是同一个对象。
在这里插入图片描述
在这里插入图片描述

4.1 单例模式测试

  1. spring.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" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="dog" class="com.bean.Dog">
        <constructor-arg index="0" value="小白"></constructor-arg>
        <constructor-arg index="1" value="2"></constructor-arg>
    </bean>
</beans>    
  1. CatTest
package com.test;

import com.bean.Dog;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DogTest {
	// 创建spring对象
    private static ApplicationContext ac = null;
    static {
        ac = new ClassPathXmlApplicationContext("spring.xml");
    }

    @Test
    public void testDog() {
        Dog dog = (Dog) ac.getBean("dog");
        System.out.println(dog);

        Dog dog2 = (Dog) ac.getBean("dog");
        System.out.println(dog2);
    }
}

  1. 测试结果
    在这里插入图片描述

4.2 多例模式测试

多例模式设置:
在这里插入图片描述

测试结果:
在这里插入图片描述
可以看出这里是调用了两次无参构造方法,创建了两个对象。

5. 懒加载

5.1 懒加载的作用/应用范围

Spring框架提供了懒加载机制。懒加载可以让指定的bean不在启动时创建对象,而是在第一次使用时才创建,可以降程序运行过程中对时间和内存的消耗。懒加载机制只有在单例模式下才起作用(默认bean组件是单例模式),对于多例模式的懒加载没有意义(多例bean是在使用时才会创建)。

没有指定是哪个bean组件,默认是第一个bean组件

  1. 不设置懒加载:
<context:component-scan base-package="com"></context:component-scan>
	<bean id="dog1" class="com.bean.Dog"></bean>
 @Test
    public void dogLazTest() {
       
    }

测试结果:单例bean组件自动创建了对象
在这里插入图片描述

  1. 设置懒加载:
    lazy-init 默认是 false,单例模式下才起作用,默认bean组件是单例模式
<context:component-scan base-package="com"></context:component-scan>
	<bean id="dog1" class="com.bean.Dog" lazy-init="true"></bean>
 @Test
    public void dogLazTest() {
       
    }

测试结果:单例bean组件没有自动创建
在这里插入图片描述

6. 初始化方法、销毁方法

  1. 方法创建:
    在这里插入图片描述

  2. spring框架的配置文件
    在这里插入图片描述

  3. 不同模式下,方法的执行情况
    单例模式下:bean对象随着框架的关闭而销毁
    多例模式下:bean对象不会随着框架的关闭而销毁
    初始化方法:创建后马上执行初始化方法
    销毁方法:销毁前马上执行销毁方法

  4. 测试结果:
    4.1 多例模式下的测试结果:没有执行销毁方法
    在这里插入图片描述

    4.2 单例模式下的测试结果:框架关闭时,会销毁bean对象,因此会执行销毁方法
    在这里插入图片描述

  5. 注意
    这里创建的是

7. IOC功能——依赖注入DI(dependency injection)

依赖注入讲的是,IOC如何给属性注入值。
在这里插入图片描述

7.1 实现方式

  1. 使用配置文件(本文介绍的就是使用配置文件)
  2. 使用注解(第二篇介绍使用注解)

7.2 注入方式

  1. 手动注入
  2. 自动匹配

8. 手动注入

标签/属性含义/作用
property标签为属性赋值
name属性名
value属性值
list标签为list集合赋值
set标签为set集合赋值
array标签为数组赋值
value标签为list/set/array设置值
ref标签引入外部对象
bean对象id
map标签为map集合赋值
entry标签添加map集合属性
key设置键
value设置值
props标签为properties集合赋值
prop标签添加property集合属性
key设置键
prop标签里设置值

8.1 八种基本数据类型+其封装类型+String

  1. 通过setter方法设置属性
    配置文件:
    <bean id="dog1" class="com.bean.Dog" scope="singleton" init-method="init" destroy-method="destroy"></bean>

测试文件:

	@Test
    public void dogTest() {
        Dog dog1 = (Dog) ac.getBean("dog1");
        dog1.setName("小黑");
        dog1.setAge(7);
        System.out.println(dog1);
    }
  1. 通过构造方法设置属性
    配置文件:
	<bean id="dog2" class="com.bean.Dog">
        <constructor-arg index="0" value="小黄"></constructor-arg>
        <constructor-arg index="1" value="3"></constructor-arg>
    </bean>

测试文件:

	@Test
    public void dogTest() {
        Dog dog2 = (Dog) ac.getBean("dog2");
        System.out.println(dog2);
    }
  1. 通过属性注入设置属性
    配置文件:
	<bean id="dog1" class="com.bean.Dog">
		<property name="name" value="小蓝"></property>
		<property name="age" value="6"></property>
	</bean>

测试文件:

	@Test
    public void testDog() {
        Dog dog = (Dog) ac.getBean("dog1");
        System.out.println(dog);
    }

测试结果:
在这里插入图片描述

8.2 属性是对象

外部注入——通过property标签的ref引用其它bean标签

配置文件:

 	<bean id="dog" class="com.bean.Dog">
        <property name="name" value="小白"></property>
        <property name="age" value="5"></property>
    </bean>

    <bean id="boy" class="com.bean.Boy">
        <property name="name" value="小王"></property>
        <property name="age" value="8"></property>
        <property name="dog" ref="dog"></property>
    </bean>    

测试文件:

	@Test
    public void testDog() {
        Dog dog = (Dog) ac.getBean("dog");
        System.out.println(dog);
    }
内部注入——直接在property标签里内嵌bean标签

配置文件:

	<bean id="boy" class="com.bean.Boy">
        <property name="dog">
            <bean class="com.bean.Dog">
                <property name="name" value="小黄"></property>
                <property name="age" value="9"></property>
            </bean>
        </property>
    </bean>    

测试文件:

	@Test
    public void testDog() {
        Dog dog = (Dog) ac.getBean("dog");
        System.out.println(dog);
    }

8.3 属性是集合、数组

属性值分别写在 list、array标签里的value标签里。
配置文件:

	<bean id="boy" class="com.bean.Boy">
        <!--list集合-->
        <property name="hobbies">
            <list>
                <value>游泳</value>
                <value>跑步</value>
                <value>跳舞</value>
            </list>
        </property>

        <!--数组-->
        <property name="jobs">
            <array>
                <value>学生</value>
                <value>后端开发</value>
                <value>全栈工程师</value>
            </array>
        </property>
	</bean>        

测试代码:

	// 集合、数组等属性依赖注入
    @Test
    public void listAndArray() {
        Boy boy = (Boy) ac.getBean("boy3");
        List<String> hobbies = boy.getHobbies();
        hobbies.forEach(hobby -> {
            System.out.println(hobby);
        });

        String[] jobs = boy.getJobs();
        for (int i=0; i < jobs.length; i++) {
            System.out.println(jobs[i]);
        }
    }

8.4 属性是map集合、properties集合

配置文件:

<bean id="boy" class="com.bean.Boy">
        <!--Map集合-->
        <property name="langMap">
            <map>
            	<!--如果存的是对象的话,可以用ref来引用-->
                <entry key="zh" value="中文"></entry>
                <entry key="en" value="英文"></entry>
            </map>
        </property>

        <!--property集合-->
        <property name="langProp">
            <props>
                <prop key="zh">中文</prop>
                <prop key="en">英文</prop>
            </props>
        </property>
    </bean>

测试代码:

	// map集合、properties集合测试
    @Test
    public void mapAndProperties() {
        Boy boy = (Boy) ac.getBean("boy4");
        Map<Integer, String> lanMap = boy.getLanMap();
        for (int i = 0; i < lanMap.size(); i++) {
            System.out.println(lanMap.get(i));
        }

        Properties langPro = boy.getLanPro();
        System.out.println(langPro.getProperty("zh"));
        System.out.println(langPro.getProperty("en"));
    }

8.5 通过构造方法给属性赋值

构造方法:必须有对应的构造方法,才能使用如下的配置

	public Boy(String name, Integer age, Dog dog, List<String> hobbies, String[] jobs, Map<String, String> langMap, Properties langProp) {
        this.name = name;
        this.age = age;
        this.dog = dog;
        this.hobbies = hobbies;
        this.jobs = jobs;
        this.langMap = langMap;
        this.langProp = langProp;
    }

配置文件:

	<bean id="boy2" class="com.bean.Boy">
        <constructor-arg index="0" value="小李"></constructor-arg>
        <constructor-arg index="1" value="10"></constructor-arg>
        <constructor-arg index="2" ref="dog"></constructor-arg>
        <constructor-arg index="3">
            <list>
                <value>跑步</value>
                <value>跳远</value>
            </list>
        </constructor-arg>
        <constructor-arg index="4">
            <array>
                <value>老师</value>
                <value>父亲</value>
            </array>
        </constructor-arg>
        <constructor-arg index="5">
            <map>
                <entry key="zh" value="中文"></entry>
                <entry key="en" value="英文"></entry>
            </map>
        </constructor-arg>
        <constructor-arg index="6">
            <props>
                <prop key="zh">中文</prop>
                <prop key="en">英文</prop>
            </props>
        </constructor-arg>
    </bean>

9. 自动注入

自动注入一共有三种方式:

方式解释
byType根据类属性的数据类型自动注入 (常用)
byName根据类属性名自动注入
constructor根据构造方法自动注入

byType:根据类属性的数据类型在spring容器里查找与它同类型的bean(属性的数据类型=bean的class)。如果找到一个,那么就给该属性注入值;找到多个报异常;没有找到,该属性就是默认值。

byName:根据属性的名字在spring容器里查找与该属性同名的bean(属性名=bean的id)。如果找到并且该bean的类型与属性的数据类型相同,则注入值;如果类型不同,则发送异常;如果没有找到与属性同名的bean,则不注入值。

constructor:根据类里的构造方法的参数的数据类型去spring容器里查找是否有bean可以为参数赋值(参数的数据类型=bean的id)。如果参数个数类型都有相匹配的bean赋值,执行该构造方法;只要有一个参数没有匹配上,就执行无参构造方法;如果没有无参构造方法,就只能报异常了

在这里插入图片描述

byType

  1. byType正确获取
    在这里插入图片描述
    在这里插入图片描述
  2. 如果在spring容器中匹配到多个类型相同的bean就报异常
    在这里插入图片描述

byName

  1. byName正确获取,狗类里有一个Dog类型的属性,其属性名是dog
    在这里插入图片描述
    在这里插入图片描述
  2. 属性名和bean里的id匹配但数据类型不一样,会报异常。

在这里插入图片描述
在这里插入图片描述

constructor

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员_动次动次

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值