Spring底层的理解

Spring底层原理理解

手写模拟Spring 代码:

Bean的生命周期

  1. UserService.class
  2. 推断构造方法
  3. 对象
  4. 依赖注入
  5. 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);
    		}
    	}
    }
    
  6. 初始化前(BeanPostProcessor.postProcessBeforeInitialization(result, beanName)和@PostConstruct)
    @PostConstruct本质上就是在BeanPostProcessor.postProcessBeforeInitialization(result, beanName)中执行的并且执行加了@PostConstruct注解的方法
  7. 初始化 实现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;
    }
    
  8. 初始化后 最重要的应用就是AOP
    注意:AOP @Configuration @Lazy 是平级的关系,@Configuration @Lazy 并不是实用的AOP
    1. 生成代理对象,但是代理对象中的对象不会依赖注入,比如被代理对象中有User属性,在我们查看的时候,发现User属性为空
    2. 所以在我们调用被代理对象(原对象)时,并不是super.method(),因为属性并没有被依赖注入进去。
    3. 实现的方式是,将前几步已经依赖注入了的被代理对象赋值到代理对象的target属性中。
    4. 在我们调用被代理对象(原对象)时,其实是target.method()
    5. 这样就不需要重复的进行依赖注入了
    6. 在我们切面逻辑中,调用jointPoint.getTarget()得到的就是被代理对象,jointPoint.getThis()得到的就是代理对象

    Spring事务
    1. 本质也是AOP,在被代理方法执行前处理,执行后处理,只是需要特殊处理的是,每一次事务方法执行前都要由TransactionManager获取数据库连接,而不是由jdbcTemplate或者mybatis获取,因为默认autoCommit属性默认是true,而且如果执行多条sql不能保证是同一个连接也就不能保证可以一起回滚。
  9. 放入Map(单例池)
    一旦放入了单例池,就可以把创建的对象称为Bean对象
  10. Bean对象

循环依赖

在springboot 2.6以后,默认禁用了循环依赖也就是allowCircularReferences被设置为了false,导致boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));变为false,无法开启解决循环依赖的二三级缓存。
三级缓存

  1. 一级缓存:singletonObjects:保存的是完整的bean,经过了完整的生命周期
  2. 二级缓存:earlySingletonObjects:提前生成的bean可能是代理对象,也可能是普通对象,主要作用是为了保证单例。但是对象还需要对被代理对象或者对象进行初始化,还没有经过完整生命周期。因此不可以放在单例池中。
  3. 三级缓存: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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值