Skip to content

Spring

黑马程序员SSM框架教程

IDEA配置Maven指南

IDEA 配置 Maven 图文教程 - 犬小哈教程

lihuibear4/smm

初识spring

image-20240220180154451

Spring Framework

Spring Framework系统架构

image-20240220181237897

学习路线

image-20240220181529178

核心容器

核心概念(IoC/DI)

当前遇到的问题

当前遇到的问题

  1. 业务层需要调用数据层的方法,就需要在业务层new数据层的对象
  2. 如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署
  3. 所以,现在代码在编写的过程中存在的问题是:耦合度偏高
image-20240220182308203
IoC(Inversion of Control)控制反转

控制反转

使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转

Spring技术对IOC思想进行了实现

Spring技术

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

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

DI(Dependency Injection)依赖注入

DI(Dependency Injection)依赖注入

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

image-20240220210557585
  • 业务层要用数据层的类对象,以前是自己new
  • 现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来
  • 这种思想就是依赖注入
目标:充分解耦

充分解耦

  • 使用IOC容器管理bean(IOC)
  • 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.
小结
小结
  1. 什么IOC/DI思想?

    • IOC:控制反转,控制反转的是对象的创建权
    • DI:依赖注入,绑定对象与对象之间的依赖关系
  2. 什么是IOC容器?

    • Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器
  3. 什么是Bean?

    • 容器中所存放的一个个对象就叫Bean或Bean对象
IoC入门案例

导入spring的坐标spring-context,对应版本5.2.10.RELEASE

配置bean

  1. bean标签标示配置bean
  2. id属性标示给bean起名字
  3. class属性表示给bean定义类型

获取IoC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

获取bean

BookService bookService = (BookService) ctx.getBean("bookService");bookService.save();

小结
IoC入门案例(XML版)

image-20240221145751715

image-20240221145810947

image-20240221145827951

image-20240221145850325

DI入门案例
  1. 删除业务层中使用new的方式创建的dao对象

  2. 提供对应的set方法

    java
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
  3. 配置server与dao的关系

    name="bookDao"中bookDao的作用是让Spring的IOC容器在获取到名称后,将首字母大写,前面加set找对应的setBookDao()方法进行对象注入 ref="bookDao"中bookDao的作用是让Spring能在IOC容器中找到id为bookDao的Bean对象给bookService进行注入

    xml
    <!--dao放到service里-->
        <bean id = "bookService" class = "com.itheima.service.impl.BookServiceImpl">
            <!--配置server与dao的关系-->
            <!--property标签表示配置当前bean的属性
            		name属性表示配置哪一个具体的属性
            		ref属性表示参照哪一个bean
    		-->
            <property name="bookDao" ref="bookDao1"/>
        </bean>
    小结
DI入门案例(XML版)

image-20240221164852435

image-20240221164857616

image-20240221165004588

IOC相关内容

bean配置
bean基础配置

image-20240221173237585

bean别名配置

image-20240221173156543

bean作用范围配置

image-20240221174007357

思考

  1. 为什么bean默认为单例?

    1. bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
    2. bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
  2. bean在容器中是单例的,会不会产生线程安全问题?

    1. 如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,

      因为所有请求线程共用一个bean对象,所以存在线程安全问题。

    2. 如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。

  3. 哪些bean对象适合交给容器进行管理?

    1. 表现层对象
    2. 业务层对象
    3. 数据层对象
    4. 工具对象
  4. 哪些bean对象不适合交给容器进行管理?

    1. 封装实例的域对象
bean实例化

Spring容器在创建对象的时候也走的是构造函数,Spring底层用的是反射,Spring底层使用的是类的无参构造方法。

构造方法(常用)

image-20240222150727481

静态工厂

image-20240222152708995

实例工厂

image-20240222154236930

使用FactoryBean实例化bean

image-20240222155401384

bean生命周期
  • 生命周期:从创建到消亡的完整过程
  • bean生命周期:bean从创建到销毁的整体过程bean
  • 生命周期控制:在bean创建后到销毁前做一些事情
java
public class AppForLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//        ctx.registerShutdownHook();//注册关闭钩子 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器 在任何时间都可以

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        ctx.close(); // 暴力关闭
    }
}

image-20240222172117372

或者

image-20240222172133041

bean在初始化过程中的阶段

bean在初始化过程中的阶段

  • 初始化容器
    • 1.创建对象(内存分配)
    • 2.执行构造方法
    • 3.执行属性注入(set操作)
    • 4.执行bean初始化方法
  • 使用bean
    • 1.执行业务操作
  • 关闭/销毁容器
    • 1.执行bean销毁方法
bean销毁时机

image-20240222172727154

DI相关内容

依赖注入
setter注入

image-20240223120413072

image-20240223120546007

构造器注入

image-20240223145543866

image-20240223145629638

选择

如何选择

介绍完两种参数的注入方式,具体我们该如何选择

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

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

方式
  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配

image-20240223165229075

特征
  • 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  • 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  • 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  • 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入
java
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="zhengzhou"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">zhengzhou</prop>
            </props>
        </property>
    </bean>
案例:数据源对象管理

image-20240223195434009

加载properties文件

image-20240223203016691

image-20240223203905483

容器

image-20240225173405338

image-20240225173414640

image-20240225174107654

image-20240225174140656

总结
容器相关
  1. BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
  2. ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
  3. ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
  4. ApplicationContext接口常用初始化类
    1. ClassPathXmlApplicationContext(常用)
    2. FileSystemXmlApplicationContext
bean相关

image-20240225181941234

依赖注入相关

image-20240225182320181

注解开发

注解开发定义bean

image-20240228083454138

image-20240228084909901

image-20240228085009241

注解开发bean管理

bean作用范围

image-20240228201631487

bean生命周期

image-20240228201647131

依赖注入

image-20240228212515790

image-20240228212539173

image-20240228212813456

读取properties文件

image-20240228213705461

第三方bean管理

第三方bean管理

image-20240228220236568

image-20240228220258622

image-20240228220311999

image-20240228220330537

第三方bean依赖注入

image-20240229090538329

image-20240229090554720

总结

注解开发总结

image-20240229090736113

整合

spring整合Mybatis

image-20240229095351704

image-20240229095745937

image-20240301084011944

image-20240301084048876

Sprirng整合Junit

image-20240301090228162

AOP

简介

  • AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。
    • OOP(Object Oriented Programming)面向对象编程

我们都知道OOP是一种编程思想,那么AOP也是一种编程思想,编程思想主要的内容就是指导程序员该如何编写程序,所以它们两个是不同的编程范式

AOP作用

  • 作用:在不惊动原始设计的基础上为其进行功能增强,前面有技术就可以实现这样的功能即代理模式。

前面有技术就可以实现这样的功能即代理模式

AOP核心概念

image-20240301092032071

image-20240301092128146

入门案例

image-20240301113504880

image-20240301113529870

image-20240301113555476

image-20240301113614928

image-20240301113636543

image-20240301113705373

AOP工作流程

流程1:Spring容器启动
  • 容器启动就需要去加载bean,哪些类需要被加载呢?
  • 需要被增强的类,如:BookServiceImpl
  • 通知类,如:MyAdvice
  • 注意此时bean对象还没有创建成功
流程2:读取所有切面配置中的切入点

image-20240301120405332

  • 上面这个例子中有两个切入点的配置,但是第一个ptx()并没有被使用,所以不会被读取。
流程3:初始化bean,

判定bean对应的类中的方法是否匹配到任意切入点

  • 注意第1步在容器启动的时候,bean对象还没有被创建成功。

  • 要被实例化bean对象的类中的方法和切入点进行匹配

    image-20240301120421472

    • 匹配失败,创建原始对象,如UserDao
      • 匹配失败说明不需要增强,直接调用原始对象的方法即可。
    • 匹配成功,创建原始对象(==目标对象==)的==代理==对象,如:BookDao
      • 匹配成功说明需要对其进行增强
      • 对哪个类做增强,这个类对应的对象就叫做目标对象
      • 因为要对目标对象进行功能增强,而采用的技术是动态代理,所以会为其创建一个代理对象
      • 最终运行的是代理对象的方法,在该方法中会对原始方法进行功能增强
流程4:获取bean执行方法
  • 获取的bean是原始对象时,调用方法并执行,完成操作
  • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

AOP切入点表达式

image-20240303174030905

image-20240303174934170

image-20240303175159465

通知类型

前置通知

image-20240303195535368

后置通知

image-20240303195553088

环绕通知(重点)

image-20240303195618307

image-20240303195833987

返回后通知(了解 )

image-20240303195853073

抛 出异常后通知(了解)

image-20240303195921359

AOP通知获取数据

获取参数

image-20240303204632404

获取返回值

image-20240303204711214

获取异常

image-20240303204724347

AOP总结

AOP的核心概念
  • 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
  • 作用:在不惊动原始设计的基础上为方法进行功能==增强==
  • 核心概念
    • 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
    • 连接点(JoinPoint):在SpringAOP中,理解为任意方法的执行
    • 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
    • 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
    • 切面(Aspect):描述通知与切入点的对应关系
    • 目标对象(Target):被代理的原始对象成为目标对象
切入点表达式
  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)

    execution(* com.itheima.service.*Service.*(..))
  • 切入点表达式描述通配符:

    • 作用:用于快速描述,范围描述
    • *:匹配任意符号(常用)
    • .. :匹配多个连续的任意符号(常用)
    • +:匹配子类类型
  • 切入点表达式书写技巧

    1.按==标准规范==开发 2.查询操作的返回值建议使用*匹配 3.减少使用..的形式描述包 4.==对接口进行描述==,使用*表示模块名,例如UserService的匹配描述为*Service 5.方法名书写保留动词,例如get,使用*表示名词,例如getById匹配描述为getBy* 6.参数根据实际情况灵活调整

五种通知类型
  • 前置通知
  • 后置通知
  • 环绕通知(重点)
    • 环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
    • 环绕通知可以隔离原始方法的调用执行
    • 环绕通知返回值设置为Object类型
    • 环绕通知中可以对原始方法调用过程中出现的异常进行处理
  • 返回后通知
  • 抛出异常后通知
通知中获取参数
  • 获取切入点方法的参数,所有的通知类型都可以获取参数
    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    • ProceedingJoinPoint:适用于环绕通知
  • 获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究
    • 返回后通知
    • 环绕通知
  • 获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究
    • 抛出异常后通知
    • 环绕通知

事务

简介

  • 事务作用:在数据层保障一系列的数据库操作同成功同失败

  • Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败

  • 举个简单的例子,

    • 转账业务会有两次数据层的调用,一次是加钱一次是减钱
    • 把事务放在数据层,加钱和减钱就有两个事务
    • 没办法保证加钱和减钱同时成功或者同时失败
    • 这个时候就需要将事务放在业务层进行处理。

Spring为了管理事务,提供了一个平台事务管理器PlatformTransactionManager

image-20240303213713372

commit是用来提交事务,rollback是用来回滚事务。

PlatformTransactionManager只是一个接口,Spring还为其提供了一个具体的实现:

转账案例-需求分析

需求: 实现任意两个账户间转账操作

需求微缩: A账户减钱,B账户加钱

为了实现上述的业务需求,我们可以按照下面步骤来实现下: ①:数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)

②:业务层提供转账操作(transfer),调用减钱与加钱的操作

③:提供2个账号和操作金额执行转账操作

④:基于Spring整合MyBatis环境搭建上述操作

转账案例-环境搭建

image-20240303215301841

image-20240303215315666

image-20240303215341174

事务角色

  • 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
  • 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

目前的事务管理是基于DataSourceTransactionManagerSqlSessionFactoryBean使用的是同一个数据源。

事务相关配置

image-20240304193154224

事务传播行为

image-20240304201320120

image-20240304201421003

Released under the MIT License.