Spring知识点总结
Spring
概述
Spring可以轻松创建Java企业应用程序。它提供了在企业环境中使用Java语言所需的一切,支持Groovy和Kotlin作为JVM上的替代语言,并可根据应用程序的需要灵活地创建多种体系结构。从Spring Framework 5.1开始,Spring需要JDK 8+(Java SE 8+),并为JDK 11 LTS提供开箱即用的支持。
Spring支持广泛的应用场景。在大型企业中,应用程序通常存在很长时间,并且必须在升级周期超出开发人员控制范围的JDK和应用程序服务器上运行。其他人可能在嵌入服务器的情况下作为单个jar运行,可能在云环境中运行。还有一些可能是不需要服务器的独立应用程序(例如批处理或集成工作负载)。
Spring是开源的。它拥有一个庞大而活跃的社区,可根据各种各样的实际用例提供持续的反馈。这有助于Spring在很长一段时间内成功发展。
设计理念
- 提供各个层面的选择。Spring允许您尽可能晚地推迟设计决策。例如,您可以通过配置切换持久性提供程序,而无需更改代码。许多其他基础架构问题以及与第三方API的集成也是如此。
- 适应不同的观点。Spring拥抱灵活性,并不认为应该如何做。它以不同的视角支持广泛的应用需求。
- 保持强大的向后兼容性。Spring的演变经过精心设计,可以在版本之间进行一些重大改变。Spring支持精心挑选的JDK版本和第三方库,以便于维护依赖于Spring的应用程序和库。
- 关心API设计。Spring团队花了很多心思和时间来制作直观的API,这些API在很多版本和多年中都有用。
- 为代码质量设定高标准。Spring Framework非常强调有意义的,最新的和准确的javadoc。它是极少数项目之一,可以声称干净的代码结构,包之间没有循环依赖。
spring-core 对顶层核心包
spring-beans spring定义的规范
spring-context 就是ioc的实现
spring-aspects 切面规范接口
spring-aop aop的实现
Spring的特征
- 核心技术:IoC容器,事件,资源,i18n,验证,数据绑定,类型转换,SpEL,AOP。
- 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。
- 数据访问:事务,DAO支持,JDBC,O / R映射,XML编组。
- Web Servlet: Spring MVC,WebSocket,SockJS,STOMP Messaging。
- Web Reactive:Spring WebFlux, WebClient, WebSocket.
- 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
- 语言:Kotlin,Groovy,动态语言
Spring框架常用到的设计模式
- 单例模式 (bean)
- 代理模式 (aop)
- 模板方法 (Template)
- 工厂/抽象工厂模式 (BeanFactory和FactoryBean)
- 委派模式 (随处可见)
- 观察者模式 (事件机制)
- 适配器模式
- 策略模式
- 门面模式
Spring容器
可以先看看我篇博文 什么是IOC
spring的IoC
IoC是一个容器概念,并不是Spring独有的,Spring只是实现了IoC而已,我们通常说的其实是SpringIoC,而Spring实现IOC主要有两种,就是spring-beans模块和spring-context模块,分别对应着BeanFactory和ApplicationContext,我们经常讨论的也就是ApplicationContext.而ApplicationContext只是BeanFactory接口的一个拓展,增加了一些额外的功能.
IOC容器 | 介绍 |
---|---|
BeanFactory | 一个bean工厂接口,类似于bean的集合,它是懒加载的,并且使用语法显式的提供资源对象,常见的实现有XmlBeanFactory,可以根据xml文件定义的内容去创建bean |
ApplicationContext | 基于BeanFactory的拓展容器,它是即时加载多的,它不想BeanFactory一样使用语法显式的提供资源对象,而是自己创建和管理资源对象,并且它还通过MessageSource支持国际化,也支持依赖的注解,常见的实现有 ClassPathXmlApplicationContext : 从classpath目录中获取xml并根据配置内容定义上下文 FileSystemXmlApplicationContext : 从文件系统中读取xml并根据配置内容定义上下文 XmlWebApplicationContext : 在web应用程序中读取xml并定义上下文 springboot提供的是ConfigServletWebServerApplicationContext |
IOC的本质其实就是工厂+反射,而springIOC只是在这个基础上处理了很多复杂逻辑而已.
SpringIoc的执行流程
refresh()
工厂初始化流程(createBeanInstance()):
主要分为三步:1.定位 2.加载 3.解析注册4.初始化5.注入
1.定位
2.加载
3.解析注册
4.初始化
5.注入
依赖注入(populateBean()):
1.读取BeanDefinition的信息,获取依赖信息,然后解析成一个BeanWapper
2.实例化(代理对象)
3.注入(设置值)
lazy-init=true的时候依赖注入发生在工厂
lazy-init=false的时候依赖注入发生在getBean()(默认)
beanFactory和FactoryBean的区别
beanFactory 工厂,管理bean,前缀是&
FactoryBean bean 是工厂实现的
SpringBean的作用域
作用域 | 所属范围 | 含义 |
---|---|---|
singleton | spring | 单例bean,默认的作用域,每个ioc容器有且仅有一个这种实例 |
prototype | spring | 多例bean,就比如说每次请求都生成一个新的bean实例 |
request | web-applicationContext | 每次请求生成一个,只在当前请求内有效 |
session | web-applicationContext | 每次请求的session生成一个,只在这个session的生命周期内有效 |
global session (5版本已废弃) | Portlet | 该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例 |
application | web-applicationContext | 每一个 Web Application 都会产生一个新的 Bean ,同时该 Bean 仅在当前 Web Application 内有效。 |
自定义 | 自定义 | 自定义作用域,实现Scope接口 |
SpringBean的生命周期
springbean的生命周期相对来说是有点复杂的,还是需要读过源码才有一些概念,尽管读的时候会走N多弯路(spring套路太深了),但是记住一句话,spring源码中只要是doXXX()的方法那你就看吧,准没错!简单总结一下:
- BeanFactory根据反射获取xml定义的bean并实例化bean(也可能是java congfig api配置的bean,注解配置的bean以及容器中beanDefinition定义的bean)
- 是用依赖注入填充bean属性
- 检查bean是否实现了Aware接口,然后根据响应的Aware调用对应的方法并传入参数,比如:如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。如果Bean实现了BeanFactoryAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。
- BeanPostProcessor前置处理:如果在Spring容器中有和加载这个Bean相关的BeanPostProcessor对象,执行postProcessBeforeInitialization(Object bean, String beanName)方法
- 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
- 如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。
- BeanPostProcessor后置处理:如果在Spring容器中有和这个Bean相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法
- 使用bean
- 当要销毁Bean的时候,如果Bean实现了DisposableBean接口,会执行destroy()方法。
- 当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。
注意: spring只管理单例bean,针对多例的bean是交给客户端自己去处理的.还有就是依赖注入不是发生在加载的时候而是发生在getBean的时候,再有就是bean定义中设置了懒加载的(lzay-init=true)在容器启动后不会加载这bean
SpringBean的getBean流程
可以说是最最复杂的地方,不看N遍源码不可能彻底搞明白,这里借用大佬一张图图片来源
bean的循环依赖
记住三个缓存:
缓存 | 含义 |
---|---|
singletonObjects | 单例bean缓存,最终成功,第一层 |
earlySingletonObjects | 对外曝光的bean缓存(ObjectFactory.getObject()),第二层 |
singletonFactories | bean工厂的缓存,第三层 |
SpringAOP
SpringMVC
1. SpringMVC是什么?
Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”来自其源模块(spring-webmvc)的名称,但它通常被称为“Spring MVC”。SpringMVC是基于模型(M)-视图(V)-控制器©的结构实现的,主要用于开发松散耦合并且灵活多变的web应用,相对来说M在其中是最复杂的一块,而V和C主要是为了处理M而存在的,目前的趋势已经很少有MVC在一起的情况了,现在都讲究前后端分离以及分布式架构,所以更多的还是在M和C上做文章.
2. SpringMVC能干什么?
SpringMVC可以快速开发WEB应用程序,Spring框架为我们封装好了很多的内容让我们可以少写N多代码,开发更加简洁,完全摆脱了早些年Servlet容器和EJB的时代.
3. SpringMVC怎么实现的?
3.1 SpringMVC的9大核心组件
MultipartResolver
Content-Type为 multipart/* 请求的解析器组件,主要是处理文件上传的解析器,它会把HttpServletRequest封装成MultipartHttpServletRequest ,然后再从MultipartHttpServletRequest 中获取我们上传的文件进行后续的解析与业务逻辑
LocaleResolver
国际化解析器,一般用的不多,做国际平台比较常见,其实就是把网站的动态内容以key-value的形式保存在一个配置文件中,然后动态解析这个配置文件的内容来展示页面的数据,比如在展示一个View,在中国展示的是日期:2019-01-01 在外国会展示成Date:2019-01-01.
ThemeResolver
主题解析器,现在前后端分离,基本都不用了,比如说在后台处理,判断User-Agent是PC端还是移动端,再相应的展示不同的View
HandlerMapping(重点)
处理器匹配映射,也是MVC中的重点知识之一,存储的其实就是请求和Handler之间的映射关系,会根据请求获得对应的Handler和HandlerInterceptor数组包装成HandlerExecutionChain返回
HandlerAdapter(重点)
处理器适配器,因为传入到HandlerAdapter的Handler是一个Object,而适配器其实只是实现了一个调用的过程,类似一个invoker,它会把Handler转换成一个HandlerMethod去参与invokeHandlerMethod()方法的逻辑处理,最后返回一个ModelAndView
HandlerExceptionResolver(重点)
处理器异常解析器,它会把Handler执行时发生的异常,解析成对应的 ModelAndView 结果并返回
RequestToViewNameTranslator
请求到View的转换器,也就是那个请求对应那个view
ViewResolver
view解析器,它会根据视图名和国际化获取到最终的View对象,针对不同类型的View有相应的实现类去实现,比如说解析JSP的InternalResourceViewResolver 和解析Freemarker的FreeMarkerViewResolver等等
FlashMapManager
FlashMap 管理器,负责重定向时的处理,基本就是先把参数信息保存到session中,然后重定向之后再从session里边获取出来用,用完再删了.
3.2 SpringMVC的工作原理
]
4. SpringMVC的异常处理
SpringMVC提供了ExceptionHandler来解决异常,主要是通过@ExceptionHandler和@ControllerAdvice注解完成的,@ExceptionHandler的使用方式一般都是作用在方法上,而@ControllerAdvice一般是用来做全局的,它会捕获Controller所有抛出的异常,作用在类上,然后针对不同的异常在这个类中在使用@ExceptionHandler去单独处理,
Spring Transaction
事务
ACID四大特性
特性 | 含义 |
---|---|
A (原子性) | 事务是原子操作,要么全部执行成功,要么全部失败 |
C (一致性) | 事务执行前后的数据应该是一致的 |
I (隔离性) | 事务与事务之间是不可见的 |
D (持久性) | 事务执行之后对数据的修改是永久性的,即使系统故障也不会丢失 |
事务的隔离级别 | 解释 | 需要的锁 | 介绍 |
---|---|---|---|
读未提交 | 只限制同一数据写事务禁止其他写事务。解决”更新丢失”。(一事务写时禁止其他事务写) | 排他写锁 | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
读已提交 | 只限制同一数据写事务禁止其它读写事务。解决”脏读”,以及”更新丢失”。(一事务写时禁止其他事务读写) | 排他写锁、瞬间共享读锁 | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
可重复读 | 限制同一数据写事务禁止其他读写事务,读事务禁止其它写事务(允许读)。解决”不可重复读”,以及”更新丢失”和”脏读”。(一事务写时禁止其他事务读写、一事务读时禁止其他事务写) | 排他写锁、共享读锁 | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 |
串行化 | 限制所有读写事务都必须串行化实行。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。(一事务写时禁止其他事务读写、一事务读时禁止其他事务读写) | 范围锁或表锁 | 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 |
事务的隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 存在 | 存在 | 存在 |
读已提交 | 不存在 | 存在 | 存在 |
可重复读 | 不存在 | 不存在 | 存在 |
串行化 | 不存在 | 不存在 | 不存在 |
安全问题 | 解释 |
---|---|
脏读 | 事务B读取到事务A修改了但是还未提交的数据,之后事务A又回滚其更新操作,导致事务B读到的是脏数据 |
不可重复读 | 事务A读取某个数据后,事务B对其做了修改,当事务A再次读该数据时得到与前一次的值不一样了,多发生于更新 |
幻读 | 事务A在读取某范围数据时,事务B又插入一条数据,当事务A再次数据这个范围数据时发现不一样了,数据量变了,多发生于插入 |