Spring一些基础问题整理

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

1.Spring Boot与以前的Spring有什么区别?
具体可以见博客:
微服务架构具体实现工具框架:Spring Boot概览与核心原理
https://blog.csdn.net/xiaofeng10330111/article/details/87271456#1.%E5%9B%9E%E9%A1%BE%E4%BD%BF%E7%94%A8Spring%E5%BC%80%E5%8F%91WEB%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E8%BF%87%E7%A8%8B

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属性中。
找出所有的应用程序初始化器,调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后调用setInitializers方法设置到SpringApplication的initializers属性中。
找出所有的应用程序事件监听器,调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationListener的类并实例化,然后调用setListeners方法设置到SpringApplication的listeners属性中。
调用deduceMainApplicationClass方法找出main类
初始化SpringApplication完成之后,调用run方法运行,run方法执行完成之后,Spring容器也已经初始化完成,各种监听器和初始化器也做了相应的工作。

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

分析SpringBoot启动配置原理_张彦峰ZYF的博客-CSDN博客
分析SpringBoot启动配置原理:给出整体初步分析和对应流程图,并从三方面进行展开分析(SpringApplication构造过程分析+SpringApplication启动过程分析+SpringBoot自动配置分析)
https://blog.csdn.net/xiaofeng10330111/article/details/85253251?spm=1001.2014.3001.5501

3.Spring的IOC/AOP的实现(必考)
IOC相关知识和回答见博客:
对IOC的相关理解总结_说一下你对ioc的理解_张彦峰ZYF的博客-CSDN博客
目录一、对IOC和DI的基本认识(一)理解IoC,即“控制反转”(二)IoC具体做什么?(三)理解IoC和DI的关系二、对IOC容器初始化的理解四、对DI依赖注入的理解(主要是)参考书籍、文献和资料一、对IOC和DI的基本认识(一)理解IoC,即“控制反转”在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解好...
https://blog.csdn.net/xiaofeng10330111/article/details/105631666

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

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

相关更细的知识见博客:
代理模式的使用总结_张彦峰ZYF的博客-CSDN博客
目录一、代理模式二、静态代理(一)静态代理(二)静态代理简单实现三、动态代理(一)动态代理(二)动态代理简单实现四、动态代理原理分析五、InvocationHandler接口和Proxy类详解六、JDK动态代理和CGLIB动态代理代码示例比较与总结(一)定义创建用户管理接口(二)用户管理实现类,实现用户管理接口(被代理的实现类)(三)采用JDK代...
https://blog.csdn.net/xiaofeng10330111/article/details/105633821

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如何解决循环依赖的简要过程:

创建对象实例:当Spring容器初始化时,它会扫描并创建所有的单例Bean。当创建一个Bean时,Spring会将其放入singletonFactories缓存中。
提前暴露对象引用:在创建Bean的过程中,当Spring遇到对其他Bean的依赖时,它会尽早暴露尚未完成初始化的Bean引用。这样,即使依赖关系中存在循环依赖,也可以获取到对方的引用。
创建完整的Bean实例:在Bean的创建过程中,如果存在循环依赖,Spring会在创建过程中暂停,将已经创建的部分Bean提前暴露给需要的地方。然后,Spring会尝试解决循环依赖,通过依赖注入完成剩余Bean的创建。这一过程会持续进行直到所有的Bean都被创建完成。
缓存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能够解决的循环依赖情况:

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

单例Bean的循环依赖:如果两个或多个单例Bean之间存在循环依赖,Spring无法解决该问题。这是因为单例Bean的创建和初始化是在容器启动时进行的,无法在运行时通过代理对象进行延迟初始化。在这种情况下,Spring会抛出BeanCurrentlyInCreationException异常,指示循环依赖无法解决。
原型(Prototype)Bean的循环依赖:Spring容器不会检测原型Bean之间的循环依赖,因为原型Bean的创建是在每次请求时进行的,无法通过缓存和代理来解决循环依赖问题。在原型Bean之间存在循环依赖时,Spring容器可能会进入无限递归的创建过程,最终导致StackOverflowError。
总结起来,Spring可以解决构造函数和setter方法的循环依赖情况,但无法解决单例Bean和原型Bean之间的循环依赖。这是因为单例Bean在启动时创建,无法进行延迟初始化,而原型Bean的创建是每次请求时进行的,无法通过缓存来解决循环依赖。在设计应用程序时,应避免出现循环依赖,以减少潜在的问题。

10.Spring注入bean的方式有哪些(列举下你使用过的注入Bean的方式)?
Spring提供了多种注入Bean的方式,以下是一些常用的注入方式:

构造函数注入(Constructor Injection):通过构造函数将依赖注入到目标Bean中。可以在Bean的构造函数上使用@Autowired注解或者在XML配置文件中使用<constructor-arg>元素进行注入。
Setter方法注入(Setter Injection):通过Setter方法将依赖注入到目标Bean中。可以在Bean的Setter方法上使用@Autowired注解或者在XML配置文件中使用<property>元素进行注入。
字段注入(Field Injection):通过直接注入字段的方式将依赖注入到目标Bean中。可以在字段上使用@Autowired注解进行注入。
接口注入(Interface Injection):通过实现接口,在接口方法中进行依赖注入。一般较少使用。
配置方法注入(Configuration Method Injection):通过在配置类中使用@Bean注解,并在方法参数上使用@Autowired注解,将依赖注入到方法中。该方法在配置类中被调用,并返回所需的Bean实例。
在我使用过的注入Bean的方式中,我主要使用了构造函数注入和Setter方法注入。构造函数注入常用于必须的依赖,而Setter方法注入则用于可选的依赖或需要动态变化的依赖。这两种方式都可以通过@Autowired注解来实现依赖注入。

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

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

postProcessBeforeInitialization:在Bean的初始化方法(如@PostConstruct注解标记的方法或实现了InitializingBean接口的afterPropertiesSet方法)调用之前,对Bean进行自定义处理。
postProcessAfterInitialization:在Bean的初始化方法调用之后,对Bean进行自定义处理。
通过实现BeanPostProcessor接口,可以在Bean的初始化前后执行一些自定义逻辑,例如在Bean初始化后添加某些功能、修改属性值、应用AOP切面等。另外,Spring还提供了其他的后置处理器接口,例如BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,它们分别用于处理Bean定义和Bean工厂的配置。

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

AOP切面:通过后置处理器可以动态为Bean添加切面逻辑,实现面向切面编程的功能。
属性加密/解密:通过后置处理器可以在Bean的属性注入前后对敏感信息进行加密或解密操作。
校验和验证:通过后置处理器可以在Bean的初始化前后进行校验和验证操作,确保Bean的正确性。
动态代理:通过后置处理器可以对Bean进行代理,实现动态扩展和拦截功能。
自定义注解处理:通过后置处理器可以处理自定义注解,实现特定逻辑。
需要注意的是,使用后置处理器要谨慎,因为它们会对容器中的所有Bean进行处理,可能会对系统的性能产生一定的影响。因此,在使用后置处理器时,应该确保逻辑简洁高效,并仅对需要进行特殊处理的Bean进行干预。

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

联系:

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

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

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

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

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

更加细节的和原理内容见:
分析Spring事务管理原理及应用_张彦峰ZYF的博客-CSDN博客
通过配置已经大体知道了spring事务管理实现的原理就是AOP,不难推测,spring会提供实现事务管理相关功能的切面,切点和通知相关的类,来完成对于事务相关功能的支持。我们以配置最简单的注解式配置为例,分析其实现方式。
https://zyfcodes.blog.csdn.net/article/details/130061447?spm=1001.2014.3001.5502

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


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

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的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能,通常情况下也不会用到该级别。


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

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

18.Spring的事务失效原因分析(必考)
事务失效的原因可能包括以下几个方面:

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

19.Spring Cloud Zuul网关的调优策略有哪些?怎么实现其高可用?Zuul和Gataway,你们项目中是怎么选择的?项目中对Zuul网关层的要求是什么样的?
详细内容查看:
微服务架构Spring Cloud Zuul原理与注意事项
https://blog.csdn.net/xiaofeng10330111/article/details/87272495#%E4%BA%94%E3%80%81Spring%20Cloud%20Zuul%E5%BA%94%E7%94%A8%E4%BC%98%E5%8C%96%E5%88%86%E6%9E%90

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 Cloud Eureka原理与注意事项
目录一、服务发现与注册的由来1.单体架构时代2.SOA时代方式一方式二3.微服务时代方案一方案二二、服务发现与注册的技术选型与Eureka简介1.服务发现与注册的技术选型2.Eureka简介3.新的替换方案---Nacos三、Eureka设计理念1.主要解决的三大问题服务实例如何注册到服务中心服务实例如何从服务中心剔除服务...
https://blog.csdn.net/xiaofeng10330111/article/details/87271881

都是服务注册发现中心,但是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 Cloud概述和基本讲解
https://blog.csdn.net/xiaofeng10330111/article/details/87271644#%E4%BA%8C%E3%80%81Spring%20Cloud%E7%9B%B8%E5%85%B3%E7%BB%84%E4%BB%B6%E6%88%90%E5%91%98%E6%A1%86%E6%9E%B6

关键技术及要求基本有:

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

对应博客:
微服务架构-实现技术之六大基础组件:服务通信+事件驱动+负载均衡+服务路由+API网关+配置管理_服务之间的通信现成的组件有哪些_张彦峰ZYF的博客-CSDN博客
微服务架构的实现首先需要提供一些基础组件,这些基础的功能性组件主要包括服务之间的通信、面向事件驱动的架构设计方法、负载均衡、服务路由、API网关和分布式配置中心等,我们对这六大基本组件进行初步的分析定案。一、服务通信:网络连接+IO模型+可靠性+同步与异步对于微服务而言,网络通信主要关注于网络连接、IO模型、可靠性设计及服务调用方式。1.网络连接一般,基于TCP网络连接有两种基本方...
https://blog.csdn.net/xiaofeng10330111/article/details/85682513

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

对应博客:
微服务架构服务治理:服务注册中心+服务发布与注册+服务发现与调用+服务监控
目录一、服务注册中心:注册中心核心功能+实现策略1.注册中心核心功能2.注册中心实现策略二、服务发布与注册三、服务发现与调用四、服务监控基本思路:日志埋点基本目标:基本定位:基本策略:具体实现:参考书籍、文献和资料:服务治理在面临系统存在大量服务时可以解决基本的三大定位问题:提升服务架构的可扩展性;有效的服务监控和故障定位;对服务的有效划分和路由...
https://blog.csdn.net/xiaofeng10330111/article/details/86770057

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

对应博客:
微服务架构数据一致性分析:分布式事物+CAP&BASE+可靠事件模式+补偿模式+Sagas模式+TCC模式+最大努力通知模式+人工干预模式
目录一、分布式事物:本地事务和分布式事务(2PC+3PC)+传统分布式事务的问题(一)本地事务和分布式事务(2PC+3PC)(1)两阶段提交协议2PC(2)三阶段提交协议3PC(二)对于微服务,传统分布式事务存在的问题二、CAP理论和BASE思想1.CAP理论一致性Consistency:可用性Availability:分区容错性PartitionToler...
https://blog.csdn.net/xiaofeng10330111/article/details/86772650

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

对应博客:
微服务架构服务可靠性分析:服务访问失败的原因和应对策略+服务容错+服务隔离+服务限流+服务降级
目录一、服务访问失败的原因和应对策略(一)服务访问失败的4大原因和分类1硬件失败2.分布式环境的固有原因3.服务自身失败4.服务依赖失败(二)服务访问的雪崩效应(三)服务访问失败的应对策略二、服务容错1.Failover2.Failback3.Failsafe4.Failfast5.Forking6.Broadcast三、服务隔离...
https://blog.csdn.net/xiaofeng10330111/article/details/86772740

23.Spring Cloud Config配置架构是什么样的?可视化怎么做的?设计的业务有哪些?
具体见博客:
微服务架构Spring Cloud Config原理与注意事项分享讲解
目录注:主要只做理论性的总结与分析,相关实战代码会在后面的博客中和github中逐步增加。一、配置中心的由来及选择(一)配置中心由来(二)配置中心要求具备的功能(三)配置中心基本流转图和支撑体系分析 ​(四)多种配置中心的选择与对比方案二、Spring Cloud Config概述及基本实现方法介绍三、Spring Clo...
https://blog.csdn.net/xiaofeng10330111/article/details/87272559

参考书籍、文献和资料
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.https://blog.csdn.net/xiaofeng10330111/article/details/87272495

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.百度安全验证
————————————————
版权声明:本文为CSDN博主「张彦峰ZYF」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiaofeng10330111/article/details/105361028

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值