spring相关问题_java面试问项目中遇到的问题「建议收藏」

spring相关问题_java面试问项目中遇到的问题「建议收藏」Spring相关高频面试题整理_springboot启动类无法引入常量类

目录

1.Spring Boot与以前的Spring有什么区别?

2.Spring Boot启动加载过程是什么样的?

3.Spring的IOC/AOP的实现(必考)

4.动态代理的实现方式(必考)是否使用过CGLiB,和JDK的区别是什么?

5.何时使用JDK还是CGLiB?如何强制使用CGLIB实现AOP?

6.Spring在选择用JDK还是CGLiB的依据是什么?CGlib比JDK快?

7.Spring如何解决循环依赖(三级缓存)(必考)

8.Spring中解决循环依赖为什么要用三级缓存,二级为什么不行呢?

9.spring能解决那些循环依赖、不能解决那些循环依赖,为什么?

10.Spring注入bean的方式有哪些(列举下你使用过的注入Bean的方式)?

11.Spring的后置处理器分析

12.BeanFactory和ApplicationContext的联系和区别

13.说说你对spring事务的理解?

14.Spring的@Transactional如何实现的(必考)

15.Spring的事务传播级别

16.Spring的事务隔离级别

17.Spring的事务失效场景分析

18.Spring的事务失效原因分析(必考)

19.Spring Cloud Zuul网关的调优策略有哪些?怎么实现其高可用?Zuul和Gataway,你们项目中是怎么选择的?项目中对Zuul网关层的要求是什么样的?

20.Spring Cloud Eureka和Nacos对比?怎么做选择?Eureka中高可用是怎么做的?进行的调优有哪些?原理是什么?

21.Spring Cloud 中常用的注解有哪些?怎么用的?

22.Spring Cloud中的组件有哪些?具体说说?微服务架构中用到的关键技术有哪些?

23.Spring Cloud Config配置架构是什么样的?可视化怎么做的?设计的业务有哪些?

参考书籍、文献和资料


备注:针对基本问题做一些基本的总结,不是详细解答!

1.Spring Boot与以前的Spring有什么区别?

具体可以见博客:Spring一些基础问题整理

Spring开发WEB应用程序过程广泛采用的固定开发模式:通常包括使用Maven、Gradle等工具搭建工程、web.xml定义Spring的DispatcherServlet、完成启动Spring MVC的配置文件、编写响应HTTP请求的Controller以及服务部署到Tomcat Web服务器等步骤。但是,基于传统Spring框架进行开发的开发过程中,逐渐暴露出一些问题,典型的就是过于复杂和繁重的配置工作

Spring Boot优化了开发过程,采用约定优于配置思想的自动化配置、启动依赖项目自动管理、简化部署并提供监控等功能,是开发过程变得简单。其核心优势体现在编码、配置、部署、监控等多个方面:

  • 编码方面:只需要在maven中添加依赖并实现一个方法就可以提供微服务架构所推荐的RESTful风格接口。
  • 配置方面简单化—>1>把Spring中基于XML的功能配置方式转换为Java Config;2>把基于*.properties/*.xml文件部署环境配置转换成语言更为强大的*.yml;3>对常见的各种功能组件均提供了各种默认的starter依赖以简化Maven的配置。
  • 部署方面:相较于传统模式下的war包,Spring Boot的部署既包含了业务代码和各种第三方类库,同时也内嵌了HTTP容器。新的部署方式包结构支持java-jar standalone.jar方式的一键启动,不需要预部署应用服务器,通过默认内嵌Tomcat降低对运行环境的基本要求。
  • 监控方面:基于spring-boot-actuator组件,可以通过RESTful接口以及HATEOAS表现方式获取JVM性能指标、线程工作状态等运行信息。

2.Spring Boot启动加载过程是什么样的?

Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法。在main方法中使用SpringApplication.run方法启动SpringBoot应用项目。

其中@SpringBootApplication是Spring Boot的核心注解,主要组合了@Configuration、@EnableAutoConfiguration、@ComponentScan。(如果不使用@SpringBootApplication注解,则可以使用在入口类上直接使用@Configuration、@EnableAutoConfiguration、@ComponentScan也能达到相同效果。)

其中几个注解的作用大致说一下:

  • @Configuration:是做类似于spring xml 工作的注解,标注在类上,类似与以前的**.xml配置文件。
  • @EnableAutoConfiguration:spring boot自动配置时需要的注解,会让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置。同时,它也是一个组合注解。
  • 在@EnableAutoConfiguration中用了@Import注解导入EnableAutoConfigurationImportSelector类,而EnableAutoConfigurationImportSelector就是自动配置关键。(SpringBoot的自动配置:SpringBoot的一大特色就是自动配置,例如,添加了spring-boot-starter-web依赖,会自动添加Tomcat和SpringMVC的依赖,SpringBoot会对Tomcat和SpringMVC进行自动配置。又例如:添加了spring-boot-starter-data-jpa依赖,SpringBoot会自动进行JPA相关的配置。)
  • @ComponentScan:告诉Spring 哪个packages 的用注解标识的类,会被spring自动扫描并且装入bean容器。SpringBoot会自动扫描@SpringBootApplication所在类的同级包以及下级包的Bean(如果为JPA项目还可以扫描标注@Entity的实体类),所以建议入口类放置在最外层包下。

spring-boot启动过程:

在这个静态方法中,创建并构造了SpringApplication对象,并调用该对象的run方法

构造SpringApplication对象:主要是对一些属性附上初始值,关键在与SpringApplication对象的initialize方法

  • 调用deduceWebEnvironment来判断当前的应用是否是web应用,并设置到webEnvironment属性中
  • 找出所有的应用程序初始化器调用getSpringFactoriesInstancesspring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后调用setInitializers方法设置到SpringApplicationinitializers属性
  • 找出所有的应用程序事件监听器,调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationListener的类并实例化,然后调用setListeners方法设置到SpringApplicationlisteners属性中。
  • 调用deduceMainApplicationClass方法找出main类

初始化SpringApplication完成之后,调用run方法运行,run方法执行完成之后,Spring容器也已经初始化完成,各种监听器和初始化器也做了相应的工作

  • 具体运行SpringApplication,重点由SpringApplicationRunListeners和SpringApplicationRunListener类实现
  • SpringApplicationRunListeners内部持有SpringApplicationRunListener集合和1个Log日志类用于SpringApplicationRunListener监听器的批量执行
  • SpringApplicationRunListener类:监听SpringApplication的run方法执行。
  • run具体的实现包括:配置并准备环境—>创建Spring容器上下文—>配置Spring容器上下文—>Spring容器创建之后回调方法postProcessApplicationContext—>初始化器开始工作—>Spring容器创建完成之后会调用afterRefresh方法

具体详细如下:

Spring一些基础问题整理

3.Spring的IOC/AOP的实现(必考)

IOC相关知识和回答见博客:Spring一些基础问题整理

AOP的实现方式:动态代理的实现方式

  • JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
  • CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
  • 区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。

4.动态代理的实现方式(必考)是否使用过CGLiB,和JDK的区别是什么?

实现方式有两种:JDK动态代理和CGLIB动态代理

相关更细的知识见博客:Spring一些基础问题整理

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类 ,使用的是 Java反射技术实现,生成类的过程比较高效
  • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 ,使用asm字节码框架实现,相关执行的过程比较高效,生成类的过程可以利用缓存弥补,因为是继承,所以该类或方法最好不要声明成final 
  • JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:实现InvocationHandler + 使用Proxy.newProxyInstance产生代理对象 + 被代理的对象必须要实现接口
  • CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理

5.何时使用JDK还是CGLiB?如何强制使用CGLIB实现AOP?

何时使用JDK还是CGLiB?

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
  • 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。

如何强制使用CGLIB实现AOP?

  • 添加CGLIB库(aspectjrt-xxx.jar、aspectjweaver-xxx.jar、cglib-nodep-xxx.jar)
  • 在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>

6.Spring在选择用JDK还是CGLiB的依据是什么?CGlib比JDK快?

Spring在选择用JDK还是CGLiB的依据:

  • 当Bean实现接口时,Spring会用JDK的动态代理。
  • 当Bean没有实现接口时,Spring使用CGlib是实现。
  • 如果Bean实现了接口,强制使用CGlib时,(添加CGLIB库,在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>)。

CGlib比JDK快?

使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类
在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐

7.Spring如何解决循环依赖(三级缓存)(必考)

Spring使用三级缓存(三级缓存是指singletonObjects、earlySingletonObjects和singletonFactories)来解决循环依赖的问题

下面是Spring如何解决循环依赖的简要过程:

  1. 创建对象实例:当Spring容器初始化时,它会扫描并创建所有的单例Bean。当创建一个Bean时,Spring会将其放入singletonFactories缓存中。
  2. 提前暴露对象引用:在创建Bean的过程中,当Spring遇到对其他Bean的依赖时,它会尽早暴露尚未完成初始化的Bean引用。这样,即使依赖关系中存在循环依赖,也可以获取到对方的引用。
  3. 创建完整的Bean实例:在Bean的创建过程中,如果存在循环依赖,Spring会在创建过程中暂停,将已经创建的部分Bean提前暴露给需要的地方。然后,Spring会尝试解决循环依赖,通过依赖注入完成剩余Bean的创建。这一过程会持续进行直到所有的Bean都被创建完成。
  4. 缓存Bean实例:当Bean创建完成后,Spring会将其放入singletonObjects缓存中,以便下次请求时直接返回已创建的实例。

总结起来,Spring通过三级缓存的机制,在Bean创建的过程中提前暴露引用并暂停创建,以解决循环依赖的问题。这种机制允许Spring容器在循环依赖的情况下正确地管理Bean的创建顺序,并确保每个Bean都可以获取到正确的依赖实例。

8.Spring中解决循环依赖为什么要用三级缓存,二级为什么不行呢?

在Spring框架中解决循环依赖问题时,使用三级缓存(三级缓存指的是singletonFactories、earlySingletonObjects和singletonObjects)是为了确保在循环依赖情况下能够正确地获取到完整的Bean对象。

为了更好地理解为什么需要三级缓存而不是二级缓存,让我们简要回顾一下Spring解决循环依赖的过程:

  • 第一阶段(提前暴露bean):Spring首先创建一个用于存储正在创建的Bean工厂的singletonFactories缓存。当一个Bean正在创建时,它会被提前暴露给其他正在被创建的Bean。
  • 第二阶段(提前暴露对象):同时,Spring将已经创建但尚未完全初始化的Bean存储在earlySingletonObjects缓存中。这样,当另一个Bean需要引用这个尚未完全初始化的Bean时,可以通过提前暴露的对象引用。
  • 第三阶段(完成创建):在完成Bean的创建和初始化后,Spring将该Bean从singletonFactories和earlySingletonObjects缓存中移除,并将其放入singletonObjects缓存中。这样,其他Bean在需要引用该Bean时,可以从singletonObjects缓存中获取到完整的Bean对象。

现在回到你的问题,为什么二级缓存(即earlySingletonObjects)不能满足解决循环依赖的需求?

在循环依赖的场景中,两个Bean相互依赖,即A依赖于B,同时B也依赖于A。如果只使用二级缓存,当创建Bean A时,它会从二级缓存(earlySingletonObjects)中获取Bean B的引用,但是Bean B此时可能尚未完全初始化,只是一个尚未初始化的对象。这样,当Bean A依赖于Bean B的某些属性或方法时,可能会出现空指针异常或不完整的对象状态。

为了避免这种情况,Spring使用三级缓存。在三级缓存中,当Bean A创建时,它会从singletonFactories缓存中获取Bean B的创建工厂,并将其作为未完全初始化的Bean对象暴露给Bean B。当Bean B需要引用Bean A时,它可以从earlySingletonObjects缓存中获取到已经创建但尚未完全初始化的Bean A。这样可以确保在循环依赖的情况下,每个Bean都能够获取到一个完整的但尚未初始化的引用,从而避免了循环依赖的问题。

因此,使用三级缓存是为了保证在循环依赖场景下的Bean获取的正确性和完整性。二级缓存(earlySingletonObjects)只提供了尚未完全初始化的Bean对象的引用,而无法确保完整的Bean状态

9.spring能解决那些循环依赖、不能解决那些循环依赖,为什么?

Spring能够解决的循环依赖情况

  1. 构造函数循环依赖:当两个或多个Bean的构造函数参数中存在相互依赖时,Spring可以通过提前暴露尚未完成初始化的Bean引用来解决循环依赖。Spring会创建一个代理对象作为占位符,并将其注入到其他依赖中,等到循环依赖解决后再填充真正的对象。
  2. setter方法循环依赖:如果循环依赖是通过setter方法进行的,Spring同样可以通过提前暴露引用的方式解决循环依赖问题。Spring会在创建Bean时将占位符注入到其他依赖中,并在循环依赖解决后再填充实际的Bean。

Spring不能解决的循环依赖情况:

  1. 单例Bean的循环依赖:如果两个或多个单例Bean之间存在循环依赖,Spring无法解决该问题。这是因为单例Bean的创建和初始化是在容器启动时进行的,无法在运行时通过代理对象进行延迟初始化。在这种情况下,Spring会抛出BeanCurrentlyInCreationException异常,指示循环依赖无法解决。
  2. 原型(Prototype)Bean的循环依赖:Spring容器不会检测原型Bean之间的循环依赖,因为原型Bean的创建是在每次请求时进行的,无法通过缓存和代理来解决循环依赖问题。在原型Bean之间存在循环依赖时,Spring容器可能会进入无限递归的创建过程,最终导致StackOverflowError。

总结起来,Spring可以解决构造函数和setter方法的循环依赖情况,但无法解决单例Bean和原型Bean之间的循环依赖。这是因为单例Bean在启动时创建,无法进行延迟初始化,而原型Bean的创建是每次请求时进行的,无法通过缓存来解决循环依赖。在设计应用程序时,应避免出现循环依赖,以减少潜在的问题。

10.Spring注入bean的方式有哪些(列举下你使用过的注入Bean的方式)?

Spring提供了多种注入Bean的方式,以下是一些常用的注入方式:

  1. 构造函数注入(Constructor Injection):通过构造函数将依赖注入到目标Bean中。可以在Bean的构造函数上使用@Autowired注解或者在XML配置文件中使用<constructor-arg>元素进行注入。
  2. Setter方法注入(Setter Injection):通过Setter方法将依赖注入到目标Bean中。可以在Bean的Setter方法上使用@Autowired注解或者在XML配置文件中使用<property>元素进行注入。
  3. 字段注入(Field Injection):通过直接注入字段的方式将依赖注入到目标Bean中。可以在字段上使用@Autowired注解进行注入。
  4. 接口注入(Interface Injection):通过实现接口,在接口方法中进行依赖注入。一般较少使用。
  5. 配置方法注入(Configuration Method Injection):通过在配置类中使用@Bean注解,并在方法参数上使用@Autowired注解,将依赖注入到方法中。该方法在配置类中被调用,并返回所需的Bean实例。

在我使用过的注入Bean的方式中,我主要使用了构造函数注入和Setter方法注入。构造函数注入常用于必须的依赖,而Setter方法注入则用于可选的依赖或需要动态变化的依赖。这两种方式都可以通过@Autowired注解来实现依赖注入。

11.Spring的后置处理器分析

在Spring框架中,后置处理器(PostProcessor)是一种特殊的Bean,用于在容器中创建和配置其他Bean时进行干预和定制。后置处理器可以在Bean的实例化、属性填充和初始化等阶段介入,并对Bean进行修改、增强或扩展功能。

Spring框架提供了多个后置处理器接口,其中最常用的是BeanPostProcessor接口。其定义了两个核心方法:

  1. postProcessBeforeInitialization:在Bean的初始化方法(如@PostConstruct注解标记的方法或实现了InitializingBean接口的afterPropertiesSet方法)调用之前,对Bean进行自定义处理。
  2. postProcessAfterInitialization:在Bean的初始化方法调用之后,对Bean进行自定义处理。

通过实现BeanPostProcessor接口,可以在Bean的初始化前后执行一些自定义逻辑,例如在Bean初始化后添加某些功能、修改属性值、应用AOP切面等。另外,Spring还提供了其他的后置处理器接口,例如BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,它们分别用于处理Bean定义和Bean工厂的配置。

使用后置处理器可以实现以下功能:

  1. AOP切面:通过后置处理器可以动态为Bean添加切面逻辑,实现面向切面编程的功能。
  2. 属性加密/解密:通过后置处理器可以在Bean的属性注入前后对敏感信息进行加密或解密操作。
  3. 校验和验证:通过后置处理器可以在Bean的初始化前后进行校验和验证操作,确保Bean的正确性。
  4. 动态代理:通过后置处理器可以对Bean进行代理,实现动态扩展和拦截功能。
  5. 自定义注解处理:通过后置处理器可以处理自定义注解,实现特定逻辑。

需要注意的是,使用后置处理器要谨慎,因为它们会对容器中的所有Bean进行处理,可能会对系统的性能产生一定的影响。因此,在使用后置处理器时,应该确保逻辑简洁高效,并仅对需要进行特殊处理的Bean进行干预。

12.BeanFactory和ApplicationContext的联系和区别

BeanFactory和ApplicationContext都是Spring框架中用于管理和获取Bean的核心接口,它们有联系和区别如下:

联系:

  1. 继承关系:ApplicationContext接口是BeanFactory接口的子接口,因此ApplicationContext是BeanFactory的扩展
  2. Bean管理:BeanFactory和ApplicationContext都提供了获取和管理Bean的功能,可以通过它们获取Bean实例、配置和管理Bean的生命周期等。

区别:

  1. 配置加载方式:BeanFactory是Spring的基础接口,它的实现类在应用启动时延迟加载Bean的定义和配置。而ApplicationContext在初始化时就会读取并解析Bean的定义和配置,提前实例化Bean。
  2. 配置元数据缓存:ApplicationContext在加载配置时会将Bean的定义和配置元数据进行缓存,以便快速获取和实例化Bean。而BeanFactory每次获取Bean时都需要解析配置,没有缓存机制。
  3. AOP支持:ApplicationContext提供了对AOP(面向切面编程)的支持,可以自动代理切面,实现声明式事务、日志等功能。而BeanFactory需要手动配置和集成AOP相关的组件。
  4. 国际化支持:ApplicationContext提供了国际化支持,可以方便地处理多语言和本地化的问题。而BeanFactory没有内置的国际化支持。
  5. 额外功能:ApplicationContext提供了更多的企业级特性,如事件发布、资源加载、Spring表达式语言(SpEL)的支持等。而BeanFactory提供的功能相对较少,主要关注于Bean的创建和管理。

总结起来,BeanFactory是Spring框架的基础接口,提供了基本的Bean管理功能;而ApplicationContext是对BeanFactory的扩展,提供了更多的高级功能和企业级特性。在实际应用中,ApplicationContext更常用,因为它提供了更多的便利和功能,并且通常能够满足大多数应用场景的需求。

13.说说你对spring事务的理解?

Spring事务是Spring框架提供的一种机制,用于管理数据库操作或其他资源访问的一系列操作,以保证数据的一致性和可靠性。事务的概念是指一组操作被视为一个不可分割的工作单元,要么全部成功提交,要么全部回滚,以确保数据的完整性。

以下是对Spring事务的一些理解:

  1. 原子性(Atomicity):事务应该被视为一个原子操作,要么全部成功执行,要么全部失败回滚。如果事务中的任何一个操作失败,所有的操作都将回滚到事务开始前的状态。
  2. 一致性(Consistency):事务在执行前和执行后都必须保持系统的一致性。这意味着事务在执行期间对数据进行的修改必须满足预定义的约束,以确保数据的有效性和正确性。
  3. 隔离性(Isolation):事务的隔离级别定义了事务之间的相互影响程度。Spring提供了多个隔离级别,如读未提交、读已提交、可重复读和串行化。每个隔离级别都有不同的特点,用于解决并发访问数据时可能出现的问题,如脏读、不可重复读和幻读。
  4. 持久性(Durability):事务提交后,对数据的修改将永久保存在数据库中,即使系统发生故障或重启,也能够保持数据的一致性。
  5. 声明式事务管理:Spring提供了声明式事务管理的方式,通过使用@Transactional注解或XML配置来定义事务的边界和属性。这种方式使得开发者可以将注意力集中在业务逻辑上,而无需过多关注事务管理的细节。
  6. 事务传播行为:Spring事务支持不同的传播行为,用于处理多个事务方法之间的事务边界。例如,当一个事务方法调用另一个事务方法时,可以选择将新方法加入到现有事务中,或者开启一个新的事务,或者将新方法设置为不受事务管理。
  7. 编程式事务管理:除了声明式事务管理,Spring还支持编程式事务管理,允许开发者以编程的方式控制事务的开始、提交、回滚等操作。

Spring事务的设计目标是提供一种灵活、可扩展和易用的事务管理机制,使开发者能够轻松地实现和管理事务,确保数据操作的一致性和可靠性。通过Spring的事务管理,开发者可以专注于业务逻辑的实现,而无需过多关注底层事务管理的细节。

更加细节的和原理内容见:Spring一些基础问题整理

14.Spring的@Transactional如何实现的(必考)

@Transactional是spring中声明式事务管理的注解配置方式,@Transactional注解可以帮助我们把事务开启、提交或者回滚的操作,通过aop的方式进行管理。通过@Transactional注解就能让spring为我们管理事务,免去了重复的事务管理逻辑,减少对业务代码的侵入,使我们开发人员能够专注于业务层面开发。

spring相关问题_java面试问项目中遇到的问题「建议收藏」

实现@Transactional原理是基于spring aop,aop又是动态代理模式的实现。主要源码如下:

spring相关问题_java面试问项目中遇到的问题「建议收藏」

15.Spring的事务传播级别

事务传播行为(为了解决业务层方法之间互相调用的事务问题):当事务方法被另一个事务方法调用时,必须指定事务应该如何传播

例如:方法可能继续在现有事务中运行,也可能开启一个新事务并在自己的事务中运行

在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况:

  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

16.Spring的事务隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能,通常情况下也不会用到该级别。

spring相关问题_java面试问项目中遇到的问题「建议收藏」

17.Spring的事务失效场景分析

以下是一些可能导致Spring事务失效的场景:

  1. 方法没有被代理:Spring的事务管理是基于代理模式实现的,如果调用事务方法的对象不是通过Spring容器获取的,或者方法调用是内部的(即在同一个类中调用),那么Spring无法对该方法应用事务代理,事务将不起作用。
  2. 异常未被捕获或被吞没:Spring事务默认只对未捕获的运行时异常(RuntimeException)进行回滚。如果方法抛出的异常被捕获并在捕获块中处理,而没有重新抛出或标记为unchecked异常,事务将不会回滚。
  3. 事务方法被声明为final:如果一个方法被声明为final,它将无法被Spring生成的代理类覆盖,导致事务无法应用于该方法。
  4. 事务方法内部调用其他事务方法:当一个事务方法内部调用另一个事务方法时,默认情况下,外部事务将被挂起,内部事务将作为独立的事务执行。如果内部事务抛出异常,外部事务不会回滚。要解决这个问题,可以使用编程式事务或设置事务传播行为。
  5. 事务方法与非事务方法混合调用:如果一个事务方法内部调用一个非事务方法,非事务方法将不会参与到事务中,无法进行事务管理。需要确保所有相关方法都被事务代理所覆盖,以便正确管理事务。
  6. 不正确的事务配置:如果事务管理器配置不正确或事务注解的属性设置错误,也可能导致事务失效。例如,事务超时时间设置不合理、隔离级别设置不正确等。

为了避免Spring事务失效,需要注意以上场景,并合理配置和使用事务管理器、事务注解和事务传播行为。同时,了解事务的特性和使用方式,以及特定场景下的注意事项,可以帮助保证事务的正确应用和有效性。

18.Spring的事务失效原因分析(必考)

事务失效的原因可能包括以下几个方面:

  1. 配置错误:事务管理器或事务注解的配置错误可能导致事务失效。例如,事务管理器的配置错误、事务注解的属性设置错误(如超时时间、隔离级别等),都可能导致事务无法正确应用或生效。
  2. 不支持的数据访问方式:某些数据访问方式可能不受事务管理的支持,例如直接使用JDBC操作数据库而绕过Spring的事务管理,或者使用第三方的ORM框架而未集成到Spring的事务管理中。
  3. 方法调用问题:Spring的事务管理是基于代理模式实现的,如果调用事务方法的对象不是通过Spring容器获取的,或者方法调用是内部的(即在同一个类中调用),Spring无法对该方法应用事务代理,事务将不起作用。
  4. 异常处理:事务默认只对未捕获的运行时异常(RuntimeException)进行回滚。如果方法抛出的异常被捕获并在捕获块中处理,而没有重新抛出或标记为unchecked异常,事务将不会回滚。
  5. 事务传播行为:当一个事务方法内部调用另一个事务方法时,默认情况下,外部事务将被挂起,内部事务将作为独立的事务执行。如果内部事务抛出异常,外部事务不会回滚。正确配置事务传播行为可以解决此问题。
  6. 不正确的事务边界:事务的边界应该正确定义,确保事务包含了需要进行事务管理的一系列操作。如果事务边界定义不正确,可能导致事务无法覆盖到需要的操作上,或者覆盖了不需要事务管理的操作。
  7. 并发问题:并发操作可能导致事务失效,例如脏读、不可重复读和幻读等。在并发环境下,需要正确选择和配置事务的隔离级别,以及使用乐观锁或悲观锁等机制来解决并发问题。

了解这些原因可以帮助开发者在使用Spring事务时注意相关细节,合理配置事务管理器和事务注解,并确保事务在应用中正确生效和回滚,以保证数据操作的一致性和可靠性。

19.Spring Cloud Zuul网关的调优策略有哪些?怎么实现其高可用?Zuul和Gataway,你们项目中是怎么选择的?项目中对Zuul网关层的要求是什么样的?

详细内容查看:Spring一些基础问题整理

Spring Cloud Zuul网关的调优策略

Zuul 1.0 是一个基于JVM的后端路由器,同时是一个建立在Servlet上的同步阻塞架构,故在使用时对这部分的优化工作是必要的,根据实践经验,对Zuul的优化分为以下几个类型:

  • 容器优化:内置容器Tomcat与Undertow的比较与参数设置;
  • 组件优化:内部集成的组件优化,如Hytrix线程隔离、Ribbon、HttpClient与OkHttp选择;
  • JVM参数优化:适合于网关应用的JVM参数建议;
  • 内部优化:一些原生参数或者内部源码,以更适当的方式进行重写。

高可用方案

Spring Cloud Zuul网关高可用可以借助OpenResty整合的Nginx和Lua,使用Lua脚本模块与注册中心构建一个服务动态增减的机制,通过Lua获取注册中心状态为UP的服务,动态地加入到Nginx的负载均衡列表中,将其称之为“多层负载”

其实也可以结合K8S特性去实现,这个之前玩K8S的时候试验过,是可以实现的!

Zuul和Gataway对比和选择

从底层源码上来看,Zuul构建于 Servlet 2.5,兼容 3.x,使用的是阻塞式的 API,不支持长连接,比如 websockets。另外

Spring Cloud Gateway构建于 Spring 5+,基于 Spring Boot 2.x 响应式的、非阻塞式的 API。同时,它支持 websockets,和 Spring 框架紧密集成,开发体验相对来说十分不错。

在微服务架构中网关上的选择,最好的方式是使用现在比较成熟的Spring Cloud套件,Zuul和Gataway都可以,最好提供了Spring Cloud Gateway网关,或是结合公司情况来开发一套适合自己的微服务套件,至少从网关上可以看出来其内部实现并不难,同时也比较期待开源项目Nacos、Spring Cloud Alibaba 建设情况,期待它能构建一个高活跃社区的、稳定的、适合中国特色(大流量、高并发)的微服务基础架构。

项目中对网关的要求

基本具备以下功能:认证和鉴权+压力控制+金丝雀测试+动态路由+负载均衡+静态响应处理+主动流量控制+限流+文件上传+参数转换+其他逻辑与业务处理等

20.Spring Cloud Eureka和Nacos对比?怎么做选择?Eureka中高可用是怎么做的?进行的调优有哪些?原理是什么?

详细请查看:Spring一些基础问题整理

都是服务注册发现中心,但是Nacos还可以用作配置中心,目前来看,建议使用Nacos,因为Eureka已经不在开源,而且性能上和高可用上没有Nacos方便。

相关调优方案见上面的博客。

21.Spring Cloud 中常用的注解有哪些?怎么用的?

  • @Controller 控制层,里面有多个连接
  • @Service 业务层,一般对于接口和实现
  • @Qualifier 如果一个接口有多个实现,那么注入时候加上唯一标示
  • @Repository 一般的dao层
  • @Autowired 自动注入依赖
  • @RequestMapping (value=’’,method={RequestMethod。GET或者POSt})绑定url
  • @RequestParam (value=’’ required=false)绑定参数
  • @ModelAttribute 一般用于controller层,呗注解的方法会在所以mapping执行之前执行,并且可以绑定参数到Model model里面。
  • @Transactional (readOnly=true)注解式事务
  • @Value(“${}”)可以注入properties里面的配置项
  • @ControllerAdvice 是spring3提供的新注解,控制器增@ExceptionHandler 如果在controller方法遇到异常,就会调用含有此注解的方法。@EnableDiscoveryClient 与@EnableEurekaCLient 具有相同的功能,不同的事该注解同时可以注册Zookeper,也可用于服务发现,标注在主启动类上;
  • @InitBinder 一般用于controller 可以将所有form 传递进来的string 进行html编码,防止xss攻击,比如可以将字符串类型的日期转换成date类型
  • @EnableCaching 注解自动化配置合适的缓存管理器。
  • @EnableWebSecurity 注解开启spring security的功能,集成websercrityconfigureadapter。
  • @SringBootApplication相当于@Configuation、@EnableAutoConfiguation、@ComponentScan三个注解合用。
  • @EnableDiscoveryClient 自定义服务发现的客服端
  • @EnableAdminServer 使用admin监控应用。
  • @EnableEurekaClient配置本应用将使用服务注册和服务发现,注意:注册和发现用这个注解。
  • @EnableHystrix表示启动断路器,断路器依赖于服务注册和发现。
  • @HystrixCommand注解方法失败后,系统将西东切换到fallbackMethod方法执行,
  • @EnableAutoConfiguration spring boot自动配置,尝试根据你添加的jar依赖自动配置你的spring应用。
  • @ComponentScan 表示将该类自动发现并注册bean 可以自动收集所有的spring组件
  • @Comfiguration 相当于传统的xml配置文件
  • @Import 导入其他配置类
  • @ImportResource用来 加载xml配置文件
  • @FeignClient注解中的fallbank属性指定回调类
  • @ResController是@controller和@ResponseBody的结合体
  • @EnableDiscoveryClient 与@EnableEurekaCLient 具有相同的功能,不同的事该注解同时可以注册Zookeper,也可用于服务发现,标注在主启动类上;

22.Spring Cloud中的组件有哪些?具体说说?微服务架构中用到的关键技术有哪些?

在介绍Spring Cloud 全家桶之前,首先要介绍一下Netflix ,Netflix 是一个很伟大的公司,在Spring Cloud项目中占着重要的作用,Netflix 公司提供了包括Eureka、Hystrix、Zuul、Archaius等在内的很多组件,在微服务架构中至关重要,Spring在Netflix 的基础上,封装了一系列的组件。

相关具体组件见:Spring一些基础问题整理

关键技术及要求基本有:

微服务架构-实现技术之六大基础组件:服务通信+事件驱动+负载均衡+服务路由+API网关+配置管理

对应博客:Spring一些基础问题整理

微服务架构-实现技术之三大关键要素1服务治理:服务注册中心+服务发布与注册+服务发现与调用+服务监控

对应博客:Spring一些基础问题整理

微服务架构-实现技术之三大关键要素2数据一致性:分布式事物+CAP&BASE+可靠事件模式+补偿模式+Sagas模式+TCC模式+最大努力通知模式+人工干预模式

对应博客:Spring一些基础问题整理

微服务架构-实现技术之三大关键要素3服务可靠性:服务访问失败的原因和应对策略+服务容错+服务隔离+服务限流+服务降级

对应博客:Spring一些基础问题整理

23.Spring Cloud Config配置架构是什么样的?可视化怎么做的?设计的业务有哪些?

具体见博客:Spring一些基础问题整理

参考书籍、文献和资料

1.SpringBoot启动过程 | wangqi的blog  Spring Boot启动加载过程讲的很详细

2.微服务架构-实现技术之具体实现工具与框架2:Spring Boot概览与核心原理_张彦峰ZYF的博客-CSDN博客

3.Spring Boot 学习笔记一(SpringBoot启动过程)_小沙弥修BUG的博客-CSDN博客

4.https://www.cnblogs.com/liubin1988/p/8909610.html

5.Java动态代理详解:JDK和CGLIB的区别和实现_Yanyan.He的博客-CSDN博客  动态代理的举例

6.https://www.cnblogs.com/wangenxian/p/10885309.html

7.https://www.cnblogs.com/gonjan-blog/p/6685611.html

8.Spring源码初探-IOC(4)-Bean的初始化-循环依赖的解决 – 简书

9.spring源码阅读–@Transactional实现原理_@transactional原理_一撸向北的博客-CSDN博客

10.Spring @Transactional工作原理详解_Java_软件编程 – 编程客栈

11.IBM Developer

12.https://www.cnblogs.com/chongaizhen/p/11003832.html

13.Spring一些基础问题整理

14.Spring Cloud Gateway VS Zuul 比较,怎么选择?_Java技术栈的博客-CSDN博客

15.微服务网关Zuul和Gateway的区别_gateway和zuul的区别与联系_莫明的编织者的博客-CSDN博客

16.Spring Cloud 常用注解注解_springcloud 常用注解_-Se7ven的博客-CSDN博客

17.微服务架构-实现技术之具体实现工具与框架4:Spring Cloud Eureka原理与注意事项_张彦峰ZYF的博客-CSDN博客

18.Spring Cloud全家桶主要组件及简要介绍_springcloud五大组件_徐刘根的博客-CSDN博客

19.【第二章】 IoC 之 2.1 IoC基础 ——跟我学Spring3 – 《亿级流量网站架构核心技术》~ – ITeye博客

20.百度安全验证

今天的文章spring相关问题_java面试问项目中遇到的问题「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/78103.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注