你真正了解Spring的工作原理吗
Spring
1.1 什么是Spring IOC 和DI ?
① 控制反转(IOC):Spring容器使用了工厂模式为我们创建了所需要的对象,我
们使用时不需要自己去创建,直接调用Spring为我们提供的对象即可,这就是控
制反转的思想。
② 依赖注入(DI):Spring使用Java Bean对象的Set方法或者带参数的构造方法为
我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的基本
思想。
1.2 有哪些不同类型的依赖注入实现方式?
依赖注入分为Setter方 法注入和构造器注入
构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类
有一系列参数,每 个参数代表一个对其他类的依赖。
Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方
法实例化bean之 后,调用该bean的setter方法,即实现了基于setter的依赖注
入。
1.3 Spring支持的几种bean的作用域
Spring框架支持以下五种bean的作用域:
singleton : bean在每个Spring ioc 容器中只有一个实例。
prototype:一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的 Spring ApplicationContext情形下有效。
application:属于应用程序域,应用程序启动时bean创建,应用程序销毁时bean销毁。该作用域仅在基于web的ServletContext.
1.4 Spring框架中的单例bean是线程安全的吗?
不是线程安全的
当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线
程会并发执行该请求对应的业务逻辑(成员方法),如果该处理逻辑中有对该单
列状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程
安全和并发问题需要开发者自行去搞定。
Spring bean并没有可变的状态(比如Service类和DAO类),所以在某种程度上说
Spring的单例bean是线程安全的。
如果你的bean有多种状态的话(比如 View Model对象),就需要自行保证线程
安全。最浅显的解决办法就是将多态bean的作用由“singleton”变更为
“prototype”。
1.5 Spring自动装配 bean 有哪些方式?
spring的自动装配功能的定义:无须在Spring配置文件中描述javaBean之间的依
赖关系(如配置 <property>、<constructor-arg> )。
自动装配模式:
1、no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需
要自行在 bean 定义中用标签明确的设置依赖关系 。
2、byName:该选项可以根据bean名称设置依赖关系 。 当向一个bean中自动装
配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的
bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。
3、byType:该选项可以根据 bean 类型设置依赖关系 。 当向一个 bean 中自动
装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的
bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。
4、constructor :构造器的自动装配和byType模式类似,但是仅仅适用于与有构
造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean ,
那么将会抛出异常 。
5、default:该模式自动探测使用构造器自动装配或者byType自动装配 。 首先会
尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在
bean内部没有找到相应的 构造器或者是无参构造器,容器就会自动选择 byTpe
的自动装配方式 。
比如如下注入 :

可以改造为:

1.6 你用过哪些重要的Spring注解?
1、@Component- 用于服务类
@Service
@Repository
@Controller
2、@Autowired - 用于在 spring bean 中自动装配依赖项。通过类型来实现自动
注入bean。和@Qualifier注解配合使用可以实现根据name注入bean。
3、@Qualifier - 和@Autowired一块使用,在同一类型的bean有多个的情况下可
以实现根据name注入的需求。
4、@Scope - 用于配置 spring bean 的范围。
5、@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。
6、@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)
1.7 Spring中的事务是如何实现的
Spring支持编程式事务管理和声明式事务管理两种方式!
编程式事务控制:需要使用TransactionTemplate来进行实现,这种方式实现对业
务代码有侵入性,因此在项目中很少被使用到。
声明式事务管理:声明式事务管理建立在AOP之上的。其本质是通过AOP功能,
对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在
目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者
回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需
在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可
以将事务规则应用到业务逻辑中。
1.8 Spring中事务失效的场景?
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有
是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是目标对象调用, 那
么@Transactional会失效
同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是
基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的
利⽤代理,也会导致@Transactianal失效
如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常,
@Transactional也会失效
@Transactional中的配置的Rollback的默认是异常是:runTimeException,更改为
Spring的事务传播行为 Exception
1. PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当
前存在事务,就 加入该事务,该设置是最常用的设置。
2. PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事
务,如果当前不 存在事务,就以非事务执行。
3. PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该
事务,如果当前 不存在事务,就抛出异常。
4. PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创
建新事务。
5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事
务,就把当前 事务挂起。
6. PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异
常。
7. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当
前没有事务,则 按REQUIRED属性执行
1.10 什么是AOP , 你们项目中有没有使用到AOP
AOP一般称为面向切面编程,作为面向对象的一种补充,用于 将那些与业务无
关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模
块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块
间的耦合度,同时 提高了系统的可维护性。
在我们的项目中我们自己写AOP的场景其实很少 , 但是我们使用的很多框架的功
能底层都是AOP , 例如 :
1、统一日志处理
2、spring中内置的事务处理
记录操作日志
需求:是谁,在什么时间,修改了数据(修改之前和修改之后),删除了什
么数据,新增了什么数据
要求:方法命名要规范
实现步骤:
1,定义切面类
2,使用环绕通知,根据方法名和参数,记录到表中
1.11 JDK动态代理和CGLIB动态代理的区别
Spring中AOP底层的实现是基于动态代理进行实现的。
常见的动态代理技术有两种:JDK的动态代理和CGLIB。
两者的区别如下所示:
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类
2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
进行增强,但是因为采用的是继承,所以该类或方法最好不要声明为final,对于
final类或方法,是无法继承的。
Spring如何选择是用JDK还是cglib?
1、当bean实现接口时,会用JDK代理模式
2、当bean没有实现接口,会用cglib实现
3、可以强制使用cglib
在springboot项目可以配置以下注解,强制使用cglib
@EnableAspectJAutoProxy(proxyTargetClass = true)

spring的bean的生命周期
bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可
以总结为以下七个阶段:
1. 处理名称,检查缓存
2. 处理父子容器
3. 处理 dependsOn
4. 选择 scope 策略
5. 创建 bean (关键阶段)
6. 类型转换处理
7. 销毁 bean

spring框架在创建的bean的时候都会调用AbstractBeanFactory类中的doGetBean
方法
1. 处理名称,检查缓存
这一步会处理别名,将别名解析为实际名称
对 FactoryBean 也会特殊处理,如果以 & 开头表示要获取 FactoryBean 本身,否则表示要获取其产品
这里针对单例对象会检查一级、二级、三级缓存
singletonFactories 三级缓存,存放单例工厂对象
earlySingletonObjects 二级缓存,存放单例工厂的产品对象
如果发生循环依赖,产品是代理;无循环依赖,产品是原始对象
singletonObjects 一级缓存,存放单例成品对象
2. 处理父子容器
如果当前容器根据名字找不到这个 bean,此时若父容器存在,则执行父容器的 getBean 流程
父子容器的 bean 名称可以重复
3. 处理 dependsOn
如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean,这一步会提前创建这些 dependsOn 的 bean
所谓非显式依赖,就是指两个 bean 之间不存在直接依赖关系,但需要控制它们的创建先后顺序
4. 选择 scope 策略
对于 singleton scope,首先到单例池去获取 bean,如果有则直接返回,没有再进入创建流程
对于 prototype scope,每次都会进入创建流程
对于自定义 scope,例如 request,首先到 request 域获取 bean,如果有则直接返回,没有再进入创建流程
5.1 创建 bean - 创建 bean 实例
| 要点 | 总结 |
| AutowiredAnnotationB eanPostProcessor |
① 优先选择带 @Autowired 注解的构造;② 若有 唯一的带参构造,也会入选 |
| 采用默认构造 | 如果上面的后处理器和 BeanDefiniation 都没找到构 造,采用默认构造,即使是私有的 |
5.2 创建 bean - 依赖注入
| 要点 | 总结 |
| AutowiredAnnotation BeanPostProcessor |
识别 @Autowired 及 @Value 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
| CommonAnnotationBe anPostProcessor |
识别 @Resource 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
| AUTOWIRE_BY_NAME | 根据成员名字找 bean 对象,修改 mbd 的 propertyValues,不会考虑简单类型的成员 |
| AUTOWIRE_BY_TYPE | 根据成员类型执行 resolveDependency 找到依赖注入 的值,修改 mbd 的 propertyValues |
| 要点 | 总结 |
| applyPropertyValues | 根据 mbd 的 propertyValues 进行依赖注入(即xml中 <property name ref|value/>) |
5.3 创建 bean - 初始化
| 要点 | 总结 |
| 内置 Aware 接口的装配 |
包括 BeanNameAware,BeanFactoryAware 等 |
| 扩展 Aware 接口的装配 |
由 ApplicationContextAwareProcessor 解析,执行时机在 postProcessBeforeInitialization |
| @PostConstr uct |
由 CommonAnnotationBeanPostProcessor 解析,执行时机在 postProcessBeforeInitialization |
| InitializingBe an |
通过接口回调执行初始化 |
| initMethod | 根据 BeanDefinition 得到的初始化方法执行初始化,即 <bean init-method> 或 @Bean(initMethod) |
| 创建 aop 代 理 |
由 AnnotationAwareAspectJAutoProxyCreator 创建,执行时机 在 postProcessAfterInitialization |
5.4 创建 bean - 注册可销毁 bean
在这一步判断并登记可销毁 bean
判断依据
如果实现了 DisposableBean 或 AutoCloseable 接口,则为可销毁 bean
如果自定义了 destroyMethod,则为可销毁 bean
如果采用 @Bean 没有指定 destroyMethod,则采用自动推断方式获取销毁
方法名(close,shutdown)
如果有 @PreDestroy 标注的方法
存储位置
singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中
自定义 scope 的可销毁 bean 会存储于对应的域对象当中
prototype scope 不会存储,需要自己找到此对象销毁
存储时都会封装为 DisposableBeanAdapter 类型对销毁方法的调用进行适配
6. 类型转换处理
如果 getBean 的 requiredType 参数与实际得到的对象类型不同,会尝试进行
类型转换
7. 销毁 bean
销毁时机
singleton bean 的销毁在 ApplicationContext.close 时,此时会找到所有
DisposableBean 的名字,逐一销毁
自定义 scope bean 的销毁在作用域对象生命周期结束时
prototype bean 的销毁可以通过自己手动调用
AutowireCapableBeanFactory.destroyBean 方法执行销毁
同一 bean 中不同形式销毁方法的调用次序
优先后处理器销毁,即 @PreDestroy
其次 DisposableBean 接口销毁
最后 destroyMethod 销毁(包括自定义名称,推断名称,AutoCloseable 接
口 多选一)
你真正了解Spring的工作原理吗的更多相关文章
- Spring MVC工作原理(好用版)
Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...
- Spring Session工作原理
本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/KCOFv0nRuymkX79-RZi9eg 作者:张正林 目录:1.引入背景2.使用方法3.工作流程 ...
- Struts1、Struts2、Hibernate、Spring框架工作原理介绍
Struts1工作原理 Struts1工作原理图 1.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控 ...
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
- Spring MVC工作原理及源码解析(一) MVC原理介绍、与IOC容器整合原理
MVC原理介绍 Spring MVC原理图 上图是Spring MVC工作原理图(图片来自网上搜索),根据上图,我们可以得知Spring MVC的工作流程如下: 1.用户(客户端,即浏览器)发送请求至 ...
- 深入理解Spring IOC工作原理
为什么会出现spring,spring出现解决了什么问题? 1.分析普通多层架构存在的问题 JSP->Servlet->Service->Dao 层与层之间的依赖很强,属于耦合而且是 ...
- Spring MVC工作原理 及注解说明
SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...
- Spring的工作原理核心组件和应用
Spring框架 Spring 是管理多个java类的容器框架,注意是类不管理接口. Spring 的主要功能 Ioc 反转控制和 DI 依赖注入. 注入的方式可以是构造函数赋值也可以是 set方法赋 ...
- 简述spring的工作原理
建议不要硬着头皮看spring代码,本身的代码800多m,就是不上班开始看也不知道什么时候看完.如果想学学ioc,控制反转这些建议看看jodd项目,比较简练,但是我仍然不建议过多的看这些框架的代码,因 ...
- Java:Spring @Transactional工作原理
本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的.之后的文章将介绍: propagation(事务传播)和isolation(隔离性)等属性的使用 事务使用 ...
随机推荐
- oss/obs对象存储上传图片,在浏览器输入地址却是下载图片。不能直接在浏览器上查看。
1.问题oss/obs对象存储上传图片获取链接地址后,在浏览器输入地址却是下载.不能直接在浏览器上面浏览图片信息.2.解决上传文件的时候需要设置:content-type类型,需要指示浏览器这是什么类 ...
- JS 打开本地应用软件
我们有遇到可以直接打开QQ的跳转链接,也有遇到过直接启动office打开文档. 具体是如何操作的呢? 添加注册表项 首先需要在注册表中添加应用软件的启动地址,操作方式如下 在HKEY_CLASSES_ ...
- 深入理解 slab cache 内存分配全链路实现
本文源码部分基于内核 5.4 版本讨论 在经过上篇文章 <从内核源码看 slab 内存池的创建初始化流程> 的介绍之后,我们最终得到下面这幅 slab cache 的完整架构图: 本文笔者 ...
- 云原生时代崛起的编程语言Go常用标准库实战
@ 目录 基础标准库 简述 字符串-string 底层结构 函数 长度 格式化输出 模版-template text/template html/template 正则表达式-regexp 编码-en ...
- 【开源游戏】Legends-Of-Heroes 基于ET 7.2的双端C#(.net7 + Unity3d)多人在线英雄联盟风格的球球大作战游戏。
Legends-Of-Heroes 一个LOL风格的球球大作战游戏,基于ET7.2,使用状态同步 Main 基于C#双端框架[ET7.2],同步到ET主干详情请看日志.(https://github ...
- 一文快速入门体验 Hibernate
前言 Hibernate 是一个优秀的持久层的框架,当然,虽然现在说用得比较多的是 MyBaits,但是我工作中也不得不接触 Hibernate,特别是一些老项目需要你维护的时候.所以,在此写下这篇文 ...
- pg数据库的备份和恢复以及sql脚本错误的解决方法
1.备份单库单表的数据,以insert语句的方式 pg_dump -h IP -p 端口 -U 用户名 -t 表名 --inserts –f dbname.sql 数据库名 pg_dump -h 17 ...
- 2022-08-01:以下go语言代码输出什么?A:panic;B:5;C:6;D:编译错误。 package main import ( “fmt“ ) func main() {
2022-08-01:以下go语言代码输出什么?A:panic:B:5:C:6:D:编译错误. package main import ( "fmt" ) func main() ...
- 2015年蓝桥杯C/C++大学B组省赛真题(星系炸弹)
题目描述: 在X星系的广袤空间中漂浮着许多X星人造"炸弹",用来作为宇宙中的路标. 每个炸弹都可以设定多少天之后爆炸. 比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在 ...
- 2013年蓝桥杯C/C++大学B组省赛真题(第39级台阶)
题目描述: 小明刚刚看完电影<第39级台阶>,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级! 站在台阶前,他突然又想着一个问题: 如果我每一步只能迈上1个或2个台阶.先迈左脚,然 ...