Spring思维导图(知识点总结,含面试题整理)
2021-04-11 21:53:58 24 举报
AI智能生成
理解Spring框架的设计理念,了解Spring的模块,掌握所应用的设计模式。 深入理解Spring的控制反转与AOP,Spring的Beans Spring事务管理知识汇总 公众号【小张日拱一卒】,回复ssm获取视频文档资源。
作者其他创作
大纲/内容
基于POJO(plain ordinary java object)的轻量级和最小侵入性编程
通过依赖注入和面向接口实现松耦合
基于切面和惯例进行声明式编程
通过切面和模板减少样板式代码
为了降低Java开发的复杂性,Spring采取了4种关键策略
Spring最根本的使命是解决企业级应用开发的复杂性,即简化Java开发。
Spring为开发者提供一个一站式轻量级应用开发平台
Spring设计目标
在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法
Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦
Spring设计理念
IoC容器和AOP模块。通过IoC容器管理POJO对象(之前自己管理,自己new对象。现在扔给Spring管理,用时直接从Spring中获取)以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务
IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件
Spring框架的核心
Spring框架的设计目标,设计理念,和核心是什么
对原来技术不影响
非侵入性
IOC是思想,DI:IOC的实现
优点见IOC篇
依赖注入DI(Dependency Injection) 、反转控制IOC(inversion of control)
AOP 对OOP进行补充
实现对程序进行权限拦截、运行监控等功能
面向切面编程AOP
Spring是一个容器
复杂项目需要1000个对象,需开辟1000个内存空间 同时不能保证他们都在使用,引入单例,需要自己去造
只用new的方法
容器,管理多个对象=Spring的组件 ,就可以管理对象的生命周期 ,使用的时候直接去调用。
有了Spring
Spring IOC 容器负责创建对象,管理对象(通过依赖注入DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
Tomcat:web容器,可以管理servlet的生命周期
容器
Spring实现了使用简单的组件配置组合成一个复杂的应用
降低耦合,一个对象存在与否与另一个对象联系不大
在 Spring 中可以使用XML和Java注解组合这些对象
项目:各个类,由类产生对象,由对象调用方法最终实现功能。
Spring可以把项目中所有的类进行管理,这些对象称为组件,组件化
接口 - 定义功能
Bean 类 - 它包含属性,setter 和 getter 方法,函数等
Bean 配置文件 - 包含类的信息以及如何配置它们
Spring 面向切面编程(AOP) - 提供面向切面编程的功能
用户程序 - 它使用接口
Spring 应用程序有哪些不同组件?
组件化
作为一个成熟的 Spring Web 应用程序
作为第三方 Web 框架,使用 Spring Frameworks 中间层
作为企业级 Java Bean,它可以包装现有的 POJO(Plain Old Java Objects)
用于远程使用
使用 Spring 有哪些方式?
在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库
一站式
只需要通过配置就可以完成对事务的管理,而无需手动编程
声明式事务的支持
Spring对Junit4支持,可以通过注解方便的测试Spring程序
方便程序的测试
Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
降低JavaEE API的使用难度
优点
Spring明明一个很轻量级的框架,却给人感觉大而全
Spring依赖反射,反射影响性能
缺点
Spring的优缺点是什么?
控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)
Spring beans:提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。
提供spring 框架的基础功能,BeanFactory 是任何以spring为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring成为一个容器。
Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从真正的应用代码中分离。最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans。该容器从XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。
详细讲解一下核心容器(spring context应用上下文) 模块
在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发
上下文更新事件(ContextRefreshedEvent)
当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件
上下文开始事件(ContextStartedEvent)
当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件
上下文停止事件(ContextStoppedEvent)
当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁
上下文关闭事件(ContextClosedEvent)
在Web应用中,当一个http请求(request)结束触发该事件。如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知
请求处理事件(RequestHandledEvent)
Spring框架中有哪些不同类型的事件
核心容器(Core Container)
AOP也是依赖于IOC
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等
AOP(Aspect Oriented Programming)和设备支持(Instrmentation)
消息(Messaging)
从下至上。ORM对象关系映射 用在持久层框架中,从数据库中查询出来的数据自动赋值给对象。操作数据库像操作实体类一样简单
spring jdbc:提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC
数据访问与集成(Data Access/Integeration)
spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext
Web
spring test:主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试
Test
Spring由哪些模块组成?
工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例
单例模式:Bean默认为单例模式
代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现:ApplicationListener
包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。
Spring 框架中都用到了哪些设计模式?
Spring概述
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
IOC 管理对象 配置到配置文件中
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
传统方式: 我想吃饭 我需要买菜做饭
反转控制: 我想吃饭 饭来张口(获取对象) (订外卖)
反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式
IOC思想:自己对对象的控制权交给容器,让容器自己去管理
不知道Spring是如何创建对象的,我们只关心,在用对象的时候能直接拿来使用。
理解内容
什么是Spring IOC 容器?
管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的
解耦,由容器去维护具体的对象
托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的
控制反转(IoC)有什么作用
IOC 或 依赖注入把应用的代码量降到最低
最小的代价和最小的侵入性使松散耦合得以实现
IOC容器支持加载服务时的饿汉式初始化和懒加载
IOC的优点是什么?
工厂模式加反射机制
前提: Spring中有IOC思想, IOC思想必须基于 IOC容器(ApplicationContext接口)来完成, 而IOC容器在最底层实质上就是一个对象工厂。
在通过IOC容器读取Bean的实例之前,需要先将IOC容器本身实例化。
BeanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的。
ApplicationContext:BeanFactory的子接口(接口越向下,功能越丰富),提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
Spring提供了IOC容器的两种实现方式
ApplicationContext 是一个接口 不能直接实例化,通过接口的实现类来进行实例化。
此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置
可以看到它的多个重载的方法
对应类路径下的XML格式的配置文件(相对路径)
ClassPathXmlApplicationContext
此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数
对应文件系统中的XML格式的配置文件(绝对路径)
FileSystemXmlApplicationContext
此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean
WebXmlApplicationContext
ApplicationContext通常的实现是什么?
初始化容器
在初始化时就创建单例的bean,也可以通过配置的方式指定创建的Bean是多实例的。
ApplicationContext ac = new ClassPathXmlApplicationContext(\"applicationContext.xml\");
ApplicationContext
1)是ApplicationContext的子接口,包含一些扩展方法
2)refresh()和close()让ApplicationContext具有启动、关闭和刷新上下文的能力。
ConfigurableApplicationContext
专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作
WebApplicationContext(SpringMVC)
类关系图
Spring IoC 的实现机制
最重要的就是依赖注入,从 XML 的配置上说,即 ref 标签。对应 Spring RuntimeBeanReference 对象
支持回调某些方法(但是需要实现 Spring 接口,略有侵入)
指定初始化方法和销毁方法
支持集合
自动装配
依赖检查
依赖注入
Spring 的 IoC支持哪些功能
可以从ApplicationContext继承的这几个接口入手,除去BeanFactory相关的两个接口就是ApplicationContext独有的功能
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
继承MessageSource,因此支持国际化
统一的资源文件访问方式
提供在监听器中注册bean的事件
同时加载多个配置文件
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能
依赖关系
BeanFactroy采用的是延迟加载(懒加载)形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢
加载方式
BeanFactory通常以编程的方式被创建
ApplicationContext还能以声明的方式创建,如使用ContextLoader
创建方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用
两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册
注册方式
ApplicationContext和BeanFactory的区别
BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取ResourcePatternResolve,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。
为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的 ClassPathXmlApplicationContext 类来展示整个容器的层级 UML 关系
最上面的是 BeanFactory,下面的 3 个绿色的,都是功能扩展接口
看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)
通常用户看到的就是 “高级容器”。 但 BeanFactory 也非常够用啦
左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其他的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂所有配置,生命周期事件回调等
加载配置文件,解析成 BeanDefinition 放在 Map 里
调用 getBean 时,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 ,完成依赖注入
IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤
至于高级容器 ApplicationContext,他包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,包含了太多的功能。一句话,他不仅仅是 IoC。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。
小结
Spring 如何设计容器的,BeanFactory和ApplicationContext的关系详解
控制反转IoC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:依赖注入和依赖查找
依赖注入:相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。
一个Bean看作new的一个对象
例如:bean标签中name=“id”value=“888”value就是对name的注入
依赖:Car – 发动机/方向盘对象 可以让Spring来维护关系
依赖于谁就为谁赋值
注入: 赋值
解释
如何理解?
什么是Spring的依赖注入?
应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由IoC容器负责,“查找资源”的逻辑应该从应用组件的代码中抽取出来,交给IoC容器负责。容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造器传递给需要的对象。
依赖注入的基本原则
依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露JavaBean的setter方法或者带参数的构造器或者接口(已弃用),使容器可以在初始化时组装对象的依赖关系
查找定位操作与应用代码完全无关
不依赖于容器的API,可以很容易地在任何容器以外使用应用对象
不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器
其与依赖查找方式相比,主要优势为
依赖注入有什么优势
没有部分注入
不会覆盖 setter 属性
任意修改都会创建一个新实例
适用于设置很多属性
构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖
Spring自动匹配合适的构造器
<constructor-arg value=\"90\" index=\"2\" type=\"java.lang.Double\"/>
通过索引值指定参数位置(一般结合type使用)
通过构造器自动装配:当bean中存在多个构造器时,此种自动装配方式将会很复杂。不推荐使用。
通过类型区分重载的构造器
使用建议:构造器参数实现强制依赖
通过bean的构造器赋值
有部分注入
会覆盖 setter 属性
任意修改不会创建一个新实例
适用于设置少量属性
Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入
bean标签内添加属性
value:属性值
name:属性名
依赖与反射,反射必须要有无参构造器
<property name=\"id\" value=\"10010\"/>
Property标签通过set方法进行赋值 进行注入(用的最多)
使用建议:setter方法实现可选依赖
通过bean的setXxx()方法赋值
有哪些不同类型的依赖注入实现方式?
工厂模式,不在乎怎么创建的对象,直接从工厂里取出需要的对象;工厂来创建对象
工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象。
工厂bean必须实现org.springframework.beans.factory.FactoryBean接口。
FactoryBean
Spring控制反转(IOC)
Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中 的形式定义。
定义spring所管理的一个对象
不需要强转也可以唯一获取
Person person = ac.getBean(\"person\
通过类型获取bean
id:该对象的唯一标示,注意:不能重复,在通过类型获取bean的过程中可以不设置 Peason.class
class=\"com.atguigu.spring.mod.Person\",依赖与反射,反射必须要有无参构造器
class:此对象所属类的全限定名 指明对象 是属于哪个类的
Spring单例模式只需要一个属性设置,而不需要自己去设计单例模式,构造方法私有化,提供一个对外的公共访问点。
容器初始化时,Spring里的bean会被创建
使用无参构造器,多次调用只调用了一次构造方法
不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题
有状态就是有数据存储功能
无状态就是不会保存数据。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所以某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了
改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
解决方案
Spring框架中的单例bean是线程安全的吗?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
Spring如何处理线程并发问题?
singleton:单例,唯一实例(默认)
多例即原型的bean,会在使用时创建
使用无参构造器,有几次调用,就有几次构造方法
使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销
prototype:原型,多例;
request:每一次HTTP请求都会产生一个新的bean(对象),该bean仅在当前HTTP request内有效。
session:每一次HTTP请求都会产生一个新的bean(对象),该bean仅在当前HTTP session内有效。
scope:设置bean的作用域
Spring IOC容器可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。
createBeanInstance() -> 实例化
实例化和属性赋值对应构造方法和setter方法的注入
populateBean() -> 属性赋值
初始化和销毁是用户能自定义扩展的两个阶段
initializeBean() -> 初始化
doCreate()方法顺序调用以下三个方法
销毁 Destruction
Spring Bean的生命周期只有这四个阶段
postProcessBeforeInstantiation在doCreateBean之前调用
作用于实例化之前
这也是Aop等功能实现的关键点
该方法的返回值会替换原本的Bean作为代理
postProcessBeforeInstantiation调用点
该方法在属性赋值方法populateBean内,但是在真正执行赋值操作之前
其返回值为boolean,返回false时可以阻断属性赋值阶段
postProcessAfterInstantiation调用点
作用于实例化阶段的前后
继承了BeanPostProcessor接口
InstantiationAwareBeanPostProcessor
作用于初始化阶段的前后
关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的
BeanPostProcessor
实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。
第一大类:影响多个Bean的接口
Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。
调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group1
EnvironmentAware
实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便
EmbeddedValueResolverAware
其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口
(涉及到另一道面试题)ApplicationContext和BeanFactory的区别
ApplicationContextAware(ResourceLoaderAware\\ApplicationEventPublisherAware\\MessageSourceAware)
Aware Group2
分类依据:排列顺序同样也是Aware接口的执行顺序
Aware接口具体可以分为两组
说明了Aware都是在初始化阶段之前调用的
Aware Group1中的三个Bean开头的Aware
在代码中直接调用的
这里调用的是Group2中的几个Aware
而实质上这里就是前面所说的BeanPostProcessor的调用点
也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的
initializeBean() -> 初始化调用点
BeanPostProcessor的另一个调用点
作用于初始化阶段之后
initializeBean() -> 初始化源码中
Aware调用时机源码分析
Aware类型的接口
注意:Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法
initializeBean 对应生命周期的初始化阶段
ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法
DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段
实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段
生命周期接口
第二大类:只调用一次的接口
常用扩展点
在这四步之间穿插的各种扩展点
1.Bean容器找到配置文件中Spring Bean的定义
2. Bean容器利用Java Reflection API创建一个Bean的实例
通过构造器或工厂方法创建bean实例(相当于servlet生命周期中的实例化)
3. 如果涉及到一些属性值,利用set()方法设置一些属性值
为bean的属性设置值和对其他bean的引用(依赖注入)
4.如果Bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法。
5.如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
6.如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
7.如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来
添加bean后置处理器后bean的生命周期
8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法。
9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
10.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法
将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
调用bean的初始化方法
11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization()方法。
将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法
bean可以使用了(实现功能)
12.当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。
13.当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。
当容器关闭时,调用bean的销毁方法
Spring IOC容器对bean的生命周期进行管理的过程
在容器加载bean的时候被调用
setup
在容器卸载类的时候被调用
teardown
两个重要的bean 生命周期方法
相应的注解(@PostConstruct和@PreDestroy)
在配置bean时,通过init-method和destroy-method 属性为bean指定初始化和销毁方法
哪些是重要的bean生命周期方法? 你能重载它们吗?
bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
典型应用:检查bean属性的正确性或根据特定的标准更改bean的属性。
bean后置处理器(对Spring所管理的每一个bean都有效果)对IOC容器里的所有bean实例逐一处理,而非单一实例。
org.springframework.beans.factory.config.BeanPostProcessor
在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法
bean后置处理器需要实现接口
bean的后置处理器(针对bean 进行的操作)
说说bean的生命周期
<bean id=\"person\" class=\"com.atguigu.spring.mod.Person\" scope=\"singleton\"></bean>
resources/.xml
什么是Spring beans?
一个Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个bean,它的生命周期详情及它的依赖。
一个 Spring Bean 定义包含什么?
Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。
Spring配置文件包含了哪些信息
可以使用字符串表示的值,可以通过value属性或value子节点的方式指定
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来
注意:引用数据类型不能使用这种方式,要使用ref
能够写在双引号中来表示正常的含义
字面量
<property name=\"score\"><null/></property>
null值
可以
你可以在Spring中注入一个null 和一个空字符串吗?
创建对象,对象来对teacher 进行赋值
使用Bean来管理一个对象
通过ref引用当前Spring所管理的范围之内的某一个Bean的ID
<property name=\"teacher\" ref=\"teacher\"/>
给bean的级联属性赋值
JDBC 连接池对象交个Spring来管理,如何来使用properties文件
引用外部属性文件
外部已声明的bean、引用其他的bean
在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的,它们的Scope一般是prototype。
什么是Spring的内部bean?Spring inner beans
为属性赋值时,可以使用哪些值
<property name=\"id\" value=\"10010\"/><br>
<bean id=\"s3\" class=\"org.xinzhang.di.Student\" p:id=\"123\" p:age=\"14\" p:name=\"zx\"/>
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。Spring\t从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean\t的属性。
p名称空间
Set方法注入
通过index设置参数的位置
通过type设置参数类型
构造器注入
静态工厂注入
实例工厂
Spring基于xml注入bean的几种方式
XML配置文件
基于注解的配置
基于java的配置
如何给Spring 容器提供配置元数据?Spring有几种配置方式
Spring所管理的bean就是一个对象,而这个对象组成由多个属性和方法组成,方法是用来调用的,而属性是用来赋值的。在为Spring所管理的对象进行赋值时,可叫做装载/注入。
1)手动装配:以value或ref的方式明确指定属性值都是手动装配。
2)自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。(非字面量属性,需要ref的)
根据名称自动装配:必须将目标bean的名称和属性名设置的完全相同
byName:通过属性名和spring容器中bean的id进行比较,若一致则可直接赋值无法赋值的例子(实体类中属性名 car,而spring中bean的id为car2)
兼容性:配置文件自动装配 \t子类可以为父类,接口赋值
在使用byType的过程中,要求spring容器中只能有一个能为属性赋值的bean
根据类型自动装配:将类型匹配的bean作为属性注入到另一个bean中。若IOC容器中有多个与目标bean类型一致的bean,Spring将无法判定哪个bean最合适该属性,所以不能执行自动装配
byType:通过spring容器中bean的类型,为兼容性的属性赋值
当设置autowire属性,会作用于该bean中所有的非字面量属性,因此谁都不用
相对于使用注解的方式实现的自动装配,在XML文档中进行的自动装配略显笨拙,在项目中更多的使用注解的方式实现
选用建议
autowire:根据某种策略自动为非字面量属性赋值
什么是 spring 装配?
在需要被spring管理的类上加上相应注解
(组件理解为bean)
在配置文件中通过<context:component-scan>对所设置的包结构进行扫描,将加上注解的类,作为spring的组件进行加载
两步:添加注解,扫描组件
\t相对于XML方式而言,通过注解的方式配置bean更加简洁和优雅,而且和MVC组件化开发的理念十分契合,是开发中常用的使用方式。
1000个对象管理,需要写1000个bean吗?一个类依赖于20个非字面量对象,只想为两个属性赋值,只依赖于两个对象。注解方式
Bean 对象由类产生,对象是类的实例化,确定对象属于哪个类,所有bean标签中class很重要,找到这个类,交个Spring来管理。使用注解方式直接加在类上
控制层接收请求--service处理业务逻辑,dao处理持久化--结果返回给service--控制层--响应客户端
请求响应过程
标识一个受Spring IOC容器管理的组件
加在类上,就可以当作类的组件进行加载 ,Spring会对这个类进行管理
普通组件:加上@Component\t
标识一个受Spring IOC容器管理的表述层控制器组件
SpringMVC控制层普普通通的类,不需要继承和实现,通过注解识别为控制层来加载。实现请求响应 springMVC封装了servlet
表述层控制器组件:@Controller
标识一个受Spring IOC容器管理的业务逻辑层组件
servlet控制请求与响应
service 业务逻辑层
业务逻辑层组件:@Service
标识一个受Spring IOC容器管理的持久化层组件
DAO(Data Access Object):数据访问层(持久层)
持久化层组件:@Repository
Spring组件: 组成部分 bean
注意:事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,即使将\t\t\t@Respository注解用在一个表述层控制器组件上面也不会产生任何错误,
所以\t@Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确\t当前的组件扮演的角色。
四个注解一样,名字不一样,哪一层就加哪一层的注解
默认情况:使用组件的简单类名首字母小写后得到的字符串作为bean的id
使用组件注解的value属性指定bean的id
组件命名规则
使用注解标识组件(组件理解为bean)
组件:指spring中管理的bean
作为spring的组件进行加载:会自动在spring的配置文件中生成相对应的bean,这些bean的id会以类的首字母小写为值
组件被上述注解标识后还需要通过Spring进行扫描才能够侦测到
<context:component-scan>:扫描组件,对设置的包下面的类进行扫描,会将加上注解的类作为spring的组件进行加载
指定被扫描的package
当需要扫描多个包时可以使用逗号分隔。
如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类
base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包及其子包中的所有类。
注意:在使用包含时,一定要设置use-default-filters=\"false\",将默认的过滤(即扫描包下所有的类)关闭,仅包含某些组件
<context:include-filter>:在设定的包结构下,再次通过注解或类型具体包含到某个或某几个类
注意:在使用排除时,一定要设置use-default-filters=\"true\",将默认的过滤(即扫描包下所有的类)打开
切记:一个<context:component-scan>中可以出现多个include,也可以同时出现多个exclude,但是两个不能同时出现
<context:exclude-filter>:在设定的包结构下,再次通过注解或类型排除某个或某几个类
包含与排除(在定位base-package的时候要尽量定位准确,加快包加载速度)
根据目标组件是否标注了指定类型的注解进行过滤
<context:component-scan base-package=””><context:include-filter 中expression属性,找对应注解类中导入的类型expression=\"import org.springframework.stereotype.Service\"
annotation
根据目标组件是否是指定类型的子类的方式进行过滤
expression=\"org.xinzhang.ioc.annotationBean.dao.UserDaoMybatisImpl\"
assignable
aspectj
regex
custom
过滤表达式type
<context:component-scan base-package=\"org.xinzhang.ioc.annotationBean\">
扫描组件
Spring通过注解实现属性装配
Service组件需要用到\tRepository组件实例
Controller组件需要用到Service组件实例
需求
该后置处理器可以自动装配标记了@Autowired(自动装配,不需要手动去new 对象)、@Resource或@Inject注解的属性
在指定要扫描的包时,<context:component-scan> 元素会自动注册一个bean的后置处理器:AutowiredAnnotationBeanPostProcessor的实例
自动装配:在需要赋值的非字面量属性上,加@Autowired,可在spring容器中,通过不同方式匹配到相应bean
Private UserService userService = new UserServiceImpl();替换成:@AutowairedPrivate UserService userService;
实现依据
根据类型实现自动装配
构造器、普通字段(即使是非public)、一切具有参数的方法都可以应用@Autowired\t\t 注解
默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的bean装配属性时,会抛出异常
若某一属性允许不被设置,可以设置@Autowired注解的required属性为 false
@Autowired装配时,会默认使用byType的方式,此时要求spring容器中只有一个能够为其赋值
@Controller\t\t生成首字母小写的bean userControllerpublic class UserController\t@Service\t\t\t生成首字母小写的bean userServiceImplpublic class UserServiceImpl@Repository\t\t生成首字母小写的bean userDaoImplpublic class UserDaoImpl
@AutowairedPrivate UserService userService;在自动装配时,没有与userService同名的id,所以是先以类型byType进行装配。 子类userServiceImpl 为接口 userService赋值
当byType实现不了装配时,会自动切换到byName,此时要求spring容器中,有一个bean的id和属性名一致
@Qualifier(value=\" userDaoImpl\")\t\t指定使用的bean
@Repositorypublic class UserDaoMybatisImpl implements UserDao@Repositorypublic class UserDaoImpl implements UserDao有了自动装配@Autowired才能使用限定 @Qualifier(value=\"beanId\") 装配多个,限定到某一个
一个注解只对一个类一个属性一个方法有效注解申明在方法上,是对参数有效果,对参数赋值之后才有值,才不是空指针异常@Autowired@Qualifier(value=\"userDaoMybatisImpl\")public void setUserDao(UserDao userDao) {\tthis.userDao = userDao;}
若自动装配时,匹配到两个bean,id分别为:userDaoMybatisImpl和userDaoImpl,可使用@Qualifier(value=\" userDaoMybatisImpl\")\t\t
默认情况下,当IOC容器里存在多个类型兼容的bean时,Spring会尝试匹配bean\t\t 的id值是否与变量名相同,如果相同则进行装配。如果bean的id值不相同,通过类 \t 型的自动装配将无法工作。此时可以在@Qualifier注解里提供bean的名称。Spring\t 甚至允许在方法的形参上标注@Qualifiter注解以指定注入bean的名称。
@Autowired注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的bean进行自动装配。
@Autowired注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的bean。
@Autowired注解用在java.util.Map上时,若该Map的键值为String,那么 Spring将自动装配与值类型兼容的bean作为值,并以bean的id值作为键。
@Autowired注解
@Resource注解要求提供一个bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为bean的名称。
@Resource
@Inject和@Autowired注解一样也是按类型注入匹配的bean,但没有reqired属性
@Inject
组件装配
通过注解配置bean
给bean的属性赋值(依赖注入的过程)
Spring Beans
代理对象:帮助我们完成这些事情的对象
目标对象:我们要做的事情
动态代理:不管我的目标对象是什么,都可以通过这样的一个类去生成相对应的代理对象帮助我去完成功能。
计算器的目的是加减乘除方法,方法存在于类中所以类名是目标对象
更像一个工具类
动态代理(三个角色:原始对象,代理对象,目标对象)
类由类加载器加载,当前代理对象所属类的类加载器,来创建代理对象。
ClassLoader loader = this.getClass().getClassLoader();
代理对象帮助我们完成功能,要知道我们的功能实现哪些接口,实现哪些功能。
Class[] interfaces = mathImpl(目标对象).getClass().getInterfaces();
参数一:代理对象 proxy
参数二:帮助实现功能(方法)
InvocationHandler:执行处理器:设置代理对象如何实现目标对象功能\tinvoke方法,匿名内部类的方法创建对象
ProxyUtil proxy = new ProxyUtil(new MathImpl()); //构造器方式直接赋值MathI math = (MathI)proxy.getProxy(); //绝不能强转为目标对象, 转换为目标对象所实现的 接口\t 涵括更多功能\tObject向下转型
方法的执行依赖于对象,有对象才能调用方法,知道方法名,知道参数列表才能确定调用哪个方法。
代理模式:保证结果的一致性,代理对象调用目标对象的方法
AOP代理模式
功能实现过程调用代码
纵向继承机制
面向对象
依赖于动态代理
功能抽取出来作用于代码(非业务逻辑(日志功能)—>业务逻辑(增删改查))
把目标对象中的 公共部分(功能)--横切关注点,非业务功能抽取出来所存放的类就叫做切面
横向抽取机制
面向切面
(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传 统 OOP(Object-Oriented Programming,面向对象编程)的补充
每个事物逻辑位于一个位置,代码不分散,便于维护和升级
业务模块更简洁,只包含核心业务代码
验证参数
前置日志
后置日志
从每个方法中抽取出来的同一类非核心业务。
横切关注点
封装横切关注点信息的类,每个关注点体现为一个通知方法。
在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。
AspectJ大量注解(具体实现):Java社区里最完整最流行的AOP(思想)。对比原生:xml配置框架。
第一步:配置文件xml中扫描组件<context:component-scan base-package=\"org.xinzhang.aop\"/>
span style=\"mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;mso-font-kerning:1.0000pt;\"当Spring IOC容器侦测到bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动为span style=\"mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;mso-font-kerning:1.0000pt;\"\tspan style=\"mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;mso-font-kerning:1.0000pt;\"与AspectJ切面匹配的bean创建代理span style=\"mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;mso-font-kerning:1.0000pt;\"
第二步:配置<aop:aspectj-autoproxy\t/>
定义切面作用的优先级,值越小优先级越高,默认值为int的最大值
Servlet在第一次访问时进行加载,让servlet提前到项目启动时加载,使用标签loadstartup数字代表加载优先级,值小优先级越高
@Order(1)
第三步:在切面上定义两个注解 组件注解 @Component+ 切面注解@Aspect(标注当前类为切面)
AspectJ
切面(Aspect)
把横切关注点加入到切面里叫通知
切面必须要完成的各个具体工作
@Before:前置通知,在方法执行之前执行
@Before(value = \
第一个*代表任意的访问修饰符和返回值类型
第二个*代表任意类
第三个*代表类中任意方法
.. 两个点代表任意的参数列表
必须设置value,其值为切入点表达式
@Before(value=\"execution(* com.atguigu.spring.aop.*.*(..))\")
@After:后置通知,作用于方法的finally语句块,即不管有没有异常都会执行
@AfterRunning:返回通知,在方法返回结果之后执行
可通过returning设置接收方法返回值的变量名
要想在方法中使用,必须在方法的形参中设置和变量名相同的参数名的参数
如果只想在连接点返回的时候记录日志,应使用返回通知代替后置通知。
@AfterReturning(value = \"myTestReuse()\
@AfterThrowing:异常通知,在方法抛出异常之后执行
可通过throwing设置接收方法返回的异常信息
在参数列表中可通过具体的异常类型,来对指定的异常信息进行操作
@AfterThrowing(value = \"myTestReuse()\
@Around:环绕通知,围绕着方法执行
在切面上写通知
通知(Advice)
条件:切面要作用到谁
AOP可以通过切入点定位到特定的连接点。
切入点(pointcut)
通知作用于哪一个包下哪一个类名的哪一个方法
通过解析表达式找到切面所应用到的连接点
@Pointcut(value = \"execution(* com.atguigu.spring.aop.*.*(..))\")\tpublic void myTestReuse() {}
1)在编写AspectJ切面时,可以直接在通知注解中书写切入点表达式。但同一个切点表达式可能会在多个通知中重复出现。
2)在AspectJ切面中,可以通过@Pointcut注解将一个切入点声明成简单的方法。切入点的方法体通常是空的,因为将切入点定义与应用程序逻辑混在一起是不合理的。
3)切入点方法的访问控制符同时也控制着这个切入点的可见性。如果切入点要在多个切面中共用,最好将它们集中在一个公共的类中。在这种情况下,它们必须被声明为public。在引入这个切入点时,必须将类名也包括在内。如果类没有与这个切面放在同一个包中,还必须包含包名。
4)其他通知可以通过方法名称引入该切入点
切入点表达式:作用于切入点
切入点表达式通常都会是从宏观上定位一组方法,和具体某个通知的注解结合起来就能够确定对应的连接点。
那么就一个具体的连接点而言,我们可能会关心这个连接点的一些具体信息
例如:当前连接点所在方法的方法名、当前传入的参数值等等。这些信息都封装在JoinPoint接口的实例对象中。
连接点(Joinpoint)
切面要作用于谁
被通知的对象(前置通知:方法执行之前,后置通知,返回通知,异常通知,环绕通知(包含四个))
目标(Target)\t
AOP 加入前置后置等操作
代理(Proxy)
AOP术语
AOP图解
AOP
一个业务逻辑需要多次操作才能完成业务逻辑,在这个业务逻辑中所有的数据库操作就在一个事务中
使用事务保证数据的完整性和一致性
事务(多次操作):要么都执行,要么都不执行
买书过程:查询图书库存以及价格 ,在库存中减一,客户账户扣费,对数据库的多次操作就是一个事务
事务管理的代码属于非核心业务
DAO中每一个方法都是对数据库的单独一次操作
事务:加在service中的方法代表一个完整的业务逻辑,完整的功能 完成事务四特性
事务概述
\"原子\" 本意“不可再分”,事务的原子性表现为一个事务中涉及的多个操作在逻辑上缺一不可。要求事务中的所有操作要么都执行,要么都不执行。
原子性(atomicity)
一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的
回滚:如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态
所有数据都处于满足业务规则的一致性状态。如:转账前后金额一致
“一致”指的是数据的一致
一致性(consistency)
在应用程序实际运行过程中,事务往往是并发执行的,所以有可能许多事务同时处理相同数据,因此每个事务都应与其他事务隔离开来,防止数据损坏
隔离性原则要求多个事务在并发执行过程中不会互相干扰
隔离性(isolation)
通常情况下,事务对数据的修改应该被写入到持久化存储器(硬盘)中
持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。
持久性(durability)
事务的四大属性ACID
Spring事务本质:数据库对事务的支持,没有数据库的事务支持,spring无法提供事务功能。真正的数据库层的事务提交和回滚通过binlog或者redo log实现
Spring事务的实现方式和实现原理
通过编程的方式管理事务,极大的灵活性,但难维护
编程式事务管理
事务管理代码的固定模式作为一种横切关注点,可以通过AOP方法模块化,进而借助Spring AOP框架实现声明式事务管理。
Spring在不同的事务管理API之上定义一个抽象层,通过配置使其生效,不必了解事务管理API的底层实现细节,就可以使用Spring的事务管理机制。
将业务代码和事务管理分离,只需用注解和XML配置来管理事务
声明式事务管理
Spring支持的事务管理类型, spring 事务实现方式有哪些?
TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
本来期望目标方法进行事务管理,但若是错误的配置这三种 可以不启动事务的propagation,事务将不会发生回滚。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。mandatory命令性强制性
支持当前事务的情况
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 如果当前存在事务,则把当前事务挂起,创建一个新的事务,
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 如果当前存在事务,则把当前事务挂起,如果当前没有事务,则以非事务方式运行,
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常
不支持当前事务的情况
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
其他情况
当多个事务同时存在时,spring如何处理这些事务的行为
说一下Spring的事务传播行为
isolation:事务的隔离级别,在并发的情况下,操作数据的一种规定,多条请求处理
TransactionDefinition 接口中定义了五个表示隔离级别的常量
Mysql 默认采用的 REPEATABLE_READ隔离级别
Oracle 默认采用的 READ_COMMITTED隔离级别
使用后端数据库默认的隔离级别
TransactionDefinition.ISOLATION_DEFAULT
假设现在有两个事务:Transaction01和Transaction02并发执行①Transaction01将某条记录的age值从20修改为30。\t②Transaction02读取了Transaction01更新后的值:30。\t③Transaction01回滚,AGE值恢复到了20。\t④Transaction02读取到的30就是一个无效的值。
读未提交:脏读
可能会导致脏读、幻读或不可重复读
读未提交:最低的隔离级别,允许读取尚未提交的数据变更
TransactionDefinition.ISOLATION_READ_UNCOMMITTED
①Transaction01读取了AGE值为20。\t②Transaction02将age值修改为30。\t③Transaction01再次读取AGE值为30,和第一次读取不一致。
读已提交:不可重复读
可以阻止脏读,但是幻读或不可重复读仍有可能发生
读已提交:允许读取并发事务已经提交的数据
TransactionDefinition.ISOLATION_READ_COMMITTED
①Transaction01读取了student表中的一部分数据(10条)。\t②Transaction02向student表中插入了新的行(10条)。\t③Transaction01读取了student表时,多出了一些行(再查成20条,幻读)。
可重复读:幻读 , 正在读取的数据,其他人不能操作,可以添加新数据
可以阻止脏读和不可重复读,但幻读仍有可能发生
可重复读:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改
TransactionDefinition.ISOLATION_REPEATABLE_READ
严重影响程序的性能
该级别可以防止脏读、不可重复读以及幻读
序列化(单线程):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰
TransactionDefinition.ISOLATION_SERIALIZABLE
说一下 spring 的事务隔离?
rollbackFor | rollbackForClassName | noRollbackFor | noRollbackForClassName:设置事务回滚的条件
noRollbackFor 不会因为抛出MyException异常而回滚 该成功该失败失败
rollbackFor(设置因为什么进行回滚,不因为什么回滚):异常所对应的权限对象
Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,也可以保证数据的一致性。
当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
捕获到RuntimeException或Error时回滚,而捕获到编译时异常不回滚
默认情况
rollbackFor属性:指定遇到时必须进行回滚的异常类型,可以为多个
noRollbackFor属性:指定遇到时不回滚的异常类型,可以为多个
span style=\"mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;mso-font-kerning:1.0000pt;\"注解@Transactional
设置途经
触发事务回滚的异常
在事务 强制回滚 前最多可以执行(等待)的时间秒杀活动,一万个请求在等待,给请求设置timeout 压力测试:超时中断线程调度设置超时时间
timeout
脏读:读未提交,不可重复读:读已提交,可重复读:幻读。
若设置为只读,不管事务中有没有写的操作,mysql都会在请求访问数据的时候,不加锁,提高性能
mysql给加锁,其他请求不可操作,面向增删改操作,不加锁可能出现一千个请求去查看修改一条数据.但是如果有写操作的情况,建议一定不能设置只读
指定当前事务中的一系列的操作是否为只读 读本身不涉及事务
readOnly
如果一个事务只读取数据但不做修改,数据库引擎可以对这个事务进行优化。
由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。
超时事务属性:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。
软件性能
爱的鼓励
事务的超时和只读属性
Spring事务管理(AOP最经典的体现)
Spring思维导图(知识点总结,含面试题整理)
0 条评论
回复 删除
下一页