Spring学习总结-01(基于黑马程序员视频及资料)

Spring学习总结-01

1. Spring优势

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

  • Spring框架的两大优势在于:简化开发框架整合

    • 简化开发:降低企业级开发的复杂性。Spring的简化开发是基于以下两大核心技术实现的

      Spring框架中两大核心技术:AOPIOC

      • AOP:面向切面编程
      • IOC:控制反转
    • 框架整合:整合其他技术,提高企业级应用的开发和运行效率。Spring可以整合市面上几乎所有主流框架

      Spring可以整合的框架:

      • MyBatis
      • Mybatis-Plus
      • Hibernate

2. Spring相关概念

2.1 Spring家族

  • Spring并不是单一的技术,而是一个大家族,一大套技术集。官网:https://spring.io

    • Spring可以用于开发web,微服务以及分布式系统等等
    • Spring已形成了完整的生态圈,我们完全可以使用Spring技术完成整个项目的构建、设计和开发
    • Spring有若干个项目,可以根据需要进行选择,下图是所有项目组合

    在这里插入图片描述

  • 目前学习了Spring Framework、SrpingBoot、SpringCloud

    • Spring Framework:Spring框架,是Spring其他所有技术的基础,一般简称Spring
    • SrpingBoot:Spring用来简化开发,SpringBoot在此基础上实现快速开发
    • SpringCloud:微服务架构,用来做分布式之微服务架构的相关开发

    在这里插入图片描述

2.2 Spring系统架构

  • Spring Framework是Spring生态圈的基础项目,是其他项目的根基

  • Spring Framework发展经历多次版本更新,以下是4版本的架构图

在这里插入图片描述

  • 核心层:

    • Core Container:核心容器

    • Spring框架最核心的部分,其他模块依赖它运行

    • 顾名思义,容器它是用来装东西的,装的是java对象

      因此可以说Spring是一个用来管对象的技术

  • AOP层:

    • AOP:面向切面编程。

      与面向对象编程一样是一种编程思想,换句话说它教你程序应该怎么做,是一个设计型的概念

    • 依赖于核心容器,目的是在不改变原有代码的基础下对其实现功能增强

    • Aspects:AOP思想的实现。

      以后实现AOP开发时,不仅要导AOP的坐标还要导Aspects的坐标

  • 数据层:

    • Data Access:数据访问

      Spring内部提供了自主访问数据层的技术

    • Data Integration:数据集成

      Spring支持整合其他技术实现对数据层的访问,比如Mybatis

    • Transactions:事务

      Spring在事务这个方面做了大的突破,提供了一种开发起来效率非常高的事务控制方案

  • Web层

  • Test层:

    • Spring整合了Junit来完成单元测试和集成测试

2.3 Spring核心概念

2.3.1 目前项目中的问题以及解决思想:
  • 代码书写现状:

    在这里插入图片描述

    1. 业务层需要调用数据层的方法,就需要在业务层创建数据层的对象

      new BookDaoImpl()

    2. 如果数据层的实现类发生变化,那么业务层也需要变化

      new BookDaoImpl() ——>new BookDaoImpl2()

    3. 因此项目需要重新编译、打包、部署

    4. 所以,当前代码编写过程存在问题:耦合度过高

  • 解决思想:

    在这里插入图片描述

    • 针对如上问题,我们把new对象的那行代码去掉,这样就能降低依赖,但显然程序将无法运行,因为bookDao没有赋值为null,强行运行会报空指针异常
  • 解决方法:

    • 目前问题在于业务层不想创建对象,而运行时又需要这个对象,该如何解决?

    • 根据此问题,Spring提出了一个解决方案:

      • 使用对象时,不再由程序主动new产生对象,而是由外部提供对象

        这种实现思想是Spring的一个核心概念,称为IOC(控制反转)

2.3.2 IOC、IOC容器、Bean、DI
  • IOC:控制反转

    使用对象时,不再由程序主动的创建对象,而是由外部提供对象。此过程中对象的创建权由程序转移到外部,这就是控制反转(IOC)的思想

  • IOC容器:Spring对IOC思想进行了实现,提供了一个容器

    Spring提供了一个容器,称为IOC容器,充当控制反转思想中的‘外部’

  • Bean

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

  • DI:依赖注入

    当IOC容器创建好service和dao对象后,程序还不能正常运行,因为两个对象虽然存在但没有任何关系。需要将dao对象交给service,也就是说要绑定service和dao对象之间的关系

    因此,在容器中建立Bean和Bean之间的依赖关系的过程,称为DI(依赖注入)

    在这里插入图片描述

2.3.3 目标与最终效果
  • 目标:充分解耦

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


3. 入门案例

3.1 IOC入门案例

3.1.1 入门案例思路分析
  • Spring是使用容器来管理bean对象的,那么管什么?
    • 主要管理项目中所使用到的类对象,比如(Service和Dao)
  • 如何将被管理的对象告知IOC容器?
    • 使用配置文件
  • 被管理的对象交给IOC容器,要想从容器中获取对象,就先得思考如何获取到IOC容器?
    • Spring框架提供相应的接口
  • IOC容器得到后,如何从容器中获取bean?
    • 调用Spring框架提供对应接口中的方法
  • 使用Spring导入哪些坐标?
    • 用别人的东西,就需要在pom.xml添加对应的依赖
3.1.2 入门案例代码实现
  • 创建maven工程

    在这里插入图片描述

  • 在pom.xml文件中添加Spring依赖坐标
    在这里插入图片描述

  • 添加案例所需的类
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

public interface BookDao {
    public void save();
}
public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("book dao save ...");
    }
}
public interface BookService {
    public void save();
}
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();
    @Override
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}
  • 创建Spring配置文件
    在这里插入图片描述

  • 在配置文件中配置bean

    • 使用bean标签配置bean

    id:给bean起名字
    class: bean类型

    在这里插入图片描述

  • 创建app类,在主函数里获取IOC容器

    通过创建ClassPathXmlApplicationContext()对象获取容器
    参数为配置文件名

    在这里插入图片描述

  • 获取IOC容器中的bean,即获取对象

    通过容器的getBean()方法获取对象
    参数为bean标签的id

    在这里插入图片描述

  • 运行
    在这里插入图片描述

  • 获取IOC容器的service bean,并执行
    在这里插入图片描述
    在这里插入图片描述

以上就是IOC入门案例的代码实现,显然BookServiceImpl类里存在BookDaoImpl对象的new操作,因此需要实现DI:依赖注入

3.2 DI入门案例

3.2.1 入门案例思路分析
  • 要想实现依赖注入,必须要基于IOC管理Bean
    • DI的入门案例要依赖于前面IOC的入门案例
  • Service中使用new形式创建的Dao对象是否保留?
    • 需要删除掉,最终要使用IOC容器中的bean对象
  • Service中需要的Dao对象如何进入到Service中?
    • 在Service中提供方法,让Spring的IOC容器可以通过该方法传入bean对象
  • Service与Dao间的关系如何描述?
    • 使用配置文件
3.2.2 入门案例代码实现
  • 删除service层使用new创建的dao对象
    在这里插入图片描述

  • 在service层提供dao的setter方法

    • 可以使用alt+insert快捷键生成
    • 该setter方法是给容器调用的

    在这里插入图片描述

  • 在配置文件完成注入

    • 因为要在service里注入dao对象,因此应该在service的bean标签中完成注入
    • 在bean标签中使用property标签实现注入
    • property标签中name为service实现类中定义的属性名,ref为需要注入的bean的id

    在这里插入图片描述

  • 运行
    在这里插入图片描述

以上结果可以看出DI注入成功,不需要在service层创建dao对象也可以使用dao对象并使用其方法

4. IOC相关内容

4.1 bean基础配置

4.1.1 bean的基础配置

在这里插入图片描述

4.1.2 bean的别名配置

在这里插入图片描述

4.1.3 bean的作用范围配置

在这里插入图片描述

  • 为什么bean默认为单例?
    bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
    bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
  • bean在容器中是单例的,会不会产生线程安全问题?
    如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,
    因为所有请求线程共用一个bean对象,所以会存在线程安全问题。
    如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,
    因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题
  • 哪些bean对象适合交给容器进行管理?
    表现层对象
    业务层对象
    数据层对象
    工具对象
  • 哪些bean对象不适合交给容器进行管理?
    封装实例的域对象,因为会引发线程安全问题,所以不适合

4.2 bean的实例化(bean如何被Spring创建出来的)

4.2.1 通过构造方法
  • 在BookServiceImpl类中加入无参构造函数,输出一句话 在这里插入图片描述
  • 运行主函数
    在这里插入图片描述 在这里插入图片描述
    通过输出结果可以看出,Spring创建bean默认是通过构造函数,并且是无参构造函数创建。如果将构造函数换位私有(private),仍然会输出这句话,Spring通过构造函数创建bean时使用暴力反射
4.2.2 通过静态工厂
  • 创建静态工厂类,实现静态方法获取dao对象
    在这里插入图片描述

  • 在配置文件中进行配置

    class:写的是静态工厂全类名。如果只写class,Spring创建的是静态工厂对象
    factory-method:写的是静态工厂创建dao对象的静态方法

    在这里插入图片描述

  • 运行
    在这里插入图片描述
    在这里插入图片描述

4.2.3 通过实例工厂
  • 创建实例工厂类,实现创建dao对象的方法
    在这里插入图片描述

  • 在配置文件中进行配置

    • 需要先创建实例工厂的对象,因此先配置实例工厂bean
    • 需要通过实例工厂的get方法创建dao对象,因此配置创建dao对象的bean
      factory-bean:实例工厂bean的id
      factory-method:实例工厂中创建dao对象的方法

    在这里插入图片描述

  • 运行
    在这里插入图片描述
    在这里插入图片描述

4.2.4 通过FactoryBean
  • 该方式是基于实例工厂实现的,需要掌握

  • 创建工厂类

    • 实现FactoryBean接口,并指定要创建的对象类型
    • 实现接口中的三个方法,isSingleton()可以不写,默认单例
      getObject()返回创建的对象
      getObjectType()返回所创建类的class对象

    在这里插入图片描述

4.3 bean的生命周期

为BookDao添加生命周期的控制方法,具体的控制有两个阶段:

  • bean创建之后,想要添加内容,比如用来初始化需要用到资源
  • bean销毁之前,想要添加内容,比如用来释放用到的资源
4.3.1 方式一:通过配置文件
  • 在BookDao实现类中添加init方法和destory方法
    在这里插入图片描述

  • 修改配置文件,在bean标签内添加init-method和destory-method

    在这里插入图片描述

  • 运行结果
    在这里插入图片描述

4.3.2 方式二:实现接口
  • 在BookDaoImpl类中实现InitializingBean和DisposableBean接口
    在这里插入图片描述
  • 实现接口中的destroy和afterPropertiesSet方法
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

从结果中可以看出,init方法执行了,但是destroy方法却未执行,这是为什么呢?

  • Spring的IOC容器是运行在JVM中
  • 运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行
  • main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了
  • 所以没有调用对应的destroy方法
  • 以下两种方式关闭容器,让bean销毁并执行方法
4.3.3 close关闭容器
  • ApplicationContext中没有close方法,需要将ApplicationContext更换成ClassPathXmlApplicationContext
  • 调用容器对象的close()方法
  • 该方法相对暴力
4.3.4 注册钩子关闭容器
  • 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器
  • 调用容器对象的registerShutdownHook()方法
    注意:registerShutdownHook在ApplicationContext中也没有

相同点:这两种都能用来关闭容器
不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭

4.3.5 小结
  • 关于Spring中对bean生命周期控制提供了两种方式:
    • 在配置文件中的bean标签中添加init-methoddestroy-method属性
    • 类实现InitializingBeanDisposableBean接口,这种方式了解下即可。
  • 对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
    • 初始化容器
      • 1.创建对象(内存分配)
      • 2.执行构造方法
      • 3.执行属性注入(set操作)
      • 4.执行bean初始化方法
    • 使用bean
      • 1.执行业务操作
    • 关闭/销毁容器
      • 1.执行bean销毁方法
  • 关闭容器的两种方式:
    • ConfigurableApplicationContext是ApplicationContext的子类
      • close()方法
      • registerShutdownHook()方法

5. DI相关内容

两种注入方式

  • setter注入
    • 注入简单数据类型
    • 注入引用数据类型
  • 构造器注入
    • 注入简单数据类型
    • 注入引用数据类型

5.1 setter注入

5.1.1 注入引用数据类型
  • 上文DI案例中便是setter注入引用类型的案例
  • 回顾:
    • 在BookServiceImpl中声明BookDao属性,并提供其set方法
      在这里插入图片描述

    • 在配置文件bean标签内添加property标签:

      • property标签中name为定义的属性名,ref为该引用类型bean的id

        在这里插入图片描述

5.1.2 注入简单数据类型
  • 在BookDaoImpl类中声明对应的简单数据类型的属性,并提供其set方法
    在这里插入图片描述

  • 在配置文件bean标签内添加property标签:

    • value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换
      在这里插入图片描述

5.2 构造器注入

5.2.1 注入引用数据类型
  • 在BookServiceImpl中声明BookDao属性,并提供有参构造方法,参数为BookDao类型
    在这里插入图片描述
  • 在配置文件bean标签内添加constructor-arg标签:
    • constructor-arg标签中name为构造方法的参数名,ref为该引用类型bean的id
      在这里插入图片描述
5.2.2 注入简单数据类型
  • 在BookDaoImpl类中声明对应的简单数据类型的属性,并提供有参构造方法
    在这里插入图片描述
  • 在配置文件bean标签内添加constructor-arg标签
    在这里插入图片描述

构造器注入方式耦合度高,因为构造方法的参数名需要与配置文件中constructor-arg标签中的name一致

在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,以了解为主。

  • 方式一:将name属性替换为type属性,即参数类型
    在这里插入图片描述
    弊端:如果参数存在两个或多个一样的类型这种方式就不太好实现
  • 方式二:将name属性替换为index属性,即参数索引
    在这里插入图片描述
    弊端:如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题

5.3 选择

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

5.4 自动装配

IOC容器根据bean所依赖的资源在容器自动查找并注入到bean中的过程称为自动装配

方式有:

  • 按类型
  • 按名称
  • 按构造方法
  • 不启动自动装配
5.4.1 按类型自动装配
  • 给需要注入的类提供setter方法
    在这里插入图片描述

  • 修改配置文件

    • 删除setter注入的property标签
    • 在bean中加入autowire属性,并选择byType值

    在这里插入图片描述

    注:

    • 使用按类型自动装配时,被注入的引用类型的bean必须唯一,即只能有一个该引用类型的bean
5.4.2 按名称自动装配
  • 给需要注入的类提供setter方法
    在这里插入图片描述

  • 修改配置文件

    • 删除setter注入的property标签
    • 在bean中加入autowire属性,并选择byName值

    在这里插入图片描述

    注:

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

5.5 集合注入

  • 准备工作
    在这里插入图片描述
5.5.1 注入数组类型数据

在bean标签中使用property标签

<property name="array">
    <array>
        <value>100</value>
        <value>200</value>
        <value>300</value>
    </array>
</property>
5.5.2 注入List类型数据

在bean标签中使用property标签

<property name="list">
    <list>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>chuanzhihui</value>
    </list>
</property>
5.5.3 注入Set类型数据

在bean标签中使用property标签

<property name="set">
    <set>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>boxuegu</value>
    </set>
</property>
5.5.4 注入Map类型数据

在bean标签中使用property标签

<property name="map">
    <map>
        <entry key="country" value="china"/>
        <entry key="province" value="henan"/>
        <entry key="city" value="kaifeng"/>
    </map>
</property>
5.5.5 注入Properties类型数据

在bean标签中使用property标签

<property name="properties">
    <props>
        <prop key="country">china</prop>
        <prop key="province">henan</prop>
        <prop key="city">kaifeng</prop>
    </props>
</property>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值