Spring 常见问题( 持续更新... ... )

Spring 常见问题


1. Spring循环依赖相关问题

	spring三层缓存的第二层缓存有什么用?
	循环依赖为什么要使用三级缓存?二级不能解决么?beanB从三级缓存中获取beanA以后提升到二级缓存 ?
	循环依赖涉及二级缓存具体作用是什么,一般不用二级缓存也能实现?
	为什么spring无法处理基于构造器的循环依赖问题?
	二级缓存为什么要放入代理对象?直接放入三级缓存中未成形对象不可以嘛?
Spring中循环依赖场景有:
	构造器的循环依赖(构造器注⼊)
	Field 属性的循环依赖(set注⼊)

其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring采⽤的是 提前暴露对象 的⽅法。

Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前。

Spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决循环依赖问题
三个缓存其实就是三个Map:
在这里插入图片描述

解答:三个缓存 各司其职(鸡蛋不要放到一个篮子里),面向对象设计的原则,就是这么设计的!
	将成型的bean和不成形的bean分开,分别存储

	一级存储:存储成型的bean
	二级缓存:存储不成形的bean,未来可以存储增强后得bean
			三级缓存是不成形得bean,在三级缓存向二级缓存存储bean得时候,可以执行增强操作,获取bean得代理对象
	三级缓存:存储数据形式<key , 工厂> 的形式
例如:
	A对象,对A对象进行了AOP增强
	B对象
ioc实例化bean过程:

具体源码剖析流程参考:Spring循环依赖源码剖析


2. SpringBean的生命周期

Bean ⽣命周期的整个执⾏过程描述:

  1. 根据配置情况调⽤ Bean 构造⽅法或⼯⼚⽅法实例化 Bean。
  2. 利⽤依赖注⼊完成 Bean 中所有属性值的配置注⼊。
  3. 如果 Bean 实现了 BeanNameAware 接⼝,则 Spring 调⽤ Bean 的 setBeanName() ⽅法传⼊当前 Bean 的 id 值。
  4. 如果 Bean 实现了 BeanFactoryAware 接⼝,则 Spring 调⽤ setBeanFactory() ⽅法传⼊当前⼯⼚实例的引⽤。
  5. 如果 Bean 实现了 ApplicationContextAware 接⼝,则 Spring 调⽤ setApplicationContext() ⽅法传⼊
    当前 ApplicationContext 实例的引⽤。
  6. 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的预初始化⽅法
    postProcessBeforeInitialzation() 对 Bean 进⾏加⼯操作,此处⾮常重要,Spring 的 AOP 就是利⽤它实现的。
  7. 如果 Bean 实现了 InitializingBean 接⼝,则 Spring 将调⽤ afterPropertiesSet() ⽅法。
  8. 如果在配置⽂件中通过 init-method 属性指定了初始化⽅法,则调⽤该初始化⽅法。
  9. 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的初始化⽅法 postProcessAfterInitialization()。
    此时,Bean 已经可以被应⽤系统使⽤了。
  10. 如果在 中指定了该 Bean 的作⽤范围为 scope=“singleton”,则将该 Bean 放⼊ Spring IoC 的缓存池中,
    将触发 Spring 对该 Bean 的⽣命周期管理;如果在 中指定了该 Bean 的作⽤范围为 scope=“prototype”,则将该 Bean 交给调⽤者,调⽤者管理该 Bean 的⽣命周期,Spring 不再管理该 Bean。
  11. 如果 Bean 实现了 DisposableBean 接⼝,则 Spring 会调⽤ destory() ⽅法将 Spring 中的 Bean 销毁;
    如果在配置⽂件中通过 destory-method 属性指定了 Bean 的销毁⽅法,则 Spring 将调⽤该⽅法对 Bean 进⾏销毁。
    注意:Spring 为 Bean 提供了细致全⾯的⽣命周期过程,通过实现特定的接⼝或 的属性设置,都可以对 Bean 的⽣命周期过程产⽣影响。
    虽然可以随意配置 的属性,但是建议不要过多地使⽤ Bean 实现接⼝,因为这样会导致代码和 Spring 的聚合过于紧密

在这里插入图片描述


3. Spring是如何对XXXService进行依赖注入的(Service没有set方法和构造方法)

反射的方式


4. spring源码分析中核心流程有哪些?面试的或工作中写代码能借鉴的

容器初始化流程
循环依赖流程


5. bean中如果又多个构造方法,容器初始化的时候要怎么去选择?

选择无参构造器,必须有无参构造器


6. Spring源码类名都很长,如何记住层层调用关系?面试提问源码问题一般细到什么层级?

了解机制原理/流程即可、不问类名


7. set方式注入时,property标签里面的name属性是需要注入的类名还是属性名,跟同事争论了很久,官方文档是写的属性名,但是老师讲的例子里面是写的类名,很困惑

setXXX中的XXX,其实不是属性名称和类名称


8. static方法和单例实例方法在内存中有什么区别,分别在什么情况下使用?单例的实例方法在多线程访问时是否有性能瓶颈?

静态方法在类加载的时候就创建了,实例方法当对象实例化的时候才去占用内存
static方法区占用内存区域有限(连续占用内存区域,执行性能稍高),太多会影响性能
实例方法是离散分布的

一般工具方法都设置成static

单例的实例方法在多线程访问时 如果存在成员变量、操作了成员变量,考虑到锁的时候,就影响性能


9. Spring容器里的单例bean如果有非静态成员变量int a=0,业务方法中会改变a的值,那么第二次调用该bean的时候a的初始值还是0吗?

不是


10. Spring容器在初始化一个bean的时候会做那些事情,顺序是怎样的,在容器关闭的时候,又会做哪些事情在这里插入图片描述

在spring的BeanFactory工厂列举了很多接口,代表着bean的生命周期,我们主要记住的是我圈红线圈出来的接口, 再结合spring的源码来看这些接口主要是在哪里调用的


14. Spring事务失效场景及原理

1)吃异常
2)数据库引擎不支持事务
3)非public方法
4)调用同类的方法 等


15. 自定义依赖注入注解不是很清楚

注解就是一个标记,不同的标记表明我们要针对类、字段、或者方法做一些什么事情


16. spring源码中总共用到了哪些设计模式,具体体现在哪?

在这里插入图片描述


17. 单例 多个线程取去会怎么样?

如果单例中操作成员变量,会造成并发问题


18. 如果autowired注入时使用的是接口,如何在ioc容器中定位实现类

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

按照名称和类型


19. 如何自定义一款spring的插件,比如做一个通用的权限拦截,然后根据用户的登录信息去用户中心查看是否有权限,在sprinng加载的时候,就把该插件加载进去?然后业务代码中这块完全不写可以做到吗?

说的这个就是SpringMVC拦截器

定义拦截器,注册到容器中


20. 事务的超时这个地方是怎么控制的?

timeout


21. Spring 循环注入有什么好处

是个问题,而非好处,我们尽量避免这种情况发生


22. 为什么不能将对象注入到servlet

bean对象在spring容器中,servlet在servlet容器中;

  1. 可以通过Spring暴露的接口方法,WebApplicationContextUtils.getWebApplicationContext获取到容器,然后getBean
  2. 也可以使用@Autowired,但是需要做一些配置
public void init() throws ServletException {
        WebApplicationContextUtils
                .getWebApplicationContext(getServletContext())
                .getAutowireCapableBeanFactory().autowireBean(this);
    }

23. 自定义注解实现动态代理,怎么作用于方法上边

对象是类的对象,方法级别控制直接在Invoke方法中判断Method是否有相应注解即可


24. PROPAGATION_NESTED 嵌套事务什么意思

PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务。潜套事务开始执行时, 它将取得一个 savepoint
如果这个嵌套事务失败, 我们将回滚到此 savepoint。潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交
如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于回滚.


25. spring多例模式管理的bean是用户获取的时候才去初始化,那么这种方式和new出来的实例有什么区别,相比而言有哪些优势

无对比性,spring ioc是管理单例对象,多例模式只是为了支持可能的其他需求


26. 容器为什么要设计@Compoment, @Repository, @Service, 只用一个注解实现不是更好管理吗?

为了让我们更方便的按层次管理代码

27. spring的单例Bean是线程安全的吗?

不是,在bean中如果维护了成员变量,请自行控制其并发访问
可以通过参数传递去避免比较好

28. servlet是单例模式,为什么doGet和doPost不需要synchronized修饰?单例如何保证高并发时的性能?(假如存在实例变量)

servlet本身没有替我们考虑线程安全问题,需要我们自己考虑

  1. 避免使用实例变量(推荐)
  2. synchronized同步 / ThreadLocal
  3. 实现SingleThreadModel 接口

最好避免使用成员变量(设计的角度)

29. 事务从手写改为动态代理,转账时执行了两次Update,第一次执行的时候代理对象会提交了事务,第二次执行Update时,出现了问题第一次的Update已经提交了就不能回滚了吧?

第一次的并没有提交,同一个事务

30. 能不能给我们讲讲大型互联网企业在使用spring国际化的一些经验

国内使用国际化较少
前端页面 /spring国际化 / 后台实现 /单独写一套/ 等方案

31. "spring在进行初始化beanDefinition的时候,是否对每一个加上@Component或者@Service等注解的类,都保留了既可以根据该类的类型得到bean对象,又可以根据该类的名称得到bean对象,也可以根据该类的自定义注解名得到该对象?

实际不需要存储两台,存储两套是一种实现的方式

32. TransactionStatus这个类具体有啥用?

查看事务的状态

33. 分布式事物该怎么去实现,大致思路是什么怎么控制

思路:外围启动一个大事务,包含很多小的事务;最终大事务的提交与否,需要依靠各个小事务来决定

比如阿里的seata: (分布式事务的一种解决方案)
Seata 的设计思路是将一个分布式事务可以理解成一个全局事务,下面挂了若干个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。
Seata 内部定义了 3个模块来处理全局事务和分支事务的关系和处理过程,这三个组件分别是:
Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
Transaction Manager ™: 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

34. spring应用如此广泛,那么他有哪些不足,或者说我们在哪些业务场景可以不考虑spring

小型项目引入Spring增加了复杂度
核心功能基于容器
一旦引入spring,和它的耦合就会很大

35. 由于现在接触的都是传统的垂直架构系统,知道spring这样用,在大型分布式系统中spring是怎么玩的?有不一样的地方或注意点吗?

互联网公司很多都摆脱了垂直架构了
IOC和aop是核心,这是不变的玩法一样,后面有SpringBoot,微服务SpringCloud

36. ThreadLocal在Spring中是怎么使用的?

无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。

就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全的“状态性对象”采用ThreadLocal进行封装,让它们也成为线程安全的“状态性对象”,因此有状态的Bean就能够以singleton的方式在多线程中正常工作

37. 面试中被问到的,如何用aop实现一个参数校验器

在前置通知中配置切入点拦截方法
取出参数,校验参数(可以自定义一些注解,添加到参数上(非空,长度限制... ...))
在aop的横切逻辑中解析注解,判断是否符合要求

38. spring初始化过程中都有加锁,spring初始化过程是并发的吗?

防止并发刷新,例如refresh可以手动触发,防止并发操作

在这里插入图片描述

39. spring有几种事件类型?怎么使用?他们的作用是什么?如果自定义一个事件?

ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
RequestHandledEvent

定义bean,实现ApplicationListener接口即可

40. 当一个接口有多个实现类,且这些实现类都有@Service注解,那么在beanDefinition中是怎么存放的呢?为什么这样@Autowired就会报错呢?

多个beanDefinition
一个接口,多个实现类,不知道具体应该使用哪个实现类,需要格外指定,否则报错

41. spring是怎么集成tomcat,然后进行启动的?

ContextLoaderListener  初始化spring容器操作

42. spring学完了,其中的组件,还不能串起来,譬如web,orm,oxm,jms,servlet

spring全家桶还没有学完

43. 从ThreadLocal中获取Connection,完成后而不手动移除,会不会造成内存泄露?

可以手动销毁资源,如果当前请求处理线程销毁了,也会销毁内部资源

44. 事务A调用事务B Brollback 事务A 也rollback吗

方法之间调用,方法中的事务和事务的传播行为的设置有关

45. 有些时候循环依赖是否可以通过懒加载的方式解决,如果可以,这种方式和spring解决循环依赖相比有什么区别?

懒加载解决不了循环依赖问题,只是掩耳盗铃把问题后置罢了

46. 有参构造注入为什么无法解决循环依赖?(set注入可以)

对象还没实例化完
set注入是把对象实例化后,进行注入对象的半成品

47. ThreadLocal 如果配合线程池使用,线程会重复使用,这样会有安全嘛?

需要清理控制,进行初始化的设置
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穿城大饼

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值