Spring学习笔记

Spring框架

Spring Framework 系统架构

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

架构图

上层依赖于下层

image-20230531163900979

核心容器

IoC/DI

image-20230531165917208

IoC ( Inversion of Control )控制反转:

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

IoC容器和Bean

image-20230601090721825

管理对象创建和初始化等工作,被创建或被管理的对象在IoC容器中统称为Bean

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

目标:充分解耦

  • 使用IoC容器管理bean (IoC)
  • 在IoC容器内将有依赖关系的bean进行关系绑定 (DI)

最终效果
使用对象时不仅可以直接从IoC容器中获取, 并且获取到的bean已经绑定 了所有的依赖关系

image-20230601091112864

IoC入门案例

实例步骤:

  1. 导入spring依赖image-20230601091337593
  2. 创建xml文件作为IoC容器 image-20230601091718710
    1. 导入spring的坐标
    2. 配置bean
  3. 写测试主函数 image-20230601092147481
    1. 获取IoC容器
    2. 获取bean
DI入门案例
  1. 删除业务层service中使用new创建的dao对象
  2. 提供得以让Dao对象进入Service的set方法image-20230601111403361
  3. 配置service与dao的关系(先判断是谁依赖谁)
  4. property标签表示配置当前bean的属性
    • name属性表示配置哪一个具体的属性
    • ref属性表示参照哪一个bean image-20230601111606406
bean基础配置

image-20230601113541235

image-20230602103739125

bean的别名

写在IoC容器的xml中image-20230601113732206名称和别名在spring系统中都等价

image-20230601113948032这个报错说明别名配置错误

bean的作用范围

spring默认创建的bean对象是单例的,因为bean一般是可复用的,
表现层对象、业务层对象、数据层对象、工具对象都很适合交给容器管理

可手动配置为多例scope="prototype"image-20230601114242459
不适合交给容器进行管理的bean:封装实体的域对象(有状态的对象,会记录成员变量的属性值)

bean的实例化
三种方式

bean本质上就是对象,创建bean使用无参构造方法完成

阅读spring的报错信息:从后往前看,信息逐步叠加

  • 使用无参构造方法(无参构造方法如果不存在,将抛出异常BeanCreat ionException)image-20230601114940679
  • 用静态工厂(兼容早期系统):(工厂模式通过封装对象的实例化过程,将对象的创建与使用分离,提供了一种灵活、可扩展的方式来创建对象;静态工厂:使用一个静态方法来创建和返回对象的实例,而不是直接调用构造函数。) image-20230601120146471image-20230601120209837
  • 实例工厂:先造factory再造beanimage-20230601140505291image-20230601140536477
  • FactoryBean(对实例工厂的改造)image-20230601141054782image-20230601141415611image-20230601141331605
    • 改造成非单例方法image-20230601141555900
bean的生命周期

生命周期:从创建到消亡的完整过程
bean生命周期: bean从创建到销毁的整体过程
bean生命周期控制:在bean创建后到销毁前做- -些事情

阶段
  • 初始化容器
    1. 创建对象 (内存分配)
    2. 执行构造方法
    3. 执行属性注入( set操作)
    4. 执行bean初始化方法
  • 使用bean
    执行业务操作
  • 关闭/销毁容器
    执行bean销毁方法
    • 手工关闭容器
      ConfigurableApplicat ionContext接口close( )操作
    • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
      ConfigurableApplicationContext接口registerShutdownHook( )操作
手动配置

步骤:

  • 定义并使用init()方法
    1. 在xml文件中指定init方法名image-20230601143140378
    2. 在想要控制的对象(如dao)的实现类中定义init()函数image-20230601143049099
    3. 使用:随bean的创造和销毁自动执行image-20230601143349053
  • 定义并使用destroy()方法
    1. 配置:在xml文件中指定destroy方法名image-20230601143134770
    2. 在想要控制的对象(如dao)的实现类中定义destroy()函数image-20230601143050976
    3. 使用:
      1.
      • 方法一:在测试函数中最后面加一个关闭方法,需要修改ctx的创建image-20230601143528975
      • 方法二:加一个关闭钩子image-20230601143802422
      1. 随bean的创造和销毁自动执行image-20230601143349053
Spring接口控制
  1. 在想要控制的对象(如service)的实现类中让类实现这两个接口image-20230601144249392
  2. 按alt+enter生成快捷键覆盖这两个方法
    image-20230601144333070

依赖注入

image-20230602103810984

方式
setter注入
  • 简单类型
    1. 在dao的实现类中定义简单类型,写set方法image-20230601154505448
    2. 在xml文件中用property的value属性配置image-20230601154257900
  • 引用类型:上面就是image-20230601152814854name标签里是实现类中定义的变量的名字

解耦后的改进方法:按类型自动装配,或者指定位置解决image-20230601162140747

构造器注入
  • 简单类型:同下

  • 引用类型
    实现类:image-20230601161216270

    配置image-20230601161740324name标签是实现类中构造方法形参的名字

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

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

自动装配方式

  • 按类型(常用)image-20230601154800712
  • 按名称image-20230601155151207image-20230601155211648这两处名字做匹配
  • 按构造方法
  • 不启用自动装配

依赖自动装配特征

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

数组
List
Set
Map
Properties

  1. 在dao的实现类定义集合和get方法和操作
  2. 注入集合对象:注意格式image-20230601160523219image-20230601160621273后面以此类推

案例:数据源对象管理

  1. 添加外部文件image-20230601163116418
  2. 管理DruidDataSource对象(bean)
    1. 先查看外部class里面有什么方法(快捷键ctrl+f12),有构造还是set
    2. 写连接池配置image-20230601164056788
  3. 添加另一个项目坐标:c3p8image-20230601164343615
    1. 找出连接池对象
    2. 写配置image-20230601165152155
  4. 添加jdbc坐标image-20230602084604619

加载properties

spring加载外部properties文件

  1. 开一个空间contextimage-20230602090822926
  2. 使用context空间加载properties文件image-20230602090935776
  3. 使用properties中的属性:把properties中的属性作为占位符写进xml的bean中image-20230602091109306image-20230602091138761
  • 防止自己写的属性与系统属性重名导致被覆盖image-20230602091548658
  • 加载多个properties文件image-20230602091630157或者image-20230602091700876或者.properties前面加上classpath:*
  • 加载类路径或jar包中的properties的文件image-20230602091838230

容器

创建容器
加载类路径下的配置文件

image-20230602095103756

从文件系统下加载配置文件

image-20230602095204808

获取bean

按名称找,然后强制转换BookDao bookDao = ( BookDao) ctx. getBean( "bookDao");

按名称找,指定类型BookDao bookDao = ctx. getBean( s: "bookDao", BookDao. class);

按类型找BookDao bookDao = ctx. getBean( BookDao. class);|

容器类层次结构

image-20230602103017377

BeanFactory

image-20230602103049157

注解开发

image-20230602151039257

  1. image-20230602104110593在对应的类里面加这一句替代上面的bean配置语句image-20230602104222587
  2. 在核心配置文件中通过组件扫描加载bean(指定搜索路径)image-20230602104509560
衍生注解
  • @Controller :用于表现层bean定义
  • @Service : 用于业务层bean定义
  • @Repository :用于数据层bean定义
纯注解开发

image-20230602110434741

  1. 用一个SpringConfig.java类代替applicationContext.xml配置文件
  2. 在该类头加一个@Configuration
  3. 在该配置类中加一个扫描组件@CompomentScan,后面写上扫描路径

使用:

  1. 加载配置类ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig . class);
  2. 后面跟之前一样image-20230602110406880
bean管理
作用范围

使用非单例对象
使用 @Scope("prototype")定义bean作用范围

生命周期
  1. 写初始化和销毁方法并指定image-20230602111041006
  2. 销毁方法还需关闭钩子或者关闭容器image-20230602111151488
依赖注入-自动装配

加一个@Autowired(按类型装配),set方法可以省略image-20230602112056042

加载多个类型

有多个相同类型的bean,用@Qualifier(“”)指定名称,该注解依赖Autowiredimage-20230602112436182

简单类型注入

用@Value可以实现简单类型注入image-20230602115023742

引用类型注入

image-20230605093521396

直接在形参上加(set方法可以省略Autowired)image-20230605092548464

加载外部文件
  1. 在配置类中加载属性@PropertySourceimage-20230602115547748
  2. 使用:用${}image-20230602115632704

路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*

管理第三方Bean

手工编程: jdbc一般要自己单独写一个配置类jdbcConfig.java

  1. 定义一个方法,获得要管理的对象
  2. 把方法的返回值定义成一个beanimage-20230602145101767
  3. 在主配置类中导入jdbcConfig.javaimage-20230602145046915

主函数:image-20230602144808831

为第三方bean注入资源
  • 简单类型:使用@Value引入的成员变量来加载image-20230602145731706
  • 引用类型(按类型自动装配)
    1. 让SpringConfig.java扫描到dao的实现类
    2. 在目标类(如jdbc)中把dao作为参数写进去image-20230602150526984

整合

Spring整合Mybatis/Druid

MyBatis程序核心对象分析

// 1.创建SqLSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2.加载SqLMapConfig. xmL配置文件,将其作为输入流读取
InputStream inputStream = Resources . getResourceAsStream("SqlMapConfig.xml");
// 3.创建SqLSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build( inputStream);
// 4.获取SqlSession
SqlSession sqlSession = sqlSessionFactory . openSession();
// 5.执行sqlSession对象执行查询, 获取结果User
AccountDao accountDao = sqlSession. getMapper(AccountDao.class);
Account ac = accountDao . findById(2);
System.out . print1n(ac);
// 6.释放资源
sqlSession.close();

三四步解释:SqlSessionFactory相对耗时,且是一个线程安全的对象(当多个线程同时访问一个对象时,线程安全的对象能够保证其内部状态的一致性和正确性,而不会导致意外的错误或数据损坏。), 应该在应用程序的生命周期内只创建一次。SqlSessionFactory 对象可以重复使用。通常情况下,每个数据库操作都需要创建一个新的 SqlSession 对象,并在完成操作后关闭它,以释放相关资源。

MyBatis配置文件:

<configuration>
    <!-- 初始化属性数据-->
    <properties resource= "jdbc. properties"></ properties>
    <!-- 初始化类型别名-->
    <typeAliases>
        <package name="com.itheima.domain"/>
    </typeAliases>
<!--    初始化dataSource-->
    <environments>
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <datasource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </datasource>
        </environment>
    </environments>
    <!--    初始化mapper-->
    <mappers>
        <mapper resource="com/itheima/dao"/>
    </mappers>
</configuration>

Mybatis管理的是SqlSessionFactory对象

  1. pom文件配置
    导入spring-context(实现IoC和Bean管理);连接池druid(管理数据库连接);mybatis和mysql的包;jdbc的包(spring操作数据库用的包);mybatis-spring(spring整合mybatis的包)

  2. 创建SpringConfig.java文件并写好配置image-20230605091601998

  3. 创建JdbcConfig.java并写好配置image-20230602163907692

  4. 配置sqlsession对应的bean

    1. 创建MyBatisConfig.java让它返回sqlsession对象image-20230602164646606

    2. 设置ssfb对象,逐一分解xml文件,把有用的用set设置,设置datasource时要注入引用类型,直接加在形参上image-20230602165023200image-20230605092120970

      设置mapperimage-20230602165803873

主函数调用image-20230602170447317

Spring整合JUnit

  1. pom中导入junit坐标和spring-junitimage-20230605095836915
  2. 创建测试类 image-20230605100344680
    1. 设定JUnit测试器并加载上下文
    2. Autowired自动装配注入要测试的Bean

AOP

概念

  • AOP(Aspect Oriented Programming) 面向切面编程,一种编程范式 ,指导开发者如何组织程序结构
    00P(0bject Oriented Progr amming )面向对象编程
  • 作用:在不惊动原始设计的基础上为其进行功能增强(无侵入式编程)

image-20230605102301774

  • 连接点:是在程序执行过程中可以被拦截的特定点。它代表着应用程序中的一个具体位置,例如方法执行的开始、结束或异常抛出的地方。连接点是AOP中的基本单位,它可以被AOP框架识别并与切面进行绑定。

  • 切入点:是用于定义一组连接点的表达式。它是在连接点中进行筛选和匹配的规则。切入点可以基于连接点的类型、方法名、参数类型等来定义,用于确定哪些连接点将被拦截和应用切面的逻辑。

    在SpringAOP中, -一个切入点可以只描述一个具体方法,也可以匹配多个方法

    • 一个具体方法: com. itheima . dao包下的BookDao接口中的无形参无返回值的save方法
    • 匹配多个方法:所有的save方法, 所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知:是在特定的连接点(Join Point)上执行的代码

  • 切面:描述通知与切入点的对应关系

入门案例

案例设定: 测定接口执行效率
简化设定:在接口执行前输出当前系统时间
开发模式: XML or注解

  1. 导入坐标( pom. xml )
    • aop的包包含在context中
    • 导入aspect包image-20230605104322248
  2. 标记程序应用注解开发aopimage-20230605105209100
  3. 制作连接点方法(原始操作,Dao接口与实现类)image-20230605104432859
  4. 制作共性功能(通知类与通知)image-20230605104628005
    1. 创建通知类
    2. 抽取出共性功能
    3. 标记为受Spring容器管理的组件:@Component
      标记为aop:@Aspect(加在最前面)
  5. 定义切入点image-20230605104756827
  6. 绑定切入点与通知关系,, 并指定通知添加到原始连接点的具体执行位置image-20230605104823050

工作流程

  1. Spring容器启动
  2. 读取所有切面配置中的切入点image-20230605110050888
  3. 初始化bean ,判定bean对应的类中的方法是否匹配到任意切入点
    • 匹配失败,创建对象(Bean)
    • 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取bean执行方法
    • 获取bean ,调用方法并执行,完成操作
    • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
      • 目标对象( Target ) : 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
      • 代理( Proxy ) :目标对象无法直接完成工作,需要对其进行功能回填, 通过原始对象的代理对象实现

切入点表达式

语法格式
  • 切入点:要进行增强的方法
  • 切入点表达式:要进行增强的方法的描述方式
    • 描述方式:
      • 描述方式一: 执行com. itheima . dao包下的BookDao接口中的无参数update方法
        execution(void com. itheima . dao. BookDao. update())
      • 描述方式二:执行com. itheima. dao . imp1包下的BookDaoImp1中的无参数update方法
        execution(void com. itheima . dao. impl . BookDaoImpl.update())
    • 标准格式:动作关键字(访问修饰符返回值包名.类/接口名.方法名(参数)异常名)
      execution (public User com.itheima.service.UserService.findById (int))
通配符

通配符:可以使用通配符描述切入点,快速描述
*不可为空

  • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
    execution (public * com.itheima.*.UserService.find* (*) )
    匹配com. itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
  • … : 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
    execution (public User com..UserService.findById (..) )
    匹配com包下的任意包中的UserService类或接口中所有名称为 findByld的方法
  • +:专用于匹配子类类型
    execution $(* * \ldots *$ Service+.* (...))
书写技巧

原则:精准、高效

  • 所有代码按照标准规范开发 ,否则以下技巧全部失效
  • 描述切入点通常描述接口,而不描述实现类
  • 访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
  • 返回值类型对于增删改类使用精准类型加速匹配 ,对于查询类使用通配快速描述
  • 包名书写尽量不使用. .匹配,效率过低,常用*做单个包描述匹配,或精准匹配
  • 接口名/类名书写名称与模块相关的采用*匹配 ,例如UserService书写成*Service , 绑定业务层接口名
  • 方法名书写以动词进行精准匹配,名词采用*匹配,例如getByld书写成getBy*,selectAll书写成selectAll
  • 参数规则较为复杂 ,根据业务方法灵活调整
  • 通常不使用异常作为匹配规则

通知类型

AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同, 最终运行代码时要将其加入到合理的位置
AOP通知共分为5种类型

前置通知&后置通知

image-20230605144435449

环绕通知(重点)

image-20230605144607351

如果原方法有返回值,通知类的返回值应为Object,同时接收这个返回值后,在方法最后面return这个返回值image-20230605145429391

推荐抛出异常

返回后通知(了解)

在后置通知之后运行
只有在没有抛出异常正常结束时才能运行

image-20230605145738465

抛出异常后通知(了解)

(@AfterThrowing)

image-20230605145757978

AOP通知获取数据

获取参数

所有通知类型都能获取

在参数列表中加JoinPoint对象拿

image-20230605150520823

可以对传进来的参数进行处理,仅对一个aop操作就行

image-20230605150733744

获取返回值

只有返回后通知和环绕通知能获取返回值

  • 环绕通知:和前面一样
    image-20230605150959297
  • 返回后通知:
    1. 定义一个用来接收返回值的形参
    2. JoinPoint和String这两个形参的顺序不能变
      image-20230605151737249
获取异常

只有抛出异常后通知和环绕通知能获取异常

  • 环绕通知使用try catch模块替代thowingimage-20230605152047197
  • 抛出异常后通知
    1. 定义一个形参接收异常对象image-20230605152407693
    2. 在原始操作中抛出异常image-20230605152736751

事务

概念

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

  • 接口image-20230605154537982
  • 实现类image-20230605154550517
入门案例-银行转账

步骤:

  1. 在业务层接口上添加Spring事务管理image-20230605155031078

    Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中, 降低耦合
    注解式事务可以添加到业务方法上表示当前方法开启事务, 也可以添加到接口上表示当前接口所有方法开启事务

  2. 在jdbcconfig中定义事务管理器

    image-20230605160833057

  3. 在springconfig中启用注解式事务驱动image-20230605160919185

Spring事务角色

通过相同的数据源,将多个事务管理为一个事务

image-20230605162000992

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

Spring事务属性

事务配置

image-20230605162347028

image-20230605162426129

程序中遇见如下两种异常则回滚,否则不回滚

  • error型异常:如溢出
  • 运行时异常

IOException就不会回滚,可以设置image-20230605162849117

事务传播行为

案例:转账业务追加日志

image-20230605163534759

分析:让log模块不参与回滚
解决方案:设置log模块的事务传播行为(事务协调员对事务管理员所携带事务的处理态度)

  1. 建立一个新事务
  2. 设置事务的传播行为image-20230605164903049

image-20230605164931966

-1695176318605)]

Spring事务角色

通过相同的数据源,将多个事务管理为一个事务

[外链图片转存中…(img-OTamBE3L-1695176318606)]

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

Spring事务属性

事务配置

[外链图片转存中…(img-nntuKnCM-1695176318607)]

[外链图片转存中…(img-Kjm8LV6B-1695176318607)]

程序中遇见如下两种异常则回滚,否则不回滚

  • error型异常:如溢出
  • 运行时异常

IOException就不会回滚,可以设置[外链图片转存中…(img-Da25TWGN-1695176318608)]

事务传播行为

案例:转账业务追加日志

[外链图片转存中…(img-qC0gc3ce-1695176318609)]

分析:让log模块不参与回滚
解决方案:设置log模块的事务传播行为(事务协调员对事务管理员所携带事务的处理态度)

  1. 建立一个新事务
  2. 设置事务的传播行为[外链图片转存中…(img-MARduawX-1695176318610)]

[外链图片转存中…(img-aOAnvmPi-1695176318611)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值