Spring有很庞大的家族,Spring一般指的其实就是SpringFramework! Ioc和aop
包含在SpringFramework中!
SpringFramework介绍和特点:
可以看到SpringFramework包含了我们通常使用的ioc,aop
有兴趣的童鞋可以把源码下载下来研究,下载下来的源码可以修改
Springframework源码地址:https://github.com/spring-projects/spring-framework
也可以本地项目引入依赖进行研究:
org.springframework
spring-context
5.2.0.RELEASE
引入依赖,创建项目:
创建X,Y类,加上@Component注解
配置spring要扫描的包
创建Main方法,使用AnnotationConfigApplicationContext 加载配置类
运行完上图中第17行代码AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);Spring容器就会被初始化,spring容器就会去加载config配置类,解析config类(由于config加了@ComponentScan注解)就会扫描com.spring包下的类,就会把加了注解@component的类加载到spring容器并实例化,所以就能X类打印出来
循环依赖:
X中依赖Y,Y中依赖X就叫循环依赖,只有单例才支持循环依赖,并且不支持构造方法依赖
为什么探讨循环依赖?
因为spring bean不等同于java对象,java对象依赖可以使用set(new Object)完成循环依赖。Spring bean不能像java对象一样完成这样的依赖
普通java对象实例过程:new 的过程
Java虚拟机启动,类加载器把编译好的class文件信息加载到方法区
Spring bean实例过程:
加了注解的类,spring 容器会把该类的class文件加载成一个BeanDefinition对象(存放了该类的所有信息),比如类名就放在 factoryBeanName中
然后把该BeanDefinition放入一个map中。Spring 就会遍历这个map,把所有的BeanDefinition拿出来做验证,验证BeanDefinition对应的类要不要实例化,因为有的类不要实例化(@Scope(“prototype”)),懒加载(@Lazy(true))的也不会马上实例化。实例化以后的bean放入一个单例池中(一个map中)。
伪代码:
扩展:可以使用BeanDefinitionMap偷天换日
先了解Bean生命周期:
Bean生命周期:
1.scan ---变成beandefinition 放进map
2.遍历map 得到beanDefinition
3.验证bd是否要实例化
4.通过bd,getClass得到class
5.推断构造方法(因为class里可能有很多构造方法)
6.实例化对象(这时候只是一个对象,不是一个完整的bean)
7.合并bean
8.缓存一个工厂
9.填充bean (判断bean有多少属性),自动注入
10.执行一部分Aware,比如ApplicationContextAware
11.执行生命周期初始化回调方法 (有三种方法:1.打上@PostConstruct注解,2.实现InitializingBean接口,3,xml配置)
@PostConstruct //生命周期回调方法 ,注解版
public void init(){
System.out.println("annotation init");
}
@Override //生命周期回调方法,接口板
public void afterPropertiesSet() throws Exception {
System.out.println("implements inti");
}
12.接口生命周期回调方法,执行一部分aware
13.如果有aop 执行aop代理
开始源码分析:
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);执行这段代码的时候,点进去会发现首先通过this()会调用父类的一个方法
xy实例完成:
继续跟踪this.refresh()
invokeBeanFactoryPostProcessors方法完成了扫描,变成BeanDefinition,并完成实例
上图其中的五个变量是spring最重要的五个类,开天辟地,比如第一个类,主要完成注解扫描
探讨循环依赖
1.spring开始实例化单例的类
继续跟踪这个方法
继续跟踪这个方法:拿到所有的BeanNames,并遍历
通过beanName从BeanDefinationMap中得到BeanDefinition
开始验证:
继续跟踪getBean方法:
跟踪一getSingleton方法
所有类实例化以后都在图中的单例池map中,下图中框起来的是就是spring 单例池(是一个map)
证明一下单例池是一个Hash
继续回到getSingleton()判断是否从单例池中拿到beanName对应的bean
因为第一次实例,从单例池中拿不到x。所以走的是上面的else ,往下会发现继续验证是否有@DependsOn注解等:
上图中,检查是单例,使用lambam调用createBean创建bean
doCreateBean方法中:
跟踪addSingletonFactory方法
回到doCreateBean方法看:此时,X只是一个对象,还不是bean
判断是否支持循环依赖,是的话提前暴露一个工厂进单例工厂map中
继续往下看,看addSingletonFactory方法:
继续往下:调用populateBean方法,完成属性填充,此时生命周期,Aware还没执行,所以还不是完整的bean
继续,该执行一部分aware了
执行aware的原理,把刚刚实例好的bean传进去进行判断,然后直接执行
继续研究:执行applyBeanPostProcessorsBeforeInitialization后,aware和部分生命周期执行完成,但是还有接口板的aware没有执行。
紧接着就是接口板的aware执行。
代理aop
Spring 容器初始化过程
其中在finishBeanFactoryInitialization(beanFactory);方法中完成bean的实例化(需要validate校验和执行life周期函数)
进入finishBeanFactoryInitialization(beanFactory);继续追踪实例化的方法。
preInstantiateSingletons中进行一系列的校验
getBean调用doGetBean,先中容器中的单例池中尝试获取,获取到则返回,没获取到继续验证,然后调用createBean
上图createBean中,通过bd,拿到class,反射调用构造方法实例对象
对象实例好了,回到doCreateBean方法。
继续往下:判断是否支持循环依赖,如果支持,就往singletonFactories(Map)中缓存一个工厂,传入bean的名字,ObjectFactory
然后执行一部分aware,判断有没有aop,有就代理上,最后把bean put进单例池中
背后的过程:
判断类是否有别名,有的话获取所有别名
当X类中有Y,Y类中有X时,实例X的时候,走到populateBean需要填充Y,肯定会调用getBean()去singleObjects(单例池)中拿Y
论证:实例x的时候
接下来又执行了一遍:这次beanName = y
发现y在单例池中没有,调用createBean()创建y
创建y的时候发现要去填充x,所以又去创建x,创建x的过程首先先去单例池中拿,由于x正在创建,所以单例池中没有,拿不到!
1.跟踪关键方法:getSingleton
看一下beforeSingletonCreation里面做了啥:判断当前创建的beanName是否包含在正在创建的集合中,如果没有,则把beanName放进正在创建的集合中
回到填充熟悉阶段:x填充y,发现y没有,然后就去创建y,当y填充x的时候,去拿一遍x
拿x的代码过程:先去单例池中拿,没有拿到,判断是否正在被创建(true,因为第一次实例的时候会把正在创建的beanName 放进一个map中),如果是,就去三级缓存earlySingletonObjects拿,没有拿到就获取x的beanFactory(之前已经暴露,所以可以拿到)
拿到X的singletonFactory:
然后通过singletonFactory拿到x Object(没有实例完成的),把x Object(singletonObject)放进三级缓存earlySingletonObjects,看图:
这样,y就能把x填充好了(x 还是Object,还不是bean),然后返回的x填充y的那段代码继续执行,循环依赖就解决了!
Bean生命周期:
1.scan ---变成beandefinition 放进map
2.遍历map 得到beanDefinition
3.验证bd是否要实例化
4.通过bd,getClass得到class
5.推断构造方法(因为class里可能有很多构造方法)
6.实例化对象(这时候只是一个对象,不是一个完整的bean)
7.合并bean
8.缓存一个工厂
9.填充bean (判断bean有多少属性),自动注入
10.执行一部分Aware,比如ApplicationContextAware
11.执行生命周期初始化回调方法 (有三种方法:1.打上@PostConstruct注解,2.实现InitializingBean接口,3,xml配置)
@PostConstruct //生命周期回调方法 ,注解版
public void init(){
System.out.println("annotation init");
}
@Override //生命周期回调方法,接口板
public void afterPropertiesSet() throws Exception {
System.out.println("implements inti");
}
12.接口生命周期回调方法,执行一部分aware
13.如果有aop 执行aop代理
很重要的beanDefiniton:
Bean的建模对象:BeanDefinition(包含了bean的类型,作用域,是否懒加载,注入模型,构造方法参数,set方法参数等信息)