02.spring源码分析.txt

UP 返回
视频地址 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.788.player.switch&vd_source=d4b23777458c9f0c9e0eb065a7a765b9&p=15
练习项目 D:\ProjectCodes\IDEA2021\MyManualSpring

Bean创建的生命周期
UserService.class → 推断构造方法(默认无参构造方法) → 普通对象 → 依赖注入 → 初始化前(@PostConstract) → 初始化(afterPropertiesSet) → 初始化后(AOP) → 代理对象 → 放入Map(单例池) → Bean对象
在推断构造方法时,默认会使用无参构造。如果只有一个构造方法,就会直接使用;如果有多个构造方法,会寻找有没有无参构造方法,如果有就用,没有就会报错。可以在构造方法上使用@Autowired来指定要调用的构造方法,如果都加注解也会报错(只要不知道用哪一个就会报错)
如果推断的构造方法有参数且也是一个bean时,会自动去单例池查找,如果找到就会用,没找到就会触发这个参数bean的构建;当然如果不是单例,那就直接创建了。所以下面这种类型,即使OrderService没有加Autowired,也会触发bean的创建并被获取到
在获取对象时,首先根据类型匹配,找到一个就直接用;找到多个再根据参数名匹配,匹配到就用;匹配不到抛异常(依赖注入也是如此)
	!!@@202503301.img_1253_381_1@@!!

bean的代理对象需要继承该bean,这样才可以在获取bean时将代理对象以子类的形式返回使用;但是代理类并不是直接在切面方法中调用父类的目标方法,因为代理类的属性并没有经过autowired这一步,他的属性其实都是空的
所以,代理类实际上还有一个属性,就是对应的bean,在切面方法中调用该属性的方法,这样就满足既能实现切面,又能让被代理的对象的属性是被注入好的

spring的事务管理,需要在切面方法中获取数据库连接,因为要主动将自动提交autocommit置为false,执行完代理方法后再判断是否需要提交。如果由后面的jdbcTemplate执行时再获取连接,可能会默认自动提交事务,就无法控制住了,但是jdbcTemplate就需要主动获取当前的连接

@Transactional用的就是AOP动态代理

一级缓存:singletonObjects	单例池(这个集合就是用来存储已经经历过完整生命周期的bean)
二级缓存:earlySingletonObjects 存储由于循环依赖需要提前创建的bean(需要保证单例,比如下面的B创建好A后就可以将A放入二级,C在创建的时候就不会重复创建了)
三级缓存:singletonFactories	打破循环!(当2.2需要对A进行AOP时,是需要获取A的普通对象的,而在这个流程中,A是不会传进来的,因为这步是对B的创建,所以这里需要三级缓存来获取A的普通对象)
一级二级缓存是为了解决循环依赖,三级缓存是为了打破循环依赖!

假设有AService BService CService,A有BC属性,BC都有A属性,就会产生循环依赖。创建A的过程如下:
1.实例化-->AService普通对象 creatingset.add< 'AService'>--->singletonFactories.put('AService',() -> getEarlyBeanReference(beanName, mbd, AService普通对象)) 		//所有的bean在创建到这一步时都会存进来,后续如果有循环依赖,就会从这里取。这里存的是一个lambda表达式,只在用的时候被调用
2.填充bService--->单例池Map--->创建BService
	BService的Bean的生命周期
	2.1.实例化-->普通对象
	2.2.填充aService--->单例池Map----creatingSet --->AService 通过creatingset判断出现了循环依赖--->earlySingletonObjects-->singletonFactories-->取出并执行lambda-->AOP(如果不需要aop那么就返回原始对象)--->AService代理对象--->earlySingleton0bjects
	2.3.填充其他属性
	2.4.做一些其他的事情(AOP)
	2.5.添加到单例池
2.填充CService--->单例池Map--->创建CService
	CService的Bean的生命周期
	2.1.实例化-->普通对象
	2.2.填充aService--->单例池Map--->creatingSet--->AService出现了循环依赖--->earlySingletonObjects
	2.3.填充其他属性
	2.4.做一些其他的事情(AOP)
	2.5.添加到单例池
3.填充其他属性
4.做一些其他的事情(AOP等) --->AService代理对象
	4.5 earlySingletonObjects.get("AService")
5.添加到单例池
6. creatingset.remove< 'AService'>
	!!@@202503302.img_1192_702_1@@!!

在上述例子中,如果A中有一个方法加了@Async,就会出现报错。因为在本例中,2.2步创建的A其实是普通对象,因为Async是另外一套机制,并不会被认为是aop。这样在4时需要对A产生Async的代理对象,原则上这个对象跟之前存入二级缓存的应该是一个对象,但实际上不相等(一个普通对象一个代理对象肯定不同),就会抛出异常
解决方法就是在B的AService属性上加一个@Lazy注解(也不是aop,是另一种关于lazy的代理对象,加了以后在创建B时就暂时不会因为自动注入A而创建A,也就不会做2.2那一步)
	!!@@202503303.img_1028_487_1@@!!

自动注入的循环依赖可以被spring解决,但是如果是构造方法出现循环依赖(比如A中有B,B的构造方法又需要传A),这种也是会报错的。。但是也可以通过在构造方法加@Lazy注解解决
	!!@@202503305.img_1014_573_1@@!!



DOWN 返回