Spring

355 阅读6分钟

IOC原理

juejin.cn/post/696615…

AOP实现原理

zhuanlan.zhihu.com/p/83004139

spring容器启动过程

大家知道,bean的生命周期是由spring容器管理的,所以在深入了解bean的生命周期之前我们先了解一下spring容器的启动加载过程,都在refresh方法里面:

// 容器启动前的一些初始化配置,比如启动时间,设置启动监听器
prepareRefresh();

// 实例化容器,并将内部的6个BeanFactoryPostProcessor构造成bd注入到容器中,ConfigurationClassPostProcessor的bd就是在这里注册的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

//注册一些内部的BeanPostProcesser和Bean,这时候的BeanPostProcesser还只是在beanPostProcessers属性中
prepareBeanFactory(beanFactory);


	// 内部修改beanFactory的入口
	postProcessBeanFactory(beanFactory);

	// 调用所有BeanFactoryPostProcessor接口实现,该方法会通过ConfigurationClassPostProcessor去扫描所有的@component,然后创建对应的bd注册到beanFactory
	invokeBeanFactoryPostProcessors(beanFactory);

	// 将所有的BeanPostProcessor实例注册到容器中,这时BeanPostProcesser已经在singletonObjects中了,AutowiredAnnotationBeanPostProcessor也是在这个时候注册的,后期@Autowired和@Value的属性依赖注入都是依赖这个BeanPostProcessor.postProcessProperties处理的

	registerBeanPostProcessors(beanFactory);

	// 初始化MessageSource(国际化用的)
	initMessageSource();

	// 初始化 event multicaster,事件发布是通过这个实现的
	initApplicationEventMulticaster();

	// 在所有用户bean未注册到容器前的内部回调
	onRefresh();

	// 注册事件监听器
	registerListeners();

	// 实例化所有的单例对象(非懒加载的),并注册到容器中
	finishBeanFactoryInitialization(beanFactory);

	//所有bean注册至容器后会发布相关事件,比如ContextRefreshedEvent
	finishRefresh();

@component注解的类注入到spring容器的全过程

  1. springboot启动,实例化一个DefaultListableBeanFactory,该类实现了beanFactory和BeanDefinitionRegistry接口;BeanDefinitionRegistry的相关接口负责注册工作,BeanFactory的相关接口负责bean的管理工作
    同时还实例化了两个功能性对象AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner,其中最主要的是往beanDefinitionMap中put了spring自己的6个BeanDefinition,其中包括了最重要的ConfigurationClassPostProcessor,他是一个beanFactoryPostProcessor。
  2. 进入到refresh方法,当调用到invokeBeanFactoryPostProcessors(beanFactory),就会调用ConfigurationClassPostProcessor的回调方法processConfigBeanDefinitions ,这个方法内部实现了扫描注解(ClassPathBeanDefinitionScanner.doscan())、注册bd(DefaultListableBeanFactory.registerBeanDefinition,这个时候的bd是不完整的,后面还有替换占位符的BeanFactoryPostProcessor。

生命周期

bean的生命周期分为以下四个阶段

  1. 实例化
    参考 www.jianshu.com/p/1dec08d29…
  2. 属性注入
  3. 初始化
  • 实现InitializingBean接口,该接口只有一个方法afterPropertiesSet(),为了减少与Spring的耦合,Spring建议使用注解@PostConstruct;如果同时使用的话,执行顺序如下: (1) @PostConstruct
    (2)afterPropertiesSet() interface
    (3) 自定义的init()
  • Spring容器级别的初始化扩展点是BeanPostProcessor接口,实现该接口可以对所有的Bean初始化过程(前后)加入自己的逻辑;
  • Spring容器工厂级别的扩展点是BeanFactoryPostProcessor接口,实现该接口可以拿到Spring容器对象DefaultListableBeanFactory,可以直接操作BeanDefinition;
  • Spring容器启动时(还未开始注入Bean),也有回调接口,Lifecycle和LifecycleProcesser
  1. 销毁
    实现DisposableBean接口,该接口只有一个方法destroy(),为了减少与Spring的耦合,Spring建议使用注解@PreDestroy; 其他的跟初始化对应。
    Spring建议非web容器需要自己实现优雅停机(web容器内部已经自己实现了),可以直接使用JVM的钩子方法Runtime.getRuntime().addShutdownHook(),也可以使用Spring的钩子方法ctx.registerShutdownHook()

BeanFactory和ApplicationContext

BeanFactory

BeanFactory是Spring容器接口,默认的实现是DefaultListableBeanFactory,所有的bean都会注册到该类中。Spring可以通过多种方式(xml、javaConfig、注解)注册bean,不管何种方式都会创建一个BeanDefinition实例来保存改bean的元数据信息,所有的BeanDefinition保存在DefaultListableBeanFactory.beanDefinitionMap,beanfactory创建bean实例的时候需要通过BeanDefinition+反射。所有的singleton对象都存储在DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry.singletonObjects,调用applicationContext.getBean时,最终也是去这个singletonObjects里面取。

ApplicationContext

ApplicationContext是BeanFactory的子接口,实现了所有BeanFactory的功能,并且还继承了其他一些接口(ApplicationEventPublisher,MessageSource,ResourcePatternResolver等),所以ApplicationContext功能更强大,Spring建议没有特别需要的话,一般用ApplicationContext。而且BeanFactory初始化时是没有注册bean实例的,只有beanDefinition,是ApplicationContext初始化时将所有单例bean都注册到容器当中的。 ApplicationContext的实现类中持有DefaultListableBeanFactory实例,所有bean相关的功能都委托给DefaultListableBeanFactory处理。

循环依赖

spring初始化bean是通过ObjectFactory.getObject()创建实例化的,入口是在AbstractBeanFactory.doGetBean方法,这里要先知道Spring内部的3个属性:DefaultSingletonBeanRegistry中singletonFactories,earlySingletonObjects,singletonObjects,singletonObjects是最终的对象容器,其他两个都是临时容器,
为了简化流程忽略其他无关代码,下面是Spring初始化时创建bean的流程,入口是AbstractBeanFactory.doGetBean

//先看下缓存里是否已经有了
Object sharedInstance = getSingleton(beanName);
//创建bean
sharedInstance = getSingleton(beanName, () -> {
	return createBean(beanName, mbd, args);
}

先看getSingleton(beanName,singletonFactory)

//通过getObject()获取对象实例
singletonObject = singletonFactory.getObject();
//该方法会将bean实例缓存到singletonObjects,并清除其他两个临时容器里面的这个bean
addSingleton(beanName, singletonObject);

getObject其实就是调用createBean,最终是调用下层的doCreateBean

//实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
//缓存beanname->singletonFactory,这个时候的bean还没有属性注入和初始化
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//bean的属性注入
populateBean(beanName, mbd, instanceWrapper);
//初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
//如果有循环依赖,则要判断循环依赖的对象(earlySingletonObject)和最终初始化完成的对象是否相同
getSingleton(beanName, false)

正常创建bean的流程是:

  1. getSingleton(beanName),发现singletonObjects没有该对象,singletonFactory也没有
  2. doCreateBean(beanName),这里面有bean实例化,属性注入,bean初始化
  3. populateBean(beanName),属性注入
  4. addsingletonFactory(beanName),放到singletonObjects中,并把其他两个容器中的移除
    当有循环依赖的时候,A在第三步属性注入时,发现依赖B,那就会先去容器里面拿B,发现没有,然后就要先往容器中注入B,B实例化后接着也是属性注入,发现又依赖于A,这时已经有A的singletonFactory,所以B就从A的singletonFactory获取到A实例(这时A的实例会被移动到earlySingletonObjects),所以B就持有了A的earlySingletonObject,B完成了实例化,然后A就可以拿到B的实例,从而完成A的属性注入。具体可参考 www.jianshu.com/p/988ad2913…

参考 www.jianshu.com/p/1dec08d29…

为什么用三级缓存不是用二级?

www.zhihu.com/question/44…

image.png

spring mvc 参数绑定过程

  1. SpringMVC初始化时,RequestMappingHandlerAdapter类会把一些默认的参数解析器添加到argumentResolvers中。当SpringMVC接收到请求后首先根据url查找对应的HandlerMethod。
  2. 遍历HandlerMethod的MethodParameter数组
  3. 根据MethodParameter的类型来查找确认使用哪个HandlerMethodArgumentResolver,遍历所有的argumentResolvers的supportsParameter(MethodParameter parameter)方法。。如果返回true,则表示查找成功,当前MethodParameter,使用该HandlerMethodArgumentResolver。这里确认大多都是根据参数的注解已经参数的Type来确认。
  4. 解析参数,从request中解析出MethodParameter对应的参数,这里解析出来的结果都是String类型。
  5. 转换参数,把对应String转换成具体方法所需要的类型,这里就包括了基本类型、对象、List、Set、Map。

MVC实现原理

www.cnblogs.com/yoci/p/1064…

MVC之参数绑定过程

www.cnblogs.com/w-y-c-m/p/8…