Spring中的循环依赖
多个Bean之间互相引用,形成了一个循环的依赖关系。这种情况下,当Spring容器初始化这些Bean时,可能会出现问题,因为每个Bean在初始化时需要先创建依赖的Bean,而依赖的Bean又需要依赖其他的Bean,从而导致循环依赖问题。
Spring怎么解决循环依赖的
Spring会提前暴露还未初始化完成的Bean对象,这样在创建Bean时,即使有循环依赖,也可以通过提前暴露的引用来解决。这种方式适用于单例Bean,Spring也会为存在循环依赖的Bean创建一个代理对象,先创建一个代理对象作为依赖的引用,等到Bean初始化完成后,再将代理对象替换为实际的Bean,也可以使用构造器的方式进行注入,这样Bean在初始化时就可以得到它所依赖的Bean。
为什么要三级缓存?二级不行吗?
不行,他三级缓存是为了生成代理对象,如果是没有代理对象的情况他使用二级缓存是没有问题的。
@Autowired的实现原理
当Spring容器初始化时,会自动查找所有的Bean定义,然后尝试根据类的类型、名称等信息进行自动装配。在自动装配的过程中,Spring会查找与字段或方法参数类型匹配的Bean,然后将匹配的Bean注入到标注了@Autowired
的地方。Spring会通过Bean的构造函数、Setter方法或直接字段注入来完成依赖注入。
怎么理解Spring中的AOP
他是一种面向切面编程的思想,能够实现横切关注点的模块化,提高代码的复用性和可维护性,同时把横切关注点集中管理,使代码更清晰和可维护。
你平时怎么使用AOP的
在一些日志的打印和性能监控方面
说说JDK动态代理和CGLIB动态代理
JDK动态代理适用于接口,CGLIB动态代理适用于无接口类,通过生成子类实现代理。选用取决于是否有接口,JDK更通用,CGLIB适合无接口情况。
Spring事务隔离级别
Spring框架支持以下五种事务隔离级别:
- DEFAULT(默认) :使用底层数据库默认的事务隔离级别。
- READ_UNCOMMITTED(读未提交) :允许一个事务读取另一个事务未提交的数据。可能导致脏读、幻读、不可重复读问题。
- READ_COMMITTED(读已提交) :保证一个事务只能读取到另一个事务已提交的数据,可以避免脏读问题。
- REPEATABLE_READ(可重复读) :保证一个事务在整个过程中可以多次读取同一数据,不会受其他事务的影响。可以避免脏读、不可重复读问题。
- SERIALIZABLE(串行化) :最高的隔离级别,确保所有事务按照顺序依次执行,避免所有并发问题。
Spring事务传播行为
Spring框架中定义了七种事务传播行为,用于控制方法在不同事务上下文中的行为。以下是这些事务传播行为:
- REQUIRED(默认) :如果当前存在事务,则加入该事务;如果没有事务,则创建一个新事务。是最常用的传播行为。
- SUPPORTS :如果当前存在事务,则加入该事务;如果没有事务,则以非事务方式执行。
- MANDATORY :要求当前必须存在事务,否则会抛出异常。
- REQUIRES_NEW :无论当前是否存在事务,都会创建一个新事务,并在方法执行完毕后提交。
- NOT_SUPPORTED :无论当前是否存在事务,都会以非事务方式执行。
- NEVER :要求当前不存在事务,如果存在则抛出异常。
- NESTED :如果当前存在事务,则在嵌套事务中执行;如果没有事务,则执行REQUIRED类似的操作。
声明式事务在哪些情况下会失效
- 当在同一个类的方法中调用另一个方法,而调用的方法带有声明式事务注解,事务可能会失效;
- 捕获了异常而不重新抛出,声明式事务可能无法正确处理异常,导致事务无法回滚;
- 非公开方法(private、protected等)上的声明式事务无法被代理,因为代理通常基于接口或类的public方法,在声明式事务中,如果使用编程式事务(如
TransactionTemplate
)来管理事务,可能会导致事务失效; - 如果运行时异常被捕获并不再次抛出,事务可能无法正确回滚;
- 在多线程环境中,声明式事务可能无法正确传播,因为线程之间的事务隔离可能导致事务不生效。
Spring MVC的工作流程
- 客户端HTTP请求到Spring MVC应用的前端控制器
DispatcherServlet
DispatcherServlet
是Spring MVC的核心控制器,它接收到所有的客户端请求,并将请求分发给不同的控制器。- :
DispatcherServlet
会查询Handler Mapping,它会根据请求的URL找到匹配的控制器(Handler)。 - 找到匹配的控制器后,
DispatcherServlet
会将请求交给对应的Controller
进行处理。 Controller
处理请求后,会返回一个ModelAndView
对象,其中包含了模型数据和视图名。View Resolver
找到视图模板后,会将模型数据注入视图模板中,生成最终的HTML响应。- 生成的HTML响应会由
DispatcherServlet
返回给客户端,完成请求-处理-响应的循环。
Spring boot自动配置原理
Spring Boot的自动配置是通过条件注解、自动配置类、spring.factories
文件和配置属性等机制来实现的。条件注解判断何时应用自动配置,自动配置类提供预定义的Bean配置,spring.factories
文件列出自动配置类,配置属性影响自动配置行为。
如何自定义一个起步依赖
自定义Spring Boot起步依赖的步骤如下:
- 创建项目 :使用Maven或Gradle创建一个新项目,作为你的自定义起步依赖项目。
- 定义自动配置类 :在项目中创建一个自动配置类(带有
@Configuration
注解),在其中定义需要自动配置的Bean和逻辑。 - 创建条件注解 :编写一个自定义的条件注解(带有
@Conditional
注解),用于决定何时应用你的自动配置。这个条件注解可以根据特定的条件来判断是否应用你的配置。 - 创建
spring.factories
文件 :在src/main/resources/META-INF
目录下创建一个spring.factories
文件,其中列出自动配置类和条件注解的全限定名。这个文件会被Spring Boot自动扫描,用于加载自定义的自动配置。 - 编写README文档 :创建一个清晰的README文档,描述你的起步依赖的用途、功能和使用方法,帮助其他开发者理解如何使用它。
- 发布到仓库 :将你的自定义起步依赖打包,并将其发布到Maven或其他仓库中,以便其他项目可以通过依赖管理工具引入它。
Spring Cloud中的核心组件及其应用
- Eureka :Eureka是一个服务注册和发现的组件
- Ribbon :Ribbon是一个负载均衡的客户端
- Feign :Feign是一个声明式的HTTP客户端
- Hystrix :Hystrix是一个断路器和容错的库
- Zuul :Zuul是一个网关服务
- Config :Config用于集中管理微服务的配置信息
- Bus :Bus用于在微服务之间传播状态变化和事件
- Stream :Stream是一个事件驱动的微服务通信框架
- Sleuth :Sleuth用于分布式系统中的请求追踪和跟踪
- nacos
Spring 中应用了哪些设计模式呢?
- 工厂模式 : Spring 容器本质是一个大工厂,使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
- 代理模式 : Spring AOP 功能功能就是通过代理模式来实现的,分为动态代理和静态代理。
- 单例模式 : Spring 中的 Bean 默认都是单例的,这样有利于容器对 Bean 的管理。
- 模板模式 : Spring 中 JdbcTemplate、RestTemplate 等以 Template 结尾的对数据库、网络等等进行操作的模板类,就使用到了模板模式。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。ApplicationRunner
- 适配器模式 :Spring AOP 的增强或通知 (Advice) 使用到了适配器模式、Spring MVC 中也是用到了适配器模式适配 Controller。
- 策略模式:Spring 中有一个 Resource 接口,它的不同实现类,会根据不同的策略去访问资源。
说一说什么是 IOC? 什么是 DI?
IOC就是控制反转,将对象的创建、生命周期和对象的关系交给容器来管理,我们想要什么对象容器就给我们什么对象,DI的话就是当容器实例化一个对象的时候会把他的依赖对象注入给他
能说一下 Spring Bean 生命周期吗?
他分为四个阶段实例化(Instantiation)、属性赋值(Populate)、初始化(Initialization)、销毁(Destruction)
- 解析类得到BeanDefinition
- 如果有多个构造方法,则要推断构造方法
- 确定好构造方法后,进行实例化得到一个对象
- 对对象中的加了@Autowired注解的属性进行属性填充
- 回调Aware方法,比如BeanNameAware,BeanFactoryAware
- 调用BeanPostProcessor的初始化前的方法
- 调用初始化方法
- 调用BeanPostProcessor的初始化后的方法,在这里会进行AOP
- 如果当前创建的bean是单例的则会把bean放入单例池
- 使用bean
- Spring容器关闭时调用DisposableBean中destory(0方法
Spring 中的单例 Bean 会存在线程安全问题吗?
会存在,因为是单例的,所有线程都会使用这一个Bean,如果这个Bean是个无状态的,就是线程的操作对Bean中成员变量不会执行查询以外的操作他就是线程安全的。