Spring底层原理理解
手写模拟Spring 代码:
Bean的生命周期
- UserService.class
- 推断构造方法
- 对象
- 依赖注入
- Aware回调
private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
- 初始化前
(BeanPostProcessor.postProcessBeforeInitialization(result, beanName)
和@PostConstruct)
@PostConstruct
本质上就是在BeanPostProcessor.postProcessBeforeInitialization(result, beanName)
中执行的并且执行加了@PostConstruct
注解的方法 - 初始化 实现InitializingBean接口,实现afterPropertiesSet()方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { // 调用回调接口 invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 调用BeanPostProcessor的BeforeInitialization方法 // 调用@PostConstruct注解修饰的方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // ((InitializingBean) bean).afterPropertiesSet(); invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 调用BeanPostProcessor的AfterInitialization方法 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
- 初始化后 最重要的应用就是AOP
注意:AOP @Configuration @Lazy 是平级的关系,@Configuration @Lazy 并不是实用的AOP- 生成代理对象,但是代理对象中的对象不会依赖注入,比如被代理对象中有User属性,在我们查看的时候,发现User属性为空
- 所以在我们调用被代理对象(原对象)时,并不是
super.method()
,因为属性并没有被依赖注入进去。 - 实现的方式是,将前几步已经依赖注入了的被代理对象赋值到代理对象的target属性中。
- 在我们调用被代理对象(原对象)时,其实是
target.method()
。 - 这样就不需要重复的进行依赖注入了
- 在我们切面逻辑中,调用jointPoint.getTarget()得到的就是被代理对象,jointPoint.getThis()得到的就是代理对象
Spring事务
- 本质也是AOP,在被代理方法执行前处理,执行后处理,只是需要特殊处理的是,每一次事务方法执行前都要由TransactionManager获取数据库连接,而不是由jdbcTemplate或者mybatis获取,因为默认autoCommit属性默认是true,而且如果执行多条sql不能保证是同一个连接也就不能保证可以一起回滚。
- 放入Map(单例池)
一旦放入了单例池,就可以把创建的对象称为Bean对象 - Bean对象
循环依赖
在springboot 2.6以后,默认禁用了循环依赖也就是allowCircularReferences
被设置为了false,导致boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
变为false,无法开启解决循环依赖的二三级缓存。
三级缓存
- 一级缓存:singletonObjects:保存的是完整的bean,经过了完整的生命周期
- 二级缓存:earlySingletonObjects:提前生成的bean可能是代理对象,也可能是普通对象,主要作用是为了保证单例。但是对象还需要对被代理对象或者对象进行初始化,还没有经过完整生命周期。因此不可以放在单例池中。
- 三级缓存:singletonFactories:目的是打破循环依赖,放的是一个lambda表达式,可以提前进行AOP
比如我们现在有两个类一个AService,一个BService
@Component
public class AService {
@Autowired
BService bService;
}
@Component
public class BService {
@Autowired
AService aService;
}
此时就发生了循环依赖。因为在bean的生命周期中,如果先创建Bean AServcie,然后需要为AServcie依赖注入BService,此时发现单例池中没有BService,那么就会去先创建BService,此时会为BService依赖注入AService,发现单例池中没有AService,又会去创建AService此时就陷入了循环,无法解决。
因此我们提出了三级缓存来解决循环依赖
为什么要提早AOP
发生循环依赖的情况下, 如果在填充完所有属性后,在进行AOP,那么BService中的AService对象就是还没有被AOP的对象,这样就发生错误
总体的流程是这样的:
同时@Lazy也可以解决循环依赖,因为在@Lazy注解修饰的属性和构造方法上,Spring为其注入的不是真正的对应的对象而是一个代理对象,只有在真正用到这个对象的时候才会执行代理逻辑,从容器中找到这个对象,并执行他的真正逻辑。
如果加上了@Async也会导致解决循环依赖失败
@Async也会产生动态代理,但不是AOP,如果是AOP那么可以被Spring解决。因为在执行上面所说的lambda表达式不会对@Async做任何处理,
如果加上了@Async那么在讲AService赋值给BService后,AService对象又变成了AService的代理对象,这样有发生了不一致。
在源码中,就是判断在initializingBean()方法后exposedObject是否发生了变化,如果发生了变化就可能导致属性中的对象和容器中的对象不一致。并且记住AOP后的代理对象中有个属性target中含有bean。