Spring八股文

目录

重点

描述一下bean的生命周期

Spring Bean 的作用域都有哪些?如何控制 Bean 的生命周期?

谈谈Spring IOC的理解,原理与实现

谈一下spring IOC的底层实现

Spring的AOP的底层实现原理

拓展

Spring是如何解决循环依赖的问题的?

Spring的事务是如何回滚的?

谈一下spring事务传播?

Bean Factory与FactoryBean有什么区别?

缓存的放置时间和删除时间

Spring中用到的设计模式


重点

描述一下bean的生命周期

简述版

  • 实例化:调用构造器 或者是通过工厂的方式创建Bean对象
  • 属性赋值:给bean对象的属性注入值
  • 初始化:调用初始化方法,进行初始化, 初始化方法是通过init-method来指定的.
  • 使用
  • IOC容器关闭时, 销毁Bean对象

详细:

1. 实例化 Bean ,反射的方式生成对象
2. 填充 bena 的属性: populateBean(), 循环依赖的问题 ( 三级缓存 )
3.初始化
1) Aware接口回调
invokeAwareMethod( 完成 BeanName 可以获取容器 bean 的名称,
BeanFactory 获取当前 bean factory 这也可以调用容器的服务, BeanClassLoader 对象的属性设置 )
2). BeanPostProcessor前置处理(postProcessBeforeInitialization)
使用比较多的有 (ApplicationContextPostProcessor 设 置ApplicationContext Environment,ResourceLoader,EmbeddValueResolver 等对象 )
3). InitializingBean的afterPropertiesSet() :
判断是否实现了 InitializingBean 接口,如果有,调用afterPropertiesSet方法
4)、 自定义init方法(init-method):
如果在配置文件中定义了 init-method 属性,容器将调用这个自定义的初始化方法。
5). BeanPostProcessor后置处理(postProcessAfterInitialization)
spring aop 就是在此处实现的, AbstractAutoProxyCreator 注册Destuction相关的回调接口
4. 获取到完整的对象,可以通过 getBean 的方式来进行对象的获取
5. 销毁流程
1)判断是否实现了 DispoableBean 接口
如果 bean 实现了 DisposableBean 接口,容器将调用 destroy() 方法
2)调用 destroyMethod 方法
如果在配置文件中定义了 destroy-method 属性,容器将调用这个自定义的销毁方法。

Spring Bean 的作用域都有哪些?如何控制 Bean 的生命周期?


Singleton(单例)
描述: 默认作用域。Spring容器中只创建一个Bean实例,并在整个容器中共享这个实例。
生命周期: 从容器启动到容器关闭期间,Bean实例始终存在。
Prototype(原型)
描述: 每次请求都会创建一个新的Bean实例。每个实例都有独立的生命周期。
生命周期: 每次获取Bean时,都会创建一个新的实例。Bean的生命周期从创建开始,到被垃圾回收时结束。
Request(请求)
描述: 每个HTTP请求都会创建一个新的Bean实例。Bean的生命周期与HTTP请求相对应。
生命周期: 从每个HTTP请求开始到请求结束,每次请求都会创建一个新的Bean实例。
Session(会话)
描述: 每个HTTP会话创建一个新的Bean实例。Bean的生命周期与HTTP会话相对应。
生命周期: 从每个HTTP会话开始到会话结束,每个会话都有一个独立的Bean实例。
GlobalSession(全局会话)
描述: 在Portlet环境中使用。每个全局会话创建一个新的Bean实例。
生命周期: 适用于Portlet应用中的全局会话,每个全局会话有一个独立的Bean实例。

谈谈Spring IOC的理解,原理与实现

控制反转:理论思想,它把传统的对象创建和依赖的管理放在了容器中,由容器控制对象的生命周期,对象与对象之间的关系由容器来管理,也就是说控制权由程序员转移到了容器上。
DIIOC的实现依赖于DI(Dependency Injection,依赖注入),IOC容器负责创建对象,并管理对象之间的依赖关系,这些类之间的依赖关系配置在配置文件中,容器通过配置文件来动态注入依赖关系
容器 :存储对象,使用 map 结构来存储,在 spring 中一般存在三级缓存, singletonObjeacts 存放完整的 bean对象,整个 bean 的生命周期,从创建到使用到销毁的过程全部都是由容器来管理的 (bean 的生命周期)
spring 中的 bean 都是通过反射的方式生成的,同时其中包含了很多的扩展点( 对占位符的处理 ) ,比如最常用的对 BeanFactory 的扩展,对 bean 的扩展,我们在公司对这方面的 使用是比较多的,除此之外,ioc 中最核心的也就是填充具体 bean 的属性,和生命周期

谈一下spring IOC的底层实现

1. 先通过 createBeanFactory 创建一个 Bean 工厂 (DefaultListableBeanFactory)
2. 开始循环创建对象,因为容器中的 bean 默认都是单例的,所以优先通过 getBean doGetBean 从容器 中查找,找不到的话,
3. 通过 createBean doCreateBean 方法,以反射的方式创建对象,一般情况下使用的是无参的构造器 (getDeclaredConstructor(),newinstance)
4. 进行对象的属性填充 populateBean
5. 进行其他的初始化操作 (initializingBean)

SpringAOP的底层实现原理

aop概念,应用场景,动态代理

aop概念:

面向切面编程,是一种将非业务代码与业务代码进行分离的一种思想

应用场景:

日志记录(Logging):在方法调用前后记录日志信息,用于跟踪方法执行情况、性能监控或调试。
权限检查(Security/Authorization):在方法执行前验证用户是否有权限执行该操作,比如角色检查或资源访问控制。
事务管理(Transaction Management):自动管理数据库事务的开启、提交或回滚,保证数据的一致性。
异常处理(Exception Handling):集中处理特定类型的异常,比如记录异常信息或执行特定的恢复操作。

动态代理:

AOP底层实现原理是动态代理(JDK动态代理+CGLIB动态代理),就是在不修改原有类对象方法的源代码基础上,通过代理对象实现对原有类对象方法的增强,也就是拓展原有类对象的功能。

拓展

Spring是如何解决循环依赖的问题的?

Spring 解决循环依赖的关键在于提前暴露一个已构造但未初始化的对象,从而允许其他对象引用它,并在全部对象构造完成后再进行初始化,。

1、Spring 三级缓存:

一级缓存 : Map<String,Object> singletonObjects ,单例池,用于保存实例化、属
性赋值(注入)、初始化完成的 bean 实例
二级缓存 : Map<String,Object> earlySingletonObjects ,早期曝光对象,用于保存
实例化完成的 bean 实例
三级缓存 : Map<String,ObjectFactory<?>> singletonFactories ,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

2、A、B实例循环依赖,他们的初始化过程:


1. 创建A实例,实例化的时候把A对象⼯⼚放⼊三级缓存,表示A开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道


2. A注⼊属性时,发现依赖B,此时B还没有被创建出来,所以去实例化B


3. 同样,B注⼊属性时发现依赖A,它就会从缓存里找A对象。依次从⼀级到三级缓存查询A从三级缓存通过对象⼯⼚拿到A,发现A虽然不太完善,但是存在,把A放⼊⼆级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入⼀级缓存


4. 接着A继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除⼆级缓存中的A,同时把A放⼊⼀级缓存


5. 最后,⼀级缓存中保存着实例化、初始化都完成的A、B对象

3、为什么使用三级缓存不适用⼆级缓存?

主要是为了⽣成代理对象。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。


因为三级缓存中放的是⽣成具体对象的匿名内部类,获取Object的时候,它可以⽣成代理对象,也可以返回普通对象。使⽤三级缓存主要是为了保证不管什么时候使⽤的都是⼀个对象。


假设只有⼆级缓存的情况,往⼆级缓存中放的显示⼀个普通的Bean对象,Bean初始化过程中,通过 BeanPostProcessor 去⽣成代理对象之后,覆盖掉⼆级缓存中的普通Bean对象,那么可能就导致取到的Bean对象不一致了。

Spring的事务是如何回滚的?

spring 的事务管理是如何实现的?
总: spring 的事务是由 aop 来实现的,首先要生成具体的代理对象,然后按照 aop 的整套流程来执行具体 的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知实现的,而是通过一个 TransactionInterceptor来实现的,然后调用 invoke 来实现具体的逻辑
分:
1. 先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
2. 当需要开启的时候,获取数据库连接,关闭自动提交功能,开启事务
3. 执行具体的 sql 逻辑操作
4. 在操作过程中,如果执行失败了,那么会通过 completeTransactionAfterThrowing 看来完成事务
的回滚操作,回滚的具体逻辑是通过 doRollBack 方法来实现的,实现的时候也是要先获取链接对象,通 过连接对象来回滚。
5. 如果执行过程中,没有任何意外情况的发生,那么通过 commitTransactionAfterReturning 来完
成事务的提交操作,提交的具体逻辑是通过 doCommit 方法来实现的,实现的时候也要获取链接,通过 链接对象来提交
6. 当事务执行完毕之后需要清除相关的事务信息 cleanupTransactionInfo
如果想要聊的更加细致的话,需要知道 TransactionInfo TransactionsStatus

谈一下spring事务传播?

传播特性有几种?七种
Required Requireds_new,nested,Support,Not_Support,Never,Mandatory
某一个事务嵌套另外一个事务的时候怎么办?
A 方法调用 B 方法, AB 方法都有事务,并且传播特性不同,那么 A 如果有异常, B 怎么办, B 如果有异常, A怎么办?
:事务的传播特性指的是不同方法的嵌套调用过程中,事务该如何进行处理,是同一个事务还是不同 的事务,当出现异常的时候会回滚还是提交,两个方法之间相互影响,在日常工作中,使用比较多的是 required, Requireds_new
1. 先说事务的不同分类,可以分为三类,支持当前事务,不支持当前事务,嵌套事务
2. 如果外层方法是 required ,内层方法是: required requireds_new,nested
3. 如果外层方法是 requireds_new ,内层方法是: required requireds_new,nested
4. 如果外层方法是 nested ,内层方法是: required requireds_new,nested
核心处理逻辑非常简单:
1. 判断内外方法是否是同一事务:
是:异常统一在外层方法处理
不是:内层方法有可能影响到外层方法,但是外层方法是不会影响内层方法的
(大致可以这么理解,但是有个别情况不同, nested

Bean FactoryFactoryBean有什么区别?

相同点:都是用来创建 bean 对象的
不同点:使用 BeanFactory 创建对象的时候,必须要遵循严格的生命周期流程,太复杂了,如果想要简 单的自定义某个对象的创建,同时创建完成的对象想交给spring来管理,那么就需要实现 FactoryBean 接口了它的方法
isSingleton :是否是单例对象
getObjectType :获取返回对象的类型
getObject :自定义创建对象的过程 (new, 反射 , 动态代理 )

缓存的放置时间和删除时间

三级缓存: CreateBeanInstance 之后: addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是不同对象的时候,同时删除三级缓存
getSingleton
一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存: addSingleton

Spring中用到的设计模式

单例模式: bean 默认都是单例的
原型模式:指定作用域为 prototype
工厂模式: BeanFactory
模板模式: postProcessBeanFactory onRefresh initPropertyValue
策略模式: XmlBeanDefinitionReader PropertiesBeanDefinitionReader
观察者模式: listener event multicast
适配器模式: Adapter
装饰者模式: BeanWrapper
责任链模式:使用 aop 的时候会生成一个拦截器
代理模式:动态代理
委托者模式: delegate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值