第六章: Spring框架 - 图1

1. 了解Spring

1.1 spring是什么?

  • Spring官网
  • 容器框架
  • Spring 是分层的javaee/javase应用,轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程)为内核

    1. 怎么使用spring

  • spring也是一个容器,里面存放java对象

  • 让容器完成对象的创建,对象之间关系的管理(属性赋值)
  • 我们在程序中从容器中获取要使用的对象

    2. 什么样的对象放到容器中

  • dao类,service类,controller类,工具类e

  • spring对象默认都是单例的(在容器中叫这个名称的对象就只有一个)

    3. 不放入到spring容器中的对象

  • 实体类对象,servlet、监听器、过滤器……

    4. Spring的优势

  • 方便解耦合,简化开发

  • AOP编程的支持
  • 声明式事务的支持
  • 方便程序的测试
  • 方便集成各种优秀的框架
  • 降低javaee api的使用难度
  • spring源码是经典的学习范例

    1.2 Spring Maven依赖

    1. <dependency>
    2. <groupId>org.springframework</groupId>
    3. <artifactId>spring-context</artifactId>
    4. <version>5.0.5.RELEASE</version>
    5. </dependency>

    spring核心技术
  • IOC AOP 这两个能实现模块之间,类之间的解耦合

    1.3 Spring对”依赖”的理解

  • 在spring中有一个词叫做依赖:

  • Class A 中使用了Class B的属性或者方法,叫做Class A 依赖 Class B

    1.4 耦合

  • 什么是耦合?

    • 简单的来说就是程序之间的依赖性
  • 都有什么耦合?
    • 类之间的依赖
    • 方法之间的依赖
  • 解耦合
    • 将低的程序间的依赖关系
  • 解耦的思路
    • 第一步:使用反射机制创建对象,而不是new关键字
    • 第二步:通过读取配置文件来获取要创建的对象的全限定类名

2. IOC控制反转

2.1 IOC是什么?

  • 英文:Inversion of control
  • 描述的是:把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是有其他的外部资源来完成的
  • 控制: 创建对象,对象属性赋值,对象之间的关系管理
  • 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现,由容器代替开发人员管理、创建、赋值
    • 正转:由开发人员在代码中使用new构造方法创建对象,开发人员主动管理对象
  • 控制反转:在这个容器里面,这个容器代替了开发人员创建对象,赋值,管理的工作
  • 容器:spring 管理所有的组件,主动的new 变成被动的 获取

    2.2 为什么使用IOC?

  • 对象的管理更加松散

  • 解耦合
  • 减少对代码的改动,也能实现不同的功能

    2.3 在之前的学习中IOC的体现

    servlet中体现出来了
    所有的对象不需要你去创建,直接在web.xml中配置一下tomcat自动就会帮你创建
    tomcat作为容器:里面它存放了 Listener对象,Filter对象,Servlet对象

    2.4 IOC的技术实现DI

  • DI是IOC的技术实现

  • DI翻译过来是 依赖注入
    • Dependency Injection
  • 我们只需要在程序中提供要使用的对象的名称就可以了,对象如何在容器中创建,赋值,查找都由容器内部实现。
  • spring是使用了DI实现了IOC的功能,spring底层创建对象使用的是反射。
  • spring是一个容器,管理对象,给属性赋值,底层是反射机制创建对象

3. Spring第一个程序

  1. 使用maven快速创建一个java项目
  2. 添加maven依赖

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5.RELEASE</version>
    </dependency>
    
  3. 创建类 (接口和他的实现类 随意创建)

  4. 创建spring需要的配置文件

image.png

大家公认的配置文件的名字为 application.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">
    <!--告诉spring创建对象
        声明bean,告诉spring要创建哪个类的对象
        id:对象的自定义名称,自己给对象起个名
        class:类的全限定名称(不能是接口)
    -->
        <!-- 一个Bean 声明一个对象 -->
    <bean id="test" class="com.yixuexi.service.impl.DoServiceImpl"></bean>
    <bean id="myDate" class="java.util.Date"></bean>
    <bean id="myString" class="java.lang.String"></bean>
</beans>
  1. 使用Spring容器

    创建ClassPathXmlApplicationContext 对象

@Test
    public void doSomeSpringTest(){
        //使用spring容器创建的对象
        //1.指定spring配置文件
        String config = "Test.xml";

        //2.创建表示spring容器的对象,ApplicationContext(是个接口)
        //ApplicationContext就是表示Spring的容器,通过容器能获取到对象
        //ClassPathXmlApplicationContext表示从类路径中加载配置文件
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //得到对象 通过之前在配置文件中写的id得到,通过key得到value
        //在进行强转一下,向下转型
        DoService do1 = (DoService)ac.getBean("test"); 
    }

3.1 spring 创建对象的时机

  • 通过测试,发现在spring读取配置文件之后会立马创建出配置文件中已经配置了的对象信息
  • 也就是说,在这行代码执行时 new ClassPathXmlApplicationContext(config); 所有以配置的对象都创建完毕
  • 默认创建对象的时间是 在创建spring容器时,会创建配置文件中所有的对象
  • spring创建对象默认调用的是对象的无参构造

    1. 获取容器中定义好的对象的数量 容器就是ApplicationContext

    int count = ac.getBeanDefinitionCount();
    

    2. 获取容器中每个定义的对象的名称 也就是id 【key是什么】

    ```java // 返回一个String数组 String[] names = ac.getBeanDefinitionNames(); // 遍历数组 for (String name : names) { System.out.println(name); }
<a name="dZiZW"></a>
### 3. 创建一个非自定义类的对象,也就是说创建一个 Date类 String 类….
```xml
<bean id="myDate" class="java.util.Date"></bean>
<bean id="myString" class="java.lang.String"></bean>

4. XML注入/${}

4.1. 在spring配置文件中给java对象赋值

DI:依赖注入(创建对象,并给属性赋值 注入就是赋值的意思)

1. DI的实现方式有两种

  1. 在spring的配置文件中,使用标签和属性完成,叫做基于xml的DI实现
  2. 使用spring中的注解,完成属性赋值,叫做基于注解的DI实现

    2. DI的语法分类

  • set注入(设值注入) :spring调用类的set方法,在set方法可以实现属性的赋值【很多人用 80%】
  • 构造注入:spring调用类的有参构造方法,创建对象,在构造中完成赋值

3. spring中对数据类型的定义

  • 简单数据类型:spring中规定了java中的基本数据类型和String都是简单类型(包装类也是简单类)
  • 引用数据类型:Object及子类

4.2 set注入

set注入 【xml方式】:通过set注入进行对里面属性的赋值(也叫设值注入)
简单数据类型的set注入(本质上是调用的是set方法)

<bean id="自己起一个id名" class="全限定类名">
  <properties name="属性名" value="此属性的值" />
  <properties name="属性名" value="此属性的值" />
</bean>

引用数据类型的set注入:

<bean id="school02" class="com.yixuexi.test02.School">
  <property name="name" value="北京市第一小学"></property>
  <property name="id" value="2222"></property>
</bean>
<bean id="student02" class="com.yixuexi.test02.Student">
  <property name="id" value="999"></property>
  <property name="name" value="张三"></property>
  <!-- value改ref 写school的id -->
  <property name="school" ref="school02"></property>
</bean>

把value换成ref,然后后面跟 对应类型对象的id(也就是bean的id)

1. set注入注意事项:

  • 类中必须要有set方法
  • 不管是什么值 在value=”都必须在引号内”
  • 比如student类中有一个 setAddress()方法,但是并没有这个address属性,那么在配置文件中这么写 他也会执行,并不会报错,spring找的就是类中的方法,他根据address判断出setAddress() 然后根据他的判断,他去找setAddress()这个方法,然后执行,不管有没有address属性。(只要有set方法 他就能用)

    4.3 构造注入

    spring调用类的有参数构造方法,在创建对象的同时,在构造方法中给属性赋值
    使用 标签 :一个constructor-arg标签表示构造方法中的一个参数

  • name:构造方法的形参名(切记 这是是形参名,一般的形参名都和属性名一致)

  • index:构造方法参数的位置,参数从左往右 , 0 1 2 3
  • value:简单类型的使用value
  • ref:构造方法中的形参类型是引用类型的 放引用数据类型的id名
    <!--通过构造方式注入来给对象属性赋值-->
    <bean id="student03" class="com.yixuexi.test03.Student">
    <constructor-arg name="id" value="10"></constructor-arg>
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg name="school" ref="school02"></constructor-arg>
    </bean>
    

    4.4 在配置文件中也支持${}写法

  1. 在类路径下添加一个properties的配置文件
  2. 然后在里面写好值 key=value
  3. 然后在xml文件中写
  1. 然后在对象value的地方进行 ${}

未命名图片.png

5. 自动注入

5.1 引用类型的自动注入

  • 引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值
  • 只针对引用类型的赋值,简单类型做不了

    1. byName

  • byName: (按名称注入) java类中引用类型的属性名和spring容器中(配置文件中)的id一样

  • 并且数据类型是一致的,这样的容器中的bean spring能够赋值给引用类型 ```xml
> 设置 autowire="byName"
> 并且 在student这个类中的school属性名 和 上面这个school bean的id一致 才行


<a name="txDAu"></a>
### 2. byType
byType:(按类型注入,了解即可) java类中引用类型的数据类型和spring容器中(配置文件中) <bean> 的class属性是同源关系的,这样的bean能够赋值给引用类型<br />**同源:**

1. java类中的引用类型的数据类型和bean的class值是一样的
1. java类中引用类型的数据类型和bean是class的值父子类关系的
1. java类中引用类型的数据类型和bean的class的值是接口或者实现类关系的

设置 autowire="byType"

- 注意:在byType中,在xml配置文件中声明bean 只能有一个符合条件的,多余一个是错误的
- 下图表示的是byType注入,其中两个类都在同一个包下,所以符合同源的第一条,所以可以自动注入成功

![未命名图片.png](https://cdn.nlark.com/yuque/0/2021/png/12374561/1616426501146-d0fcd736-e437-4773-a79e-6982043273b2.png#align=left&display=inline&height=395&margin=%5Bobject%20Object%5D&name=%E6%9C%AA%E5%91%BD%E5%90%8D%E5%9B%BE%E7%89%87.png&originHeight=395&originWidth=1185&size=306348&status=done&style=none&width=1185)

<a name="mrFvL"></a>
# 6. 使用使用多个配置文件的优势

1. 分担了一个文件的大小
1. 避免多人编写带来的冲突

- 多文件的分配方式
- 按功能模块分类,一个模块一个配置文件(学生成绩,学生选课)
- 按类的功能,数据库相关的配置一个配置文件,事务的功能一个配置文件
<a name="MNozT"></a>
## 6.1 包含关系的配置文件

- 有三个配置文件,分别是spring-student.xml ,spring-school.xml,
- 还有一个主配置文件spring-total.xml
- 主配置文件一般都不定义对象,而是用来包含其他配置文件
<a name="PTxUP"></a>
##### 语法:<br />
```xml
<import resource="其他配置文件的路径"/>
关键字 "classpath:"  表示类路径的(class文件所在的目录)
在spring中如果需要指定别的文件的话 需要classpath:
【idea中指的是 tagert目录下的路径】
<import resource="classpath:spring-student.xml"/>
<import resource="classpath:spring-school.xml"/>
  • 当在spring-total.xml文件中集成了这些文件之后,当读取这一个文件的时候这里面的被继承文件也都读取到了
  • 并且也可以支持引用类型的注入
  • Spring-student.xml里面需要一个school类型的属性而spring-school.xml里面有,这样的话,就算隔着一个文件也可以引用注入
  • Spring-total.xml叫包含关系的配置文件

    6.2 统配符方式

    这样的话 最终的包含配置文件不能叫spring-total.xml 改名为total.xml

  • 主配置文件不能包含在通配符的范围内

  • 最好是放在同一级目录中