【Spring】Spring控制反转(Inversion of Control,IoC)(笔记一)

Love The Way You Lie 2023-10-08 15:22 60阅读 0赞

【Spring】Spring控制反转(Inversion of Control,IoC)(笔记一)

注:学习Spring的初期可能无法理解控制反转、依赖注入、注解等概念,不要气馁,坚持学习。学完注解开发基础后,再回头尝试去理解这些感念,会发现容易许多。(个人的一些感想)

文章目录

    • 【Spring】Spring控制反转(Inversion of Control,IoC)(笔记一)
      • 一、基础概念
        • 1、Spring框架概述
        • 2、Spring的优点
        • 3、Spring体系架构
        • 4、IOC的概念(重点)
        • 5、依赖注入(Dependency Injection,DI)
      • 二、控制反转(Inversion of Control,IoC)
        • 1、一个简单的Spring程序
          • 1.1 目录结构
          • 1.2 引入Maven依赖(pom.xml)
          • 1.3 自定义实体类Student
          • 1.4 Spring的配置文件applicationContext.xml
          • 1.5 测试类testSpring.java
          • 1.6 运行结果
        • 2、Spring的容器接口和实现类
          • 2.1 ApplicationContext 接口(容器)
          • 2.2 ApplicationContext容器中对象的装配时机
          • 2.3 Spring创建java对象结构图
        • 3、注入分类(重点)
          • 3.1 set注入
            • 3.1.1 简单类型
            • 3.1.2 引用类型
          • 3.2 构造方法的注入
          • 3.3 引用类型属性自动注入
            • 3.3.1 byName方式自动注入
            • 3.3.2 byType 方式自动注入
      • 4、基于注解的DI
        • 4.1 指定多个包的三种方式
        • 4.2 常用注解
          • 4.2.1 创建对象的注解
          • 4.2.2 给对象赋值的注解
          • 4.2.3 应用案例
      • Over!

一、基础概念

1、Spring框架概述
  • 2003年兴起的轻量级Java开发框架,为解决企业应用开发的复杂性而创建。
  • Spring的核心是 控制反转(IoC)面向切面编程(AOP)
  • Spring官网
  • 可以将Spring容器看成一个超级大工厂,负责创建、管理所有Java对象,这些Java对象被称为Bean。Spring通过“依赖注入(DI)”的方式管理Bean之间的依赖关系,使用“控制反转(IoC)”实现对象之间的“解耦合”。
2、Spring的优点
  • 1)轻量级:Spring框架使用的jar均较小,通常早1M以下,Spring核心功能所需的jar共4M左右。Spring框架运行占用资源少,运行效率高,且不依赖其它jar包。
  • 2)针对接口编程,解耦合:Spring提供了 控制反转(IoC),由容器管理对象及对象之间的依赖关系。
  • 3)AOP编程的支持:即将公共的、通用的重复的代码单独开发,在需要的时候反织回去,底层的原理是动态代理。
  • 4)方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,且Spring可降低各种框架的使用难度,Spring提供了对各种优秀框架(Struts2、Hibernate、MyBatis等)的直接支持。
3、Spring体系架构
  • Spring由20多个模块组成,可分为:数据访问/集成、Web、AOP、JVM代理、消息发送、核心容器、测试。
    在这里插入图片描述
4、IOC的概念(重点)
  • IoC是一个概念,又是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现独享的创建、属性的赋值、依赖的管理。
  • IoC的实现,当今流行的方式为依赖注入
5、依赖注入(Dependency Injection,DI)
  • 依赖:A类中含有B类的实例,在A中调用B的方法完成某项功能,即称A类对B类有依赖。
  • DI, 程序代码不用做定位查询,这些工作由容器自行完成。DI是指程序运行过程中,若需要调用另一个对象协助,无序代码中创建被调用者,而是依赖外部容器(Spring),有外部容器创建后传递给程序。
  • Spring框架使用依赖注入(DI)实现控制反转(IoC)。

二、控制反转(Inversion of Control,IoC)

以下通过案例阐述IoC与DI

案例基于Maven实现,有关Maven的使用不再阐述。

1、一个简单的Spring程序
1.1 目录结构

在这里插入图片描述

1.2 引入Maven依赖(pom.xml)
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.Etui</groupId>
  6. <artifactId>spring_01_demo</artifactId>
  7. <version>1.0-SNAPSHOT</version>
  8. <properties>
  9. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  10. <maven.compiler.source>1.8</maven.compiler.source>
  11. <maven.compiler.target>1.8</maven.compiler.target>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.11</version>
  18. <scope>test</scope>
  19. </dependency>
  20. <!-- 引入Spring依赖 -->
  21. <dependency>
  22. <groupId>org.springframework</groupId>
  23. <artifactId>spring-context</artifactId>
  24. <version>5.3.18</version>
  25. </dependency>
  26. </dependencies>
  27. <build>
  28. <resources>
  29. <resource>
  30. <directory>src/main/java</directory>
  31. <includes>
  32. <include>**/*.xml</include>
  33. <include>**/*.properties</include>
  34. </includes>
  35. </resource>
  36. <resource>
  37. <directory>src/main/resources</directory>
  38. <includes>
  39. <include>**/*.xml</include>
  40. <include>**/*.properties</include>
  41. </includes>
  42. </resource>
  43. </resources>
  44. </build>
  45. </project>
1.3 自定义实体类Student
  1. package com.Etui.entity01;
  2. public class Student {
  3. private String name;
  4. private Integer age;
  5. public void setName(String name) {
  6. this.name = name;
  7. }
  8. public void setAge(Integer age) {
  9. this.age = age;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Student{" +
  14. "name='" + name + '\'' +
  15. ", age=" + age +
  16. '}';
  17. }
  18. public Student() {
  19. System.out.println("Student对象被创建……………………");
  20. }
  21. }
1.4 Spring的配置文件applicationContext.xml
  • Spring 的配置文件位于rsrc/main/resources目录下,文件名任意。
  • :用于定义一个实例对象,一个实例对象对应一个bean元素。

    id:bean实例的唯一标识,相当于实例对象的名称。 class:指定该bean的类,这里只能是类不能是接口

    <?xml version=”1.0” encoding=”UTF-8”?>







1.5 测试类testSpring.java
  1. package com.Etui.test01;
  2. import com.Etui.entity01.Student;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class testSpring {
  7. // 传统常见Student对象的方法
  8. @Test
  9. public void testStudent() {
  10. Student student = new Student();
  11. System.out.println(student);
  12. }
  13. // 通过Spring创建对象的方法
  14. @Test
  15. public void testStudentSpring() {
  16. ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");
  17. Student student = (Student) ac.getBean("stu");
  18. System.out.println(student);
  19. }
  20. }
1.6 运行结果

在这里插入图片描述

2、Spring的容器接口和实现类
2.1 ApplicationContext 接口(容器)
  • ApplicationContext用于加载Spring的配置文件,在程序中充当“容器”的角色,它的实现类有两个:
    在这里插入图片描述
  • Spring 配置文件在项目的类路径下,则使用ClassPathXmlApplicationContext 实现类进行加载。
2.2 ApplicationContext容器中对象的装配时机
  • ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。 以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。Spring初始化对象时要使用无参的构造方法,切记保证类中有无参构造方法。
2.3 Spring创建java对象结构图

\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-12RfOq7h-1650805242647)(F:\\CSDN写作素材\\Sprin容器创建对象.jpg)\]

3、注入分类(重点)

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。根据注入方式的不同,常用的有两类:set 注入、构造注入

3.1 set注入
  • 通过setter方法传入调用者的实例。这种注入方式简单直观,在spring的依赖注入中大量使用。
3.1.1 简单类型
  • School类

    1. package com.Etui.entity02;
    2. public class School {
    3. private String name;
    4. private String address;
    5. public School() {
    6. System.out.println("School类被创建………………");
    7. }
    8. @Override
    9. public String toString() {
    10. return "School{" +
    11. "name='" + name + '\'' +
    12. ", address='" + address + '\'' +
    13. '}';
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. public void setAddress(String address) {
    19. this.address = address;
    20. }
    21. }
  • spring配置文件

    1. <!-- 创建School对象 -->
    2. <bean id="school" class="com.Etui.entity02.School">
    3. <property name="name" value="合肥学院"></property>
    4. <property name="address" value="合肥市蜀山区"></property>
    5. </bean>
  • 测试类
    \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PCZpxNmX-1650805242648)(C:\\Users\\34162\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220424172003413.png)\]
3.1.2 引用类型
  • 当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。ref 的值必须为某 bean 的 id 值。如下,Student类中含有Scholar类。

    1. package com.Etui.entity02;
    2. public class Student {
    3. private String name;
    4. private Integer age;
    5. private School school;
    6. @Override
    7. public String toString() {
    8. return "Student{" +
    9. "name='" + name + '\'' +
    10. ", age=" + age +
    11. ", school=" + school +
    12. '}';
    13. }
    14. public void setName(String name) {
    15. this.name = name;
    16. }
    17. public void setAge(Integer age) {
    18. this.age = age;
    19. }
    20. public void setSchool(School school) {
    21. this.school = school;
    22. }
    23. public Student() {
    24. }
    25. }
  • 对其他对象的引用,使用bean标签的ref属性:

    1. <!-- 创建Student对象 -->
    2. <bean id="student" class="com.Etui.entity02.Student">
    3. <property name="name" value="凝光"></property>
    4. <property name="age" value="21"></property>
    5. <property name="school" ref="school"></property>
    6. </bean>
  • 测试类
    在这里插入图片描述
3.2 构造方法的注入
  • 构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器依赖关系。在实体类中必须提供相应参数的构造方法。
  • 构造注入通过标签实现,该标签属性有:

    • name:指定参数名称。
    • index:参数对应着构造器的第几个参数,从零开始。可不写,但若参数类型相同,或参数之间有包含关系,则需要保证赋值顺序与构造器中的参数顺序一致。
  • 实体类如下:

    1. package com.Etui.entity02;
    2. public class School {
    3. private String name;
    4. private String address;
    5. }
    6. public class Student {
    7. private String name;
    8. private Integer age;
    9. }
    10. public class Student {
    11. private String name;
    12. private Integer age;
    13. private School school;
    14. }
  • 构造方法注入共有以下三种注入方式:

    1. <!-- 创建学校的对象,使用构造方法参数名称注入值 -->
    2. <bean id="school" class="com.Etui.entity03.School">
    3. <constructor-arg name="name" value="合肥学院"></constructor-arg>
    4. <constructor-arg name="address" value="合肥市蜀山区"></constructor-arg>
    5. </bean>
    6. <!-- 创建学生对象,使用构造方法的参数的下标注入值 -->
    7. <bean id="student" class="com.Etui.entity03.Student">
    8. <constructor-arg index="0" value="钟离"></constructor-arg>
    9. <constructor-arg index="1" value="23"></constructor-arg>
    10. <constructor-arg index="2" ref="school"></constructor-arg>
    11. </bean>
    12. <!-- 创建学生对象,使用默认的构造方法的参数顺序 -->
    13. <bean id="studentSequence" class="com.Etui.entity03.Student">
    14. <constructor-arg value="甘雨"></constructor-arg>
    15. <constructor-arg value="18"></constructor-arg>
    16. <constructor-arg ref="school"></constructor-arg>
    17. </bean>
3.3 引用类型属性自动注入
3.3.1 byName方式自动注入
  • 当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
3.3.2 byType 方式自动注入
  • 使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类, 要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。

4、基于注解的DI

  • DI 使用注解,不再需要在Spring配置文件中声明bean实例。Spring中使用注解,需要在原有的基础之上配置组件扫描器,用于指定在基本包中扫描注解。如下:
    在这里插入图片描述
4.1 指定多个包的三种方式
  • 1)使用多个 context:component-scan 指定多个不同的包路径

    1. <context:component-scan base-package="com.Etui.entity"></context:component-scan>
    2. <context:component-scan base-package="com.Etui.service"></context:component-scan>
  • 2)指定 base-package的值使用分隔符

    1. <!-- 分隔符可使用逗号、分号或空格 -->
    2. <context:component-scan base-package='com.Etui.entity, com.Etui.service'></context:component-scan>
  • 3)base-package指定到父包名

    1. <context:component-scan base-package="com.Etui"></context:component-scan>
4.2 常用注解
4.2.1 创建对象的注解
  • @Component:创建所有对象,都可以使用此注解,除了控制器,业务逻辑层、数据访问层的对象。
  • @Controller:创建控制器层的对象,此对象可以接收用户请求,返回处理结果。
  • @Service:创建业务逻辑层的对象,此对象可实施事务控制,向上给控制器返回数据,向下调用数据访问层。
  • @Repository:创建数据访问层的对象,对数据库中的数据进行增删改查。
4.2.2 给对象赋值的注解
  • @Value:给简单类型赋值。
  • @Autowired:给引用类型按类型注入。
  • Qualifier:给引用类型按名称注入。
4.2.3 应用案例
  • 目录结构:
    在这里插入图片描述
  • 实体类如下:

    1. // School类
    2. @Component("schoolParent")
    3. public class School {
    4. @Value("合肥大学")
    5. private String name;
    6. @Value("合肥市蜀山区")
    7. private String address;
    8. public School() {
    9. System.out.println("School类的构造函数………………");
    10. }
    11. @Override
    12. public String toString() {
    13. return "School{" +
    14. "name='" + name + '\'' +
    15. ", address='" + address + '\'' +
    16. '}';
    17. }
    18. }
  1. // Student类
  2. @Component
  3. public class Student {
  4. @Value("砂糖")
  5. private String name;
  6. @Value("18")
  7. private Integer age;
  8. // 引用类型按类型注入
  9. // @Autowired
  10. // private School school;
  11. // 引用类型按名称注入
  12. @Autowired
  13. @Qualifier("school")
  14. private School school;
  15. @Override
  16. public String toString() {
  17. return "Student{" +
  18. "name='" + name + '\'' +
  19. ", age=" + age +
  20. ", school=" + school +
  21. '}';
  22. }
  23. public Student() {
  24. }
  25. }
  26. // Student类的子类
  27. @Component("school")
  28. public class SubSchool extends School{
  29. @Value("合肥168中学")
  30. private String name;
  31. @Value("合肥市经开区")
  32. private String address;
  33. @Override
  34. public String toString() {
  35. return "SubSchool{" +
  36. "name='" + name + '\'' +
  37. ", address='" + address + '\'' +
  38. '}';
  39. }
  40. public SubSchool() {
  41. System.out.println("SubSchool的构造方法…………");
  42. }
  43. }
  • Spring配置文件(applicationContext.xml)

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    6. <context:component-scan base-package="com.Etui.entity03"></context:component-scan>
    7. </beans>
  • 测试代码
    \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qsjarrfP-1650805242650)(C:\\Users\\34162\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220424205031344.png)\]

Over!

发表评论

表情:
评论列表 (有 0 条评论,60人围观)

还没有评论,来说两句吧...

相关阅读