Java面试-Spring10问

1、BeanFactory和FactoryBean的区别?BeanPostProcessor和BeanFactoryPostProcessor的区别?

BeanFactory

BeanFactory可以理解为Spring的顶级容器框架,定义了整个Spring容器的边界,同时BeanFactory还是Spring的顶级接口,提供了一些公共API,getBean()、isSingleton()、getType()等,这样后面继承和实现BeanFactory的接口、抽象类、普通类等真实的小容器,共同组成了Spring真实容器并对外提供了丰富的真实API实现。
比如DefaultListableBeanFactory里存放了beanDefinitionMap集合,AbstractApplicationContext里存放了beanFactoryPostProcessors集合,DefaultSingletonBeanRegistry里存放了singletonObjects集合,AbstractBeanFactory里存放了beanPostProcessors集合,ClassPathXmlApplicationContext提供了getBean()方法,他们共同组成了Spring,容器里的Bean默认都是单例模式,可设置为原型模式。

FactoryBean

FactoryBean是一个工厂接口,与BeanFactory这样一个容器比起来,它是一个真正的意义上工厂。
实现了FactoryBean接口之后,再结合范型,便可以通过getObject()返回任何想要的对象,而这样的Bean我们也称之为工厂Bean。这样一个工厂Bean方便我们在代码层面对实例对象进行统一的封装和加工,在容器中用getBean(“&+实例对象”)的方式返回的便是真的工厂Bean对象实例,典型的工厂模式。

BeanPostProcessor和BeanFactoryPostProcessor

1、一个是Bean实例对象的处理器,一个是BeanFactory容器的处理器。
2、前者保存在AbstractBeanFactory类中,后者保存在AbstractApplicationContext类中。
3、AOP也正是通过BeanPostProcessor后置处理的方式完成了IOC容器里Bean的扩展,用到了代理模式。

2、Spring 容器的启动流程?

Spring容器的Bean加载流程是Spring框架启动流程的核心,从程序入口开始或者启动类开始,核心方法都是AbstractApplicationContext抽象类的refresh()方法,具体流程是:
1、初始化容器的运行环境并校验必要的属性值:prepareRefresh()方法为容器的启动做一些准备工作,设置AbstractApplicationContext上下文的close关闭、active活跃标识,初始化环境资源即将所有的spring.profiles文件都加载到容器,然后根据配置的环境变量来确定要执行的配置文件,然后校验当前环境必要的属性值。
2、创建DefaultListableBeanFactory容器并加载BeanDefinition对象:obtainFreshBeanFactory()方法创建DefaultListableBeanFactory工厂,BeanDefinitionReader以流的形式将.xml、.properties等配置文件加载到容器当中,并以BeanDefinition对象的形式保存到DefaultListableBeanFactory的beanDefinitionMap集合当中。对应后面要讲的容器启动阶段。
3、填充DefaultListableBeanFactory容器属性并注册环境对象:prepareBeanFactory()方法为刚创建的DefaultListableBeanFactory工厂对象做属性填充,并将一些environment、systemEnvironment系统环境Bean注册到DefaultSingletonBeanRegistry的singletonObjects集合中。
4、加工DefaultListableBeanFactory容器对象:postProcessBeanFactory()方法对DefaultListableBeanFactory工厂对象做简单的加工,例如在自动注入时忽略指定的依赖接口、注册特定于 Web 的范围。
5、调用BeanFactory容器的PostProcessors处理器,完成BeanDefinition对象的处理:invokeBeanFactoryPostProcessors()方法调用各种BeanFactory容器的BeanFactoryPostProcessor处理器,对BeanFactory容器进行加工处理,在这一步也完成了对BeanDefinition对象里的占位符的替换。这里注意一个ConfigurationClassPostProcessor处理器,他是SpringBoot自动装配处理器,有对应@Component、@Configuration、@ComponentScan、@Import等注解的配置类的处理,配置类里为了保证Bean是单例,用到了代理模式。
6、注册BeanPostProcessor处理器:registerBeanPostProcessors()方法将BeanPostProcessor处理器注册到AbstractBeanFactory类的beanPostProcessors集合当中。
7、初始国际化信息源:initMessageSource()方法用来初始化MessageSource信息源,使用国际化,定制不同的消息。
8、初始化应用事件管理器:initApplicationEventMulticaster()方法初始化应用事件管理器。
9、创建并启动Web服务器:onRefresh()方法虽然在AbstractApplicationContext是一个空方法,但SpringBoot项目正是在这一步完成内嵌的Tomcat Web服务器的启动,这里用到模版模式。
10、注册事件监听器并监听处理早期事件:registerListeners()方法向应用事件管理器注册事件监听器,并调用事件监听器执行方法,监听处理早期事件,这里用到了观察者模式。
11、完成容器内自定义对象的创建:finishBeanFactoryInitialization(beanFactory)方法完成容器内自定义的非懒加载的Bean的实例化、属性赋值、初始化、增强实现,容器内的自定义对象创建完成,可以拿来使用了,容器里的Bean默认都是饥饿加载的单例Bean。
12、finishRefresh();
13、destroyBeans();

3、Spring Bean的加载流程(生命周期)?

一、容器启动阶段

在这里插入图片描述

1、实现BeanDefinitionReader接口的XmlBeanDefinitionReader、PropertiesBeanDefinitionReader、AnnotatedBeanDefinitionReader读取并加载来自xml文件、properties文件,配置类的元信息,将<Bean>的Document对象加载为一个个BeanDefinition对象,BeanDefinition描述了一个Bean对象的全部信息。
2、实现BeanDefinitionRegistry接口的DefaultListableBeanFactory通过registerBeanDefinition()方法,将BeanDefinition对象保存到内部的beanDefinitionMap集合当中,beanDefinitionMap集合是Key是bean的全类名,Value是BeanDefinition对象的ConcurrentHashMap。
3、实现BeanFactoryPostProcessor接口的PropertyResourceConfigurer对BeanDefinition对象做最后的修改,将占位符替换为真实数据。

二、Bean的获取阶段

1、一般在使用ApplicationContext.getBean()或者自动注入Bean时,都会调用AbstractBeanFactory的doGetBean()方法,会先从DefaultSingletonBeanRegister中获取单例对象,DefaultSingletonBeanRegister中有三个重要的集合,singletonObjects、earlySingletonObjects、singletonFactories,对应的一、二、三级缓存,执行getSingleton()方法时,会依次查找对象实例,直到返回,但注意当一个单例 bean 被放入到earlySingletonObjects缓存后,就要从 singletonFactories 缓存中移除,两者是互斥的,主要用来解决循环依赖的问题。
2、从缓存中拿回对象后就要判断是否为null,如果不为空的话再调用getObjectForBeanInstance()方法判断当前实例对象是不是一个FactoryBean工厂Bean,如果是的话直接返回,如果不是的话从factoryBeanObjectCache缓存(集合)中获取。
3、从缓存中拿回对象如果是null,就要通过BeanDefinition判断Bean是否为单例对象,但不管是不是单例对象,都会调用AbstractAutowireCapableBeanFactory的createBean()->doCreateBean()->createBeanInstance()方法去创建Bean实例对象,也就是核心的Bean实例化阶段(生命周期),只不过,如果Bean是单例对象的话,创建完成后会把实例对象加入到singletonObjects一级缓存当中,同时从earlySingletonObjects、singletonFactories中移除,也就是说这三个缓存是彼此互斥的,不会针对同一个Bean的实例同时存储。

三、Bean的实例化阶段:

在这里插入图片描述

如上图所示是Spring Bean的一个完整生命周期,大概可以分为反射调用构造器实例化对象、populateBean完成属性赋值、initializeBean完成初始化和postProcessor增强实现、使用并销毁实例化对象四个步骤,也就是对应的下面的Bean的实例化阶段。
但一个完整Bean的加载流程,还需要前面的容器准备阶段,而且Spring Bean默认的饥饿加载方式,一般在使用时都是从容器的缓存中获取(集合),所以下面单独来看Bean的获取和Bean的实例化。
Bean的实例化:
1、AbstractAutowireCapableBeanFactory的createBeanInstance()方法首先会通过传入的beanName以及BeanDefinition对象解析出一个Class类对象,然后获取Class类对象的构造器,不使用构造注入或者重写构造函数的话,默认都是无参构造,然后使用构造器.newInstance()获得对象实例,这里也是为何Spring的三级缓存无法解决构造注入导致的循环依赖的原因,构造里相互依赖就会导致先有鸡还是先有蛋的问题。
2、刚实例化的Bean会被BeanWrapper所包装成为一个包装类,提供了一些API操作,例如返回实例对象的类对象、返回实例对象、返回实例对象属性描述等,接下来实例对象会调用populateBean()方法进行属性填充,然后调用initializeBean()方法对实例对象进行初始化。
3、在initializeBean()方法中会先检查,实例对象除了属性注入之外是否还有Aware接口注入,例如实现了BeanNameAware接口,则调用setBeanName方法,实现了BeanClassLoaderAware接口,则调用setBeanClassLoader方法,实现了BeanFactoryAware接口,则调用setBeanFactory方法,然后初始化实例对象的前置增强器,执行前置增强方法。
4、实例对象的前置增强器执行结束之后,会调用invokeInitMethods()方法,用来执行初始化阶段要执行的方法,例如Bean实现了InitializingBean接口,调用afterPropertiesSet方法,如果Bean定义了init-method方法,则调用Bean的init-method方法。
5、最后,实例对象会初始化后置增强器,执行后置增强方法,AOP也正是在这一步生成了代理类。至此,实例对象的实例化、初始化都结束了,准备就绪被放倒容器当中,后面伴随容器的销毁而销毁。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值