Spring底层原理
Spring底层原理
原理
Bean的创建过程
推断构造方法
选择使用的构造方法:
如果只有无参的构造方法,就用无参的;
如果只有一个有参的构造方法,就用这个有参的;
如果有多个有参的构造方法,会使用构造上加了@Autowired的构造,没有则spring也不知道用哪个,会尝试找无参的,没有就报错。
对入参进行依赖注入
会对有参的构造函数中的参数进行依赖注入,先通过类型去单例池中找,如果有多个则再通过参数名匹配,没有就报错。
依赖注入
找加了响应注解(@Autowired、@Resource)的属性,先byType再byName
初始化
- 初始化前:扫描对应注解(@PostConstruct),执行初始化前方法
- 初始化中:扫描对应接口(afterPropertiesSet),执行初始化方法
- 初始化后:AOP产生代理对象
- cglib:代理对象继承原对象,原对象成为代理对象的一个属性。切面方法里通过joinPoint.getTarget()可以获取原对象,joinPoint.getThis()可以获取代理对象
放到Map(单例池)中
Bean对象
事务
和AOP类似,生成代理对象来增强功能
开启事务:在数据库配置类上加@EnableTransactionManagement、@Configuration
- 事务管理器新建一个数据库连接conn
- conn.autocommit = false // 关闭自动提交
- 使用@Configuration把dataSource注入bean,使每次拿到的都是同一个dataSource
使用事务:@Transactional
:star:事务失效原理
必须是从获取到的代理对象来调用有事务的方法才会生效。
如果是从自己new的对象/其他方法调用事务方法等方式则不会经过切面,从而事务失效
:star:循环依赖
提前AOP
成因:在创建一个bean时将其名字添加到一个set中,创建完后将其删除。如果此时另一个bean需要依赖注入的bean在单例池中找不到,而在这个set中,说明出现了循环依赖
只有出现循环依赖时,将AOP的步骤提前到填充属性前,得到代理对象注入到二级缓存(earlySingletonObjects)中。此时的代理对象还不能放到单例池中,因为代理对象里的原对象还没创建出来,现在处于半成品状态
后面再出现循环依赖,会先去二级缓存中找,没有再去提前AOP
当当前对象创建完后,再从二级缓存中取出半成品对象继续初始化完再放进单例池中,半成品会被删掉
而创建二级缓存中代理对象的方法,存在三级缓存(singletonFactories)中,在去二级缓存中找代理对象而没有找到时调用,调用完删掉。在之后正常流程的AOP时发现三级缓存里的被删除了的话,就不再AOP
@Lazy
成因:@Async会生成代理对象,但和AOP是不同的逻辑,是在后处理器中做的代理。所以在提前AOP时放入二级缓存的是原始对象,注入的也是原始对象。而之后从二级缓存中取出继续初始化后,放入一级缓存的却是代理对象
成因:在构造函数时出现循环依赖,即创建不出原始对象,如AService(Bservice b)、BService(AService a)
解决:使用@Lazy会先用一个代理对象来占位,到之后用到时再注入对象,从而不会发生循环依赖
三级缓存
三级缓存就是三个Map,最终是为了保证单例
- 第一级缓存:singletonObjects (单例池):存放创建好的bean
- 第二级缓存:earlySingletonObjects:存放提前创建的代理对象
- 第三级缓存:singletonFactories:存放创建代理对象的方法
源码
1.Bean的创建
分析过程
目标:通过debug来寻找在哪里创建了User对象,根据何时打印构造方法里的打印来寻找
1 |
|
- 通过配置文件方式将bean注入到容器中
1 |
|
1 |
|
- 创建容器,通过debug发现实在创建容器时创建了user
1 |
|
- 继续往里看,debug发现执行到refresh()时创建了user
1 |
|
- 点入refresh(),发现创建容器的步骤,其中执行到第11步
finishBeanFactoryInitialization(beanFactory);
时创建了user
- 点入
finishBeanFactoryInitialization()
方法,发现调用了beanFactory.preInstantiateSingletons();
后创建了user - 继续往下点发现在方法里判断当前类是不是抽象、单例、懒惰,后调用了
getBean(beanName)
来创建或获取Bean getBean()
调用doGetBean()
,会先尝试从缓存中取,没有则先初始化依赖的Bean,然后调用createBean()
来实例化和初始化BeancreateBean()
中调用了InstantiationAwareBeanPostProcessor()
后置处理器来实现AOP,然后调用doCreateBean()
反射实例化和初始化Bean
总结
到这里发现是调用了beanFactory的doGetBean()方法创建了非懒加载的单例bean。beanFactory通过反射创建空参的单例对象,创建后将对象保存到了一个map集合中(singletonObjects),key为bean的名字,value为user的单例对象。
2.Bean的获取
context.getBean(),获取beanFactory,通过beanFactory的getBean方法,根据名称获取创建时放进map里的bean