首页 > 编程语言 >Java八股-Spring三级缓存,自动装配原理

Java八股-Spring三级缓存,自动装配原理

时间:2024-11-19 21:43:30浏览次数:3  
标签:缓存 Java Spring Bean 依赖 注解 Configuration

文章目录

Spring的Bean生命周期

Spring三级缓存的学习需要有对Spring的Bean生命周期的理解:
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

【新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)】 https://www.bilibili.com/video/BV1yT411H7YK/?p=39&share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a

一般来说Bean的定义和注册现在很少用XML方式来搞,这么搞太复杂了,现在一般都是要用@Configuration注解的类来完成XML文件的Bean注册。
至于具体怎么用@Configuration来搞注册Bean的类,可以看下面这个视频,然后后头再来看本博客应该就能有清晰的了解了

【黑马程序员SpringBoot3+Vue3全套视频教程,springboot+vue企业级全栈开发从基础、实战到面试一套通关】 https://www.bilibili.com/video/BV14z4y1N7pg/?p=9&share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a

@Configuration
public class CommonConfig {
	//该方法负责注册Bean到IOC容器里面,当然你也可以@Bean多个方法来注册多个Bean
	@Bean public StrUtil str(){//StrUtil是第三方导入的包
		return new StrUtil();
	}
	//	注册多个Bean
	@Bean public StrUtil2 str2(){//StrUtil是第三方导入的包
		return new StrUtil2();
	}
	//	注册多个Bean
	@Bean public StrUtil3 str3(){//StrUtil是第三方导入的包
		return new StrUtil3();
	}
}

ApplicationContext 这里是SpringBoot的IOC容器,里面是有各种各样的依赖注入的Bean对象,而Bean对象的注入可以用@Autowire来注入,@Configuration的配置类来@Bean注入,这里讲解的就是第二种!

@SpringBootApplication
public class App {
	public static void main(String[] args){
        ApplicationContext appContext = SpringApplication.run(App.class, args);
		StrUtil obj = appContext.getBean(StrUtil.class);
		System.out.println(obj);
	}
}

在Spring框架中,@Configuration注解和@Bean注解有着紧密的联系,它们共同用于定义Spring容器中的Bean。

  1. @Configuration注解

    • @Configuration是一个类级别的注解,用于声明一个类作为配置类,相当于传统XML配置文件中的标签。
    • @Configuration注解的类内部通常包含一个或多个@Bean注解的方法。
    • @Configuration注解的类可以包含构造函数、普通方法、成员变量等,它们可以定义和注册多个Bean。
    • @Configuration类可以被组织成层级结构,允许继承和组合,这样可以更灵活地组织配置逻辑。
  2. @Bean注解

    • @Bean是一个方法级别的注解,用于声明一个方法的返回值应该被注册为Spring容器中的一个Bean。
    • @Bean注解的方法通常会执行一些初始化逻辑,并返回一个对象实例,这个实例随后会被Spring容器管理。
    • @Bean注解可以指定Bean的名称,如果不指定,则默认使用方法的名称作为Bean的名称。
    • @Bean注解可以与@Configuration注解配合使用,也可以与@Component注解配合使用,后者用于定义组件类,而@Bean用于显式地声明组件类的实例为Bean。

联系

  • @Configuration注解的类提供了一个上下文环境,允许开发者使用Java代码来定义Bean,而不是XML配置文件。
  • @Bean注解用于在@Configuration注解的类中声明具体的Bean。每个@Bean注解的方法都会告诉Spring容器,这个方法的返回值应该被注册为一个Bean。
  • @Configuration类中可以包含多个@Bean注解的方法,每个方法都可以定义一个或多个Bean。
  • @Configuration和@Bean注解的结合使用,使得Spring框架能够以编程的方式定义和管理Bean,这被称为Java配置(Java-based Configuration)。

总结来说,@Configuration注解定义了一个配置类,而@Bean注解定义了配置类中具体的方法,这些方法返回的对象会被注册为Spring容器中的Bean。这种机制提供了一种声明式的方式来配置Spring应用上下文,使得配置更加清晰和易于管理。

Spring三级缓存无法解决‘构造函数级别 ’的循环依赖(这种只能用@Lazy延迟加载解决)
Spring三级缓存解决的是‘初始化赋值阶段 的循环依赖,也就是通过set方法来初始化的阶段的循环依赖

面对以下情况的循环依赖问题,这只是
@Aotuowire级别的循环依赖,不是构造函数级别的循环依赖!可以用Spring三级缓存解决!

在这里插入图片描述
构造函数级别的循环依赖:↓↓↓↓↓↓↓↓。只能用@Lazy
在这里插入图片描述
Spring的Bean生命周期↓↓↓↓↓↓↓↓

在这里插入图片描述
总结↓↓↓↓↓↓↓↓
在这里插入图片描述

Spring三级缓存

在这里插入图片描述

Spring的三级缓存机制是解决循环依赖问题的关键。三级缓存的设计主要是为了在Bean的创建过程中,能够有效地处理单例Bean之间的循环依赖。以下是三级缓存的详细解释:

  1. 一级缓存(singletonObjects)

    • 这是一个存储已经完全初始化的Bean的缓存。当一个Bean被完全创建和初始化后,它会被添加到这个缓存中。这个缓存确保了在后续的依赖查找中,可以直接获取到已经完成的Bean实例。
  2. 二级缓存(earlySingletonObjects)

    • 这个缓存存储的是早期暴露的对象,即那些已经被构造函数创建但尚未完成属性填充和初始化的Bean。这些对象在Bean创建过程中被放入二级缓存,以便其他Bean可以引用它们,从而解决循环依赖问题。
  3. 三级缓存(singletonFactories)

    • 三级缓存用于存储Bean‘工厂对象’,这些工厂对象能够在Bean完全初始化之前生成Bean实例。当一个Bean正在被创建时,如果它依赖于另一个尚未完全初始化的Bean,Spring会从三级缓存中获取相应的工厂对象,并调用它来生成早期暴露的Bean实例。

循环依赖的解决过程

当Spring容器创建Bean时,如果发现需要依赖的Bean尚未完全初始化,它会将当前Bean的半成品放入三级缓存中,并继续创建依赖的Bean。如果依赖的Bean也需要当前Bean,则Spring会从二级缓存中查找早期暴露的对象,确保能够正确地解决循环依赖。

这种三级缓存机制不仅解决了单例Bean之间的循环依赖问题,还能够处理原型Bean之间的循环依赖,因为原型Bean的每次请求都会创建新的实例,而三级缓存确保了即使在创建过程中也能引用到正在创建的Bean的早期暴露对象。

结论

通过引入三级缓存,Spring在处理复杂的依赖关系时变得更加灵活和强大,能够有效地解决循环依赖问题,确保应用的正常运行。
在这里插入图片描述

如果对象被增强了,有什么代理对象之类的,需要使用到三级缓存!
流程:

  1. 先去实例化A,生成A的对象工厂ObjectFactory,吧工厂放到三级缓存池中
  2. 这时候A依赖B,需要注入B,B对象不存在,此时实例化B,然后B生成一个ObjectFactory,存入三级缓存池里
  3. 此时需要注入A,然后我们从三级缓存池里面取出A的对象工厂,由工厂判断此时需要的是A的代理对象还是A?比如这里需要的是A的代理对象,ok那么我们ObjectFactory生成A的代理对象,这个工厂生成的A的代理对象存到二级缓存池(earlySingleton),再吧A的代理对象注入到B
  4. 然后B创建成功,把B丢到一级缓存池里面,再把B注入到A里面,然后A也创建成功,再把A丢到一级缓存池里面
  5. 最后把二级缓存里面的所有半成品清除

在这里插入图片描述

Q&A

Q:二级缓存是否是多余的?上面这个图只有一级缓存和三级缓存也能解决循环依赖,还能解决代理对象的问题了

A:不是的,一般来说,我们的对象都是单例的,在通过A的对象工厂ObjectFactory创建代理对象时 ,创建完成之后丢到二级缓存里,将B注入给A的时候,就需要从二级缓存里面获取A,从哪里获取呢?答案是二级缓存池里面!如果反复创建了代理对象,那么如果有二级缓存池的话,第一次创建完毕之后可以放到二级缓存池里面,以后再次需要的时候就可以直接拿出来,无需重复创建!

Q:光有一级缓存能不能解决@Autowire级别的循环依赖问题?

A:不能,一级缓存是要经历完整Bean生命周期才能丢到一级缓存里面的,但是循环依赖问题是A依赖B,B依赖A,此时A和B都没有经历完整的生命周期,都无法丢到一级缓存里面

Q:光有一级缓存和二级缓存,能不能解决@Autowire级别的循环依赖问题?

A:可以的,可以解决大部分循环依赖问题,但是如果A被增强过了,那就不能了!
如果A没有被增强过:
流程如下:↓

  1. 先创建A,把A的半成品丢到二级缓存earlySingletonObjects
  2. 此时需要注入B,B不存在,创建B,把半成品B丢到二级缓存里面
  3. 半成品B需要A,把之前二级缓存里面半成品A拿出来组成成品B,B历经完整Bean生命周期,丢到一级缓存里面
  4. 再把B注入A,此时A也完整了,丢到一级缓存里面。
  5. 最后把二级缓存里面的所有半成品清除
    在这里插入图片描述

在这里插入图片描述

Spring自动装配原理

@Import(ClassA.class)的意思是,ClassA.class一般是某个带有@Configuration的配置类,负责Bean的注册导入,@Import(ClassA.class)的意思是导入这个配置类,来完成第三方Bean的导入使用。
@Import(ClassA.class)的豪华升级装逼版是@Import(AutoConfigurationImportSelector.class),导入指定Meta-INF里面的spring.factories
里面的所有类名,每个类都是带有条件的注解,比如下面这个@ConditionalOnClass@ConditionalOnMissingBean

@ConditionalOnClass

@ConditionalOnClass 是Spring框架中用于条件化配置的一个注解,它的作用是仅当指定的类存在于项目的类路径(classpath)中时,才会使标注了该注解的类或方法生效。这个注解可以用在类上,也用在方法上,特别是用在带有@Configuration注解的类和带有@Bean注解的方法上。

具体来说,@ConditionalOnClass 注解有两个属性:

  1. value():接收一个Class对象数组,表示必须存在于类路径上的类。只有当这些类都被找到时,条件才会成立。

  2. name():接收一个字符串数组,表示必须存在于类路径上的类的全限定名称。这个属性允许你不通过Class对象来指定类,而是直接使用类的全限定名。

@ConditionalOnClass 注解的工作原理是通过OnClassCondition类来实现的,这个类实现了Condition接口,并在matches方法中判断指定的类是否存在于类路径中。如果条件成立(即指定的类存在),则相关的配置类或Bean将会被创建并注册到Spring容器中;如果不成立,则这些配置将被忽略。

在实际开发中,@ConditionalOnClass 注解非常有用,它允许开发者根据类路径中是否存在某些类来动态地启用或禁用特定的配置。例如,如果一个项目中包含了某个特定的库或框架,可能需要加载一些特定的配置来集成这个库或框架的功能,这时就可以使用@ConditionalOnClass来实现这种条件化配置。
说白了类似于C里面的条件编译语句#ifndef#ifdef

@ConditionalOnMissingBean

@ConditionalOnMissingBean 是Spring框架中用于条件化配置的一个注解,它的作用是在容器中没有找到指定类型的Bean时,才会创建并注册被该注解标记的Bean。以下是@ConditionalOnMissingBean注解的主要特点和使用方式:

  1. 作用位置@ConditionalOnMissingBean注解可以作用在带有@Bean注解的方法上,也可以作用在带有@Configuration注解的类上。它用于控制Bean的创建过程,确保在没有其他相同类型的Bean被定义时,才创建该Bean。

  2. 保证唯一性@ConditionalOnMissingBean注解确保Spring容器中只有一个特定类型的Bean实例。当存在多个相同类型的Bean实现时,该注解可以帮助选择或提供一个默认的实现。

  3. 使用方式:在定义Bean的方法上使用@ConditionalOnMissingBean注解,并指定需要检查是否存在的Bean的类型。如果该类型的Bean尚未被注册到容器中,则该方法会被调用,从而注册一个新的Bean实例。

  4. 与继承关系@ConditionalOnMissingBean不仅会检查直接的类匹配,还会检查类的继承树。如果容器中存在参数中指定的类或其子类、父类,@ConditionalOnMissingBean会返回false,使得标注的类不执行。

  5. 扩展性@ConditionalOnMissingBean在封装组件时特别有用,它允许开发者提供一个默认的实现类,并在没有其他自定义Bean时使用这个默认实现。这样可以提高组件的可扩展性,允许用户根据业务需求定义自己的Bean。

  6. 自动配置:在Spring Boot中,@ConditionalOnMissingBean常用于自动配置类中,以确保只有在没有用户定义的Bean时,才加载默认的自动配置。

总结来说,@ConditionalOnMissingBean是一个强大的条件注解,它帮助开发者在Spring应用中实现更灵活和可配置的Bean管理。通过使用这个注解,可以避免不必要的Bean创建,同时提供默认实现,增强了应用的灵活性和可维护性。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标签:缓存,Java,Spring,Bean,依赖,注解,Configuration
From: https://blog.csdn.net/weixin_46028606/article/details/143881416

相关文章

  • 基于Java+Springboot+Jpa+Mysql实现的在线网盘文件分享系统功能设计与实现二
    一、前言介绍:免费学习:猿来入此1.1项目摘要在线网盘文件分享系统的课题背景主要源于现代社会对数字化信息存储和共享需求的日益增长。随着互联网的普及和技术的快速发展,人们越来越依赖电子设备来存储和传输各种类型的数据文件。然而,传统的本地存储方式存在诸多不便,如空间有限、......
  • 2025最新-计算机毕业设计Java基于kubenetes的OpenStack私有云平台部署
    一、项目介绍  基于K8S的opoenstack私有云平台的监测系统通过对Web应用服务器运行情况的分析统计系统的建设以实现服务器运行数据监控与分析功能。私有云平台是web应用正常运行的核心,为了确保这些网站的稳定运行,势必需要做好对网站服务器的监控。做好对服务器运行的各......
  • JAVA反序列化学习-CommonsCollections6(基于ysoserial)
    环境准备JDK1.8(8u421)我以本地的JDK8版本为准、commons-collections(3.x4.x均可这里使用3.2版本)cc3.2:<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2</version>&l......
  • java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,
    @目录一、记录文件相关操作方法二、代码1.读取路径返回List<File>2.读取路径返回List<String>3.删除文件夹4.删除文件一、记录文件相关操作方法二、代码1.读取路径返回List<File>importorg.slf4j.LoggerFactory;importorg.slf4j.Logger;importjava.io.File;importjav......
  • Java小白成长记(创作笔记一)
    目录序言思维导图 开发流程新建SpringBoot并整合MybatisPlus        新建SpringBoot整合MybatisPlus统一结果封装全局异常处理引入数据库序言   在一个充满阳光的早晨,一位对编程世界充满好奇的年轻人小小白,怀揣着梦想与激情,踏上了学习Java编程的......
  • 146. LRU 缓存
    https://leetcode.cn/problems/lru-cache/description/?envType=study-plan-v2&envId=top-100-liked最近最久未使用,显然我们需要维护一个使用队列,最近使用过的在队尾,未使用过的靠近队首并且他要求函数get必须以O(1)的平均时间复杂度运行显然我们需要用到hashput必须以......
  • 面试题--Java反射
    目录获得一个类的class对象有哪些方式?1.使用.class属性:2.使用Class.forName方法:3.通过实例的getClass方法:4.通过类加载器:5.通过数组的getClass方法:6.通过Thread.currentThread().getContextClassLoader().loadClass:7.通过Method、Constructor等类的getDeclaringClass和getReturnT......
  • 你可能不知道的JavaScript-1
    目录1.防御式CSS2.js的应用领域JavaScript中让人迷惑的知识点3.一个网页URL从输入到浏览器中到显示经历过怎么样的解析过程呢4.浏览器内核1.是什么2.浏览器的渲染过程HTML解析CSS解析构建RenderTree3.回流与重绘1.回流(重排)2.重绘3.页面性能优化1.减少DOM操......
  • 基于SpringBoot+Vue的旅游网站管理系统设计与实现毕设(文档+源码)
    目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:         大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的旅游网站管理系统,项目源码请点击文章末尾联系我哦~目前有各类成品毕设JavaWeb......
  • 基于SpringBoot+Vue的论坛管理系统设计与实现毕设(文档+源码)
    目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:         大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的论坛管理系统,项目源码请点击文章末尾联系我哦~目前有各类成品毕设JavaWeb SSM......