Spring常见面试题(源码)

1、Spring获取Bean的流程

1、加载配置,可以是xml配置或者是配置类,Spring提供了统一的抽象接口BeanDefinitionReader,对于不同的配置有不同的实现类,xml配置是使用XmlBeanDefinitionReader,然后将Bean解析成BeanDefinition对象,然后注册到beanDefinitionMap中,key就是bean的id,value就是BeanDefinition对象,如果有别名的话,在map额外保存一个key是别名,value是id,获取Bean的时候会重定向一次

2、Spring的事件传播器会接受相应事件并传播

  • Bean工厂BeanFactory是一个接口,我们使用的是它的一个实现类DefaultListableBeanFactory
 public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
 }
  • BeanDefinition,表示一个Bean的定义,spring通过BeanDefinition来创建对象,
重要的属性:
	benanClass
	scope
	isLazy
	dependsOn
	primary
	:表示一个Bean是主Bean,在Spring中一个类型可以有多个bean对象,在进行依赖注入时,如果根绝类型找到了多个bean,此时会判断这些bean是否存在一个主bean,如果存在,直接将这个bean注入给属性
	initMethodName
	...
  • 里面有一个属性,存放了所有Bean的定义以及这个Bean被封装成的BeanDefinition对象,
  private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

BeanFactotyPostProcessor Bean工厂的后置处理器即获取工厂中的BeanPostProcessor,调用方法处理bean

1.2Spring获取Bean的流程

1、扫描 ----> 创建BeanDefinition对象 ———>放到beanDefinitionMap中

2、验证 遍历beanDefinitionMap,验证类是否能被创建出来(是否是singleton 是否是抽象类,是否是懒加载,是否是FactoryBean接口的实现类 id属性是否合法 等等),将最终的Bean的id存到一个Set集合中(singleton类型的),这个Set集合的名字是SingletonsCurrentlyInCreation 当一个Bean的生命周期全部结束后,会将这个id移除掉,

3、得到Bean的class对象,根据注入模型,如果设置了构造模式就推断构造方法,判断要使用哪个构造方法进行创建对象,没有设置构造模式默认使用的就是无参的构造方法

4、得到构造器对象,使用反射实例化对象

5、合并BeanDefinition,主要是合并有父类的bean

6、提前暴露一个bean工厂对象---->为了解决循环依赖

7、填充属性,对属性的注入

8、执行部分aware接口,比如ApplicationContextAware接口,为其注入ApplicationContext工厂,等 并执行实现BeanPostProcessor接口中重新的postProcessBeforeInitialization()方法

9、执行剩下的aware接口,并执行Bean的初始化方法,即@PostConstruct标注的方法

10、执行接口版和自定义xml配置版的初始化方法(即实现了InitializingBean接口重写的方法afterPropertiesSet())

11、执行实现的BeanPostProcessor接口的postProcessAfterInitialization()方法,aop代理就是在此方法中完成的

12、将Bean放到单例池中(一级缓存)

13、获取工厂后调用getBean(“id”)调用的就是BeanFactory的doGetBean()方法

1.3Spring的缓存

一级缓存

单例的Bean被创建后就被存放在一级缓存中,其实就是一个Map,只要这个单例bean被创建后,以后再次获取直接从Map中获取

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>

三级缓存

  • singletonFactories,三级缓存,主要存放半成品单例bean的被包装成的ObjectFactory,后续可以解决循环依赖,

    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>
    

二级缓存

  • earlySingletonObjects,二级缓存,从二级缓存中取的半成品的bean,主要存放半成品的bean 如果不存在循环依赖那么创建的bean不会放在三级缓存 Map集合
private final Map<String, Object> earlySingletonObjects = new HashMap<>();

1.4为什么需要三级缓存?

核心就是为了实现AOP,如果注入的早期对象需要的是其代理对象,就需要使用三级缓存为早期对象生成代理,存到二级缓存中去,最终返回早期实例是二级缓存中的其代理对象,使用三级缓存的本质在于解决AOP代理问题

第三级缓存存的是原生早期对象,第二级缓存中存的是经过代理之后的早期对象

2、Spring如何解决循环依赖

2.1什么是循环依赖

就是不同类之间循环引用,比如A类的构造方法依赖B,B类的构造方法依赖A

2.2Spring中的三种循环依赖

1、原型循环依赖(无法解决 只能抛出异常)

每次getBean都是创建新的对象,Spring不会去缓存对象,没有缓存池

2、单例构造方法循环依赖(无法解决,只能抛出异常)

3、单例setter方法循环依赖 (可以解决,提前暴露对象(已完成实例化未完成初始化))

2.3如何判断产生了循环依赖

2.3.1原型模式如何判断产生了循环依赖

原型模式是当getBean(“id”)时Spring才会去根据BeanDefinition定义去反射创建对象,在创建对象时会将当前的beanName存到ThreadLocal中的一个Set集合中,当进行属性注入时发现依赖B,这时就会去获取B的对象,将B的beanName也存进ThreadLocal的Set中,然后B中也依赖A,这时就会去获取A,发现A的beanName已经存在于Set集合中,说明A 和B都处于正在创建的过程中,就可以说明发生了循环依赖,直接抛出异常

2.3.2singleton模式下如何判断产生了循环依赖

当根据A的BeanDefinition去创建对象时,在创建过程中会将beanName存到一个Set集合中,当进行属性注入时发现依赖B,这时就根据B的BeanDefinition创建B,这时B的beanName也会存进Set集合中,创建B的过程发现B依赖A,然后试图将A的beanName存到Set集合中,这时返现Set集合中已经有了A的beanName,即表示A正在创建中,就判断出了发生了循环依赖

2.4Sping如何解决singleton循环依赖

singleton的Bean假设A在创建时会先将这个尚未经过属性注入和初始化的对象包装到一个ObjectFactory对象内,然后存到三级缓存中,key就是beanName,value就是ObjectFactory对象,然后在往下进行属性注入时发现依赖B,就去getBean()去获取B,单例池中没有B,就去根据B的BeanDefinition进而去创建B,在创建B的过程发现B依赖A,就去获取A,就去获取A暴露ObjectFactory对象,通过调用get方法获取A的早期对象,进而完成对A的注入,然后B完成创建后,就将B的对象存到一级缓存中,然后回到A的逻辑完成B的注入

3、BeanFactory与FactoryBean的不同

  • 1、BeanFactory和FactoryBean都是接口
  • 2、BeanFactory就是Spring的Bean工厂,创建并保存了我们的Bean对象,
  • 3、而FactoryBean是Spring提供的专门创建那些复杂对象的,复杂对象即不能直接使用new关键字创建的对象,比如说Connection对象,SqlSessionFactory对象,我们需要实现FactoryBean接口,主要是重写getObject()方法,写创建对象的代码,然后将这个实现类配置在配置文件或者使用配置类的形式,我们获取工厂后使用getBean(“id”)的方式获取的就是这个实现类为我们创建的复杂对象,如果想要获取这个实现类对象,在getBean()获取Bean时id前加入&即可

4、BeanFactory与ApplicationContext的不同

1、ApplicationContext是BeanFactory的子接口

2、 BeanFactory是工厂接口,负责创建Bean的实例,并保存这些单实例的bean在Map中

3、ApplicatonContext是容器的接口,比BeanFactory功能更加强大,更多的负责容器功能的实现,可以基于BeanFactory创建好的对象之上完成强大的容器,AOP DI都是ApplicatonContext接口下的这些类里,

BeanFactory是最底层的接口,ApplicatonContext是留给我们使用的ioc容器接口。

Spring最大的模式就是工厂模式

你可能感兴趣的:(Spring,spring,bean,设计模式,ioc,java)