当前位置: 首页 > news >正文

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!

Spring源码

参考资料

https://www.bilibili.com/video/BV1Tz4y1a7FM
https://www.bilibili.com/video/BV1iz4y1b75q

image-20230727230632443

bean的生命周期

bean–>推断构造方法(默认是无参构造,或指定的构造方法)–>实例化成普通对象(相当于new bean)

–>进行依赖注入(bean里的属性)–>执行afterPropertiesSet()(InitializingBean的一个回调方法,同@PostConstruct)

–>初始化后是否需要AOP–>AOP–>代理对象(target=普通对象)–>把对象放入Map<beanname,bean对象>单例池

//真正创建Bean的方法protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//封装被创建的Bean对象BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();//获取实例化对象的类型Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.//调用PostProcessor后置处理器synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.//向容器中缓存单例模式的Bean对象,以防循环引用boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.//Bean对象的初始化,依赖注入在此触发//这个exposedObject在初始化完成之后返回作为依赖注入完成后的BeanObject exposedObject = bean;try {//将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象populateBean(beanName, mbd, instanceWrapper);//初始化Bean对象exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {//获取指定名称的已注册的单例模式Bean对象Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {//根据名称获取的已注册的Bean和正在实例化的Bean是同一个if (exposedObject == bean) {//当前实例化的Bean初始化完成exposedObject = earlySingletonReference;}//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);//获取当前Bean所依赖的其他Beanfor (String dependentBean : dependentBeans) {//对依赖Bean进行类型检查if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.//注册完成依赖注入的Beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}
//初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//JDK的安全机制验证权限if (System.getSecurityManager() != null) {//实现PrivilegedAction接口的匿名内部类AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;//对BeanPostProcessor后置处理器的postProcessBeforeInitialization//回调方法的调用,为Bean实例初始化前做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}//调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置//文件中通过init-method属性指定的try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//对BeanPostProcessor后置处理器的postProcessAfterInitialization//回调方法的调用,为Bean实例初始化之后做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

三级缓存解决循环依赖

循环依赖

在A创建的过程中,A的属性B需要注入属性A

  • singletonObjects(一级缓存)
  • earlysingletonObjects(二级缓存)
  • singletonFactories(三级缓存)
  • private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
  1. 创建的A放入 Set singletonsCurrentlyInCreation(只要创建就放入set,表示bean正在初始化)
  2. 首先是实例化,new 普通对象,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));为了防止循环引用,尽早持有对象的引用,第二个参数是一个lamda表达式可用来获取普通对象
  3. 在A填充B时,B需要注入A,判断A正在初始化,此时出现循环依赖
  4. 先向二级缓存里查找,在多方循环中保证创建的是都是同一个代理对象A
  5. 再向三级缓存里查找,没有则执行lamda获取普通对象,并且进行AOP,生成代理对象
  6. 放入bean到二级缓存中
  7. 填充其他的属性
  8. 进行Aop的逻辑,若是循环依赖则会提前进行Aop(step5)而不是现在
  9. 在二级缓存里查找,是不是已经有已经生成好的bean
  10. 添加到单例池
  11. Set中removeA,标识初始化完成
http://www.lryc.cn/news/124077.html

相关文章:

  • Unity 鼠标实现对物体的移动、缩放、旋转
  • 67Class 的基本语法
  • 企业数字化转型:无形资产占比测算(2007-2021年)
  • [centos]设置主机名
  • 华为OD真题--新学习选址--带答案
  • Qt自定义对话框
  • Python 程序设计入门(018)—— format() 函数的用法详解
  • 演进式架构
  • OCP China Day 2023:五大社区齐聚,加速开源开放创新与落地
  • 【Linux】进程间通信之管道
  • 记录一个正则表达式
  • 用于全局复根和极点查找算法的自适应网格生成器(Matlab代码实现)
  • 修改Linux中SSH的端口
  • Ansible从入门到精通【六】
  • 国企的大数据岗位方向的分析
  • 【MySQL--->数据类型】
  • Ceph部署
  • 打工日记-Vue3+Ts二次封装el-table
  • funbox3靶场渗透笔记
  • springcloud3 hystrix实现服务降级,熔断,限流以及案例配置
  • ComponentOne Studio ASP.NET MVC Crack
  • OPENCV C++(十一)
  • ES使用心得
  • Stable Diffusion - 幻想 (Fantasy) 风格与糖果世界 (Candy Land) 人物提示词配置
  • 部署K8S集群
  • 在时间和频率域中准确地测量太阳黑子活动及使用信号处理工具箱(TM)生成广泛的波形,如正弦波、方波等研究(Matlab代码实现)
  • 一百五十四、Kettle——Linux上安装Kettle9.3(踩坑,亲测有效,附截图)
  • PackageNotFoundError: No package metadata was found for bitsandbytes解决方案
  • uni-app和springboot完成前端后端对称加密解密流程
  • 【Unity造轮子】制作一个简单的2d抓勾效果(类似蜘蛛侠的技能)