【面试题】SpringBean高频面试题总结(详细回答)


1. 什么是Spring Bean?

由springioc容器管理的对象就是一个bean,是由ioc容器实例化,组装,管理的对象

2. Java Bean和Spring Bean的区别?

  • 用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean
  • 写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法
  • 生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行为

3. 实例化bean有哪几种方式?

  • 构造器方式(反射)–xml,@Component
  • 静态工厂
  • 实例工厂(@bean)
  • bean工厂

4. Spring Bean 的生命周期?

简单文字说明

  • 实例化Bean:对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
  • 设置对象属性(依赖注入):实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
  • 处理Aware接口:接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
    • ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(StringbeanId)方法,此处传递的就是Spring配置文件中Bean的id值;
    • ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
    • ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
  • BeanPostProcessor:如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
  • InitializingBean 与 init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
  • 如果这个Bean实现了BeanPostProcessor接口,将会调postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
  • DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
  • destroy-method:最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

5. Spring 中 bean 是线程安全的吗?

Spring 容器中的 Bean 本身不具备线程安全的特性, 但是具体还是要结合具体scope 的 Bean 去研究。

  • Spring 容器中的 Bean 默认是单例的,所有线程都共享一个单实例的 Bean,因此是存在资源的竞争。如果单例 Bean,是一个无状态 Bean,也就是线程中的操作不会对 Bean 的成员执行查询以外的操作,那么这个单例 Bean 是线程安全的。比如Spring mvc 的 Controller、Service、Dao 等,这些 Bean 大多是无状态的,只关注于方法本身。对于有状态的 bean , 是线程不安全的, 但是我们可以通过ThreadLocal 去解决线程安全的方法。
  • 对于原型 Bean(即 scope="prototype"),每次创建一个新对象,也就是线程之间并不存在 Bean 共享,自然是不会有线程安全的问题。

6. 如何处理线程并发问题?

  • 设置为多例的
  • 将成员变量放在threadlocal中
  • 同步锁syn(变成串行了会影响吞吐量)

7. 如何解决bean的循环依赖?

三级缓存,也就是三个Map集合类:

singletonObjects:第一级缓存,里面放置的是已经实例化好的单例对象;

earlySingletonObjects:第二级缓存,里面存放的是提前曝光的单例对象;

singletonFactories:第三级缓存,里面存放的是将要被实例化的对象的对象工厂。

所以当一个Bean调用构造函数进行实例化后,即使set属性还未填充,就可以通过三级缓存向外暴露依赖的引用值进行set(所以循环依赖问题的解决也是基于Java的引用传递),这也说明了另外一点,基于构造函数的注入,如果有循环依赖,Spring是不能够解决的。

还要说明一点,Spring默认的Bean Scope是单例的,而三级缓存中都包含singleton,可见是对于单例Bean之间的循环依赖的解决,Spring是通过三级缓存来实现的。

 

8. BeanFactory 和ApplicationContext的区别

  • BeanFactory和ApplicationContext都是接口,并且ApplicationContext间接继承了BeanFactory。
  • BeanFactory是Spring中最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能,而ApplicationContext是Spring的一个更高级的容器,提供了更多的有用的功能。  
  • ApplicationContext提供的额外的功能:获取Bean的详细信息(如定义、类型)、国际化的功能、统一加载资源的功能、强大的事件机制、对Web应用的支持等等。
  • 加载方式的区别:BeanFactory采用的是延迟加载的形式来注入Bean;ApplicationContext则相反的,它是在Ioc启动时就一次性创建所有的Bean,好处是可以马上发现Spring配置文件中的错误,坏处是造成浪费。

9. BeanFactory和FactoryBean的区别?

  • 两者都是接口;
  • BeanFactory主要是用来创建Bean和获得Bean的;
  • FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象;
  • 通过BeanFactory和beanName获取bean时,如果beanName不加&则获取到对应bean的实例;如果beanName加上&,则获取到FactoryBean本身的实例
  • FactoryBean 通常是用来创建比较复杂的bean(如创建mybatis的SqlSessionFactory很复杂),一般的bean 直接用xml配置即可,但如果创建一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

10. 夺命连环问【高级】

1.二级缓存能不能解决循环依赖?
        如果只是死循环的问题: 一级缓存就可以解决:无法避免在并发下获取不完整的Bean
        二级缓存也可以解决循环依赖:只不过如果出现重复循环依赖 会多次创建aop的动态代理


2. Spring有没有解决多例Bean的循环依赖?
        多例不会使用缓存进行存储(多例Bean每次使用都需要重新创建)
        不缓存早期对象就无法解决循环


3. Spring有没有解决构造函数参数Bean的循环依赖?
        构造函数的循环依赖也是会报错
        可以通过@Lazy, 就不会立即创建依赖的bean了而是等到用到才通过动态代理进行创建

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值