Spring
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
Spring源码解析
1 |
|
prepareRefresh
Prepare this context for refreshing, setting its startup date and active flag as well as performing any initialization of property sources.
1 | protected void prepareRefresh() { |
监听器,earlyApplicationListeners
obtainFreshBeanFactory
This implementation performs an actual refresh of this context’s underlying bean factory, shutting down the previous bean factory (if any) and initializing a fresh bean factory for the next phase of the context’s lifecycle.
1 | protected final void refreshBeanFactory() throws BeansException { |
prepareBeanFactory
Configure the factory’s standard context characteristics, such as the context’s ClassLoader and post-processors.
Params:
beanFactory – the BeanFactory to configure
1 | protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { |
postProcessBeanFactory
Modify the application context’s internal bean factory after its standard initialization. All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for registering special BeanPostProcessors etc in certain ApplicationContext implementations.
Params:
beanFactory – the bean factory used by the application context
1 | protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { |
invokeBeanFactoryPostProcessors
Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given.
Must be called before singleton instantiation.
1 | protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { |
registerBeanPostProcessors
Instantiate and register all BeanPostProcessor beans, respecting explicit order if given.
Must be called before any instantiation of application beans.
1 | protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { |
initMessageSource
Initialize the MessageSource. Use parent’s if none defined in this context.
1 | protected void initMessageSource() { |
initApplicationEventMulticaster
Initialize the ApplicationEventMulticaster. Uses SimpleApplicationEventMulticaster if none defined in the context.
See Also:
SimpleApplicationEventMulticaster
1 | protected void initApplicationEventMulticaster() { |
onRefresh
Template method which can be overridden to add context-specific refresh work. Called on initialization of special beans, before instantiation of singletons.
This implementation is empty.
Throws:
BeansException – in case of errors
See Also:
refresh()
1 | protected void onRefresh() throws BeansException { |
registerListeners
Add beans that implement ApplicationListener as listeners. Doesn’t affect other listeners, which can be added without being beans.
1 | protected void registerListeners() { |
finishBeanFactoryInitialization
Finish the initialization of this context’s bean factory, initializing all remaining singleton beans.
1 | protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { |
finishRefresh
Finish the refresh of this context, invoking the LifecycleProcessor’s onRefresh() method and publishing the ContextRefreshedEvent.
1 | protected void finishRefresh() { |


Spring核心

IOC
Inversion of Control,控制反转
IOC也叫依赖注入(DI)
核心:反射
1 |
|
1 | UserController userController = new UserController(); |

AOP
面试题
谈谈SpringIOC的理解,原理和实现
控制反转:理论思想,原来的对象是由使用者来进行控制,有了Spring之后,可以把整个对象交给Spring来帮我们进行管理
DI:依赖注入,把对应的属性的值注入到具体的对象中,@Autowired,populateBean完成属性的注入
容器:存储对象,使用map结构进行储存,再spring中一半存在三级缓存,singletonObjects存放完成的bean对象
整个bean的声明周期,从创建到使用到销毁的过程都是由容器来管理(bean的声明周期)
分:
- 一般聊
IOC容器的时候要涉及到容器的创建过程(beanFactory,DefaultListableBeanFactory),向bean工厂中设置一些参数(BeanPostProcessor,Aware接口的子类)等等属性 - 加载解析
bean对象,准备要创建的bean对象的定义对象beanDefinition(xml,或者注解的解析过程) beanFactoryPostProcessor的处理,此处是扩展点,PlaceholderConfigureSupport,ConfiguationClassPostProcessorBeanPostProcessor的注册功能,方便后续对bean对象完成具体的扩展功能- 通过反射的方式将
BeanDefinition对象实例化成具体的bean对象 bean对象的初始化过程(填充属性,调用aware子类的方法,调用BeanPostProcessor前置处理方法,调用init-method方法,调用BeanPostProcessor的后置处理方法)- 生成完整的
bean对象,通过getBean方法可以直接获取 - 销毁过程
面试官,这是我对IOC的整体理解,包含了一些详细的处理过程,您看一下有什么问题,可以指点我一下
具体的细节我记得不太清了,但是spring中的bean都是通过反射的方式生成的,同时其中包含很多的扩展点,比如最常用的对BeanFactory的扩展,对bean的扩展,我们公司在这方面的使用是比较多的,除此之外
谈谈spring IOC的底层实现
底层实现:工作原理、过程、数据结构、流程、设计模式、设计思想
反射,工厂,设计模式,关键的几个方法名
createBeanFactory、getBean、doGetBean、createBean、doCreateBean、createBeanInstance(getDeclaredConstructor,newInstance)、populateBean
- 先通过
createBeanFactory创建出一个Bean工厂(DefaultListBaleBeanFactory) - 开始循环创建对象、因为容器中的
bean默认都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话 - 通过
createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用的是无参的构造方法(getDeclaredConstructor,newInstance) - 进行对象的属性填充
populateBean - 进行其他的初始化操作(
initalizingBean)
描述一下bean的生命周期
背图
在表述的时候,不要只说图中的关键点,要学会扩展
- 实例化
bean:反射的方式生成对象 - 填充
bean的属性:populateBean(),循环依赖的问题(三级缓存) - 调用
aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置) - 调用
BeanPostProcessor中的前置处理方法:使用比较多的有(ApplicationContextPostProcessor,设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象) - 调用
initmethod方法:invokeinitmethod,判断是否实现了initiaizingBean接口,如果有,调用afterPropertiesSet方法,没有就不调用 - 调用
BeanPostProcessor的后置处理方法:spring的AOP就是在此处实现的,AbstractAutoProxyCreator,注册Destuction相关的回调接口:钩子函数 - 获取到完成的对象,可以通过
getBean的方式来进行对象的获取 - 销毁流程,1:判断是否实现了
DispoableBean接口 2:调用destroyMethod方法

Spring是如何解决循环依赖的问题
三级缓存,提前暴露对象,aop
总:什么是循环依赖问题,A依赖B,B依赖A
分:先说明Bean的创建过程:实例化、初始化
- 先创建
A对象,实例化A对象,此时A对象中的b属性为空,填充属性b - 从容器中查找对象,如果找到了,直接赋值(不存在循环依赖问题),找不到直接创建
B对象 - 实例化
B对象,此时B对象中的a属性为空,填充属性a - 从容器中查找
A对象,找不到,直接创建
形成闭环原因
此时,会发现A对象是存在的,只不过此时的A对象不是一个完成的状态,只完成了实例化但是未完成初始化
如果在程序调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先把非完成状态的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整对象的引用,所以解决问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键
当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中存在对象的几个状态,完成实例化但未完成初始化,完成状态,因为都在容器中,所以要使用不同的map进行存储,此时就有了一级缓存和二级缓存。如果一级缓存中有了,那么二级缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找的。
一级缓存中放的是完整对象,二级缓存中放的是非完整对象
为什么需要三级缓存?三级缓存的value类型是ObjectFactory,是一个函数式接口,存在的意义是保证在整个容器的运行过程中同名的bean对象只有一个
如果一个对象需要被代理,或者说需要生成代理对象,那么要先生成一个普通对象
普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际调用过程中,是没有办法确定什么时候对象被调用,所以就要求当某个对象被调用的时候,优先判断次对象是否需要被代理,类似一种回调机制的实现,因此传入lambda表达式的时候,可以通过lambda表达式来执行对象的覆盖过程,getEarlyBeanReference()
因此,所有的bean对象在创建的时候都要优先放到三级缓存中,在后续的使用过程中,如果需要被代理则返回代理对象,如果不需要被代理,则直接返回普通对象
缓存的放置时间和删除时间
三级缓存:createBeanInstance之后:addSingletonFactory
二级缓存:第一次从三级缓存中确定对象是代理对象还是普通对象的时候,同时删除三级缓存:getSingleton
一级缓存:生成完整对象之后放到一级缓存,删除二级三级缓存:addSingleton
BeanFactory和FactoryBean有什么区别
相同点:都是用来创建bean对象的
不同点:使用BeanFactory创建对象的时候,必须要遵守严格的生命周期流程,如果想简单的自定义某个对象的创建,同时创建完成的对象想交给spring来管理,那么就需要实现FactoryBean接口了
isSingleton:是否是单例对象
getObjectType:获取返回对象的类型
getObject:自定义创建对象的过程(new,反射,动态代理)
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
BeanFactory
BeanFactory定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,也就是Spring IOC所遵守的最底层和最基本的编程规范。在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现
1 | package org.springframework.beans.factory; |
FactoryBean
一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式
1 | package org.springframework.beans.factory; |
在该接口中还定义了以下3个方法:
T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;boolean isSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;Class<T> getObjectType():返回FactoryBean创建的Bean类型。
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
例:如果使用传统方式配置下面Car的<bean>时,Car的每个属性分别对应一个<property>元素标签
1 | public class Car { |
如果用FactoryBean的方式实现就灵活点,下例通过逗号分割符的方式一次性的为Car的所有属性指定配置值
1 |
|
有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置CarBean了:
1 | <bean id="car"class="com.baobaotao.factorybean.CarFactoryBean" |
当调用getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀:如getBean("&car");
Spring中用到的设计模式
单例模式:bean默认都是单例的
原型模式:指定作用域未prototype
工厂模式:BeanFactory
模板方法:postProcessBeanFactory onRefresh initPropertyValue
策略模式:XmlBeanDeifnitionReader,PropertiesBeanDefinitionReader
观察者模式:listener,event,multicast
适配器模式:Adapter
装饰者模式:BeanWapper
责任链模式:使用aop的时候会先生成一个拦截器链
代理模式:动态代理
委托者模式:delegate
Spring的AOP的底层原理
动态代理
aop是ioc的一个扩展功能,先有的ioc,再有aop,只是在ioc的整个流程中新增的一个扩展点而已:BeanPostProcessor
总:aop概念,应用场景,动态代理
分:bean的创建过程中有一个步骤可以对bean进行扩展实现,aop本身就是一个扩展功能,所以在BeanPostProcessor的后置处理方法中来实现
- 代理对象的创建过程(
advice、切面、切点) - 通过
jdk或者cglib的方式生成代理对象 - 在执行方法调用的时候,会调用到生成的字节码文件中,直接对找到
DynamicAdvisoredInterceptor的intercept方法,从此方法开始执行 - 根据之前定义好的通知来生成拦截器链
- 从拦截器链中依次获取每一个通知开始执行,在执行过程中,为了方便找到下一个通知是哪个,会有一个
InvocationInterceptor的对象,找的时候是从-1的位置依次开始查找并执行
Spring的事务是如何回滚的
spring的事务管理是如何实现的
总:spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体逻辑
分:
- 先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开启新事务
- 当需要开启的时候,获取数据库连接,关闭自动提交功能,开启事务
- 执行具体的
sql逻辑操作 - 在操作过程中,如果执行失败了,那么会通过
completeTransactionAfterThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是要先获取连接对象,通过连接对象来回滚 - 如果执行过程中没有任何意外情况发生,那么通过
commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCimmit方法实现的,实现的时候也是要先获取连接对象,通过连接对象来提交 - 当事务执行完毕需要清除相关的事务信息
cleanupTransaction
如果想要聊的更加细致,需要了解TransactionInfo和TransactionStatus
谈一下spring的事务传播
传播特性有几种?7种
Required,Requires_new,nested,Support,Not_support,Never,Mandatory
某一个事务嵌套另一个事务的时候怎么办
A方法调用B方法,AB方法都有事务,并且传播特性不同,那么A如果有异常,B怎么办,B如果有异常,A怎么办
总:事务的传播特性指的是不同的嵌套过程种,事务应该如何进行处理,是用同一个事务还是不同的事务,当出现异常的时候会回滚还是提交,两个方法之前的相关影响,在日常工作中,使用比较多的是required,requireds_new,nested
分:
- 先说事务的不同分类,可以分为三类:支持当前事务,不支持当前事务,嵌套事务
- 如果外层方法是
required,内层方法是required,requireds_new,nested - 如果外层方法是
requireds_new,内层方法是required,requireds_new,nested - 如果外层方法是
nested,内层方法是required,requireds_new,nested
核心处理逻辑非常简单
- 判断内外方法是否是同一个事务
- 是:异常统一在外层方法处理
- 不是:内层方法有可能影响到外层方法,但是外层方法是不会影响内层方法的(大致可以这么理解,个别情况除外
nested)
参考文献
Spring学习(二十八)-ApplicationListener原理