Spring
1.对spring框架的理解?
Spring翻译过来就是春天,意为Java开发程序员的春天。
Spring是一款开源的轻量级的Java开发框架,它是很多模块的集合,使用这些模块可以很方便的协助我们进行开发,最主要的支持IOC和AOP(Aspect-Oriented Programming面向切面编程),主要包含Core Container、AOP、Data Access/Integration、Spring Web、Messaging、Spring Test。(详情见JavaGuide)
2.IOC和AOP的理解?
IOC(nverse of Control)控制反转。这里控制是指对对象实例化、管理的权力,反转就是指权力的反转,控制反转就是将对象的实例化、管理的权力交由IOC容器管理。我们一般的方式是new、getInstance等直接或者间接调用构造方法创建一个对象。现在直接从spring容器中取,维护对象之间的依赖关系,降低对象之间的耦合度。 实现方式为DI:依赖注入,有三种注入方式:构造器、setter、注解、接口注入。
DI(依赖注入)就是Spring将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入的过程。
AOP(面向切面编程)能够将那些与业务无关,却为业务模块的公共代码(逻辑或者责任)(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。 Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象; 而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
(也可以使用 AspectJ !Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。)
加分回答:
(OOP --> Object Oriented Programming ---> AOP是面向对象编程的延续,能实现在程序运行的过程中,动态地切入代码段。在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。)
AOP不能增强的类:
-
Spring AOP只能对IoC容器中的Bean进行增强,对于不受容器管理的对象不能增强。
-
由于CGLib采用动态创建子类的方式生成代理对象,所以不能对final修饰的类进行代理。
3.动态代理的种类有几种?在哪些场景下用? (上方)
4.IOC容器的生命周期?/Bean的声明周期?
简单说法:
创建,初始化,调用,销毁。
- bean的创建方式有四种,构造器,静态工厂,实例工厂,setter注入的方式。
- spring在调用bean的时候因为作用域的不同,不同的bean初始化和创建的时间也不相同。
- 在作用域为singleton的时候,bean是随着容器一起被创建好并且实例化的,在作用域为pritotype的时候,bean是随着它被调用的时候才创建和实例化完成。
- 然后程序就可以使用bean了,当程序完成销毁的时候,bean也被销毁。
细致:
- 通过反射进行Bean对象创建 2. 给bean对象的属性注入属性值 3. 判断当前bean有没有实现相应的Aware接口(如:BeanNameAware、BeanFactoryAware等),如果 有,则执行相应的方法 4. 执行Bean后置处理器中的postProcessBeforeInitialization 5. 调用初始化方法,进行初始化,初始化方法可以通过init-method或者@PostConstruct注解或者实现 InitializingBean接口来指定 6. 执行Bean的后置处理器中postProcessAfterInitialization 7. 判断当前对象是单例还是多例bean,如果是单例则放入单例池,如果是多例则进行返回(getBean()方法 的调用) 8. 使用bean 9. IOC容器关闭时,销毁单例Bean对象
Bean的循环依赖问题如何解决的?
Spring可以解决通过setter注入进行依赖的循环依赖问题,通过Spring的三级缓存来实现,利用Java引用对象的特性,将实例对象进行提前暴露。
一级缓存存放的是完整对象,也叫成品对象。
二级缓存存放的是半成品对象,就是那些属性还没赋值的对象。
三级缓存存放的是 ObjectFactory<?> 类型的 lambda 表达式,就是这用于处理 AOP 循环依赖的。
那如果没有三级缓存,只有二级或者一级,能解决循环依赖吗?
循环依赖过程: 首先实例化A,实例化前先将半成品暴露在三级缓存中。 填充属性B,发现B还没有实例化,先去实例化B。 实例化B的过程中,需要填充属性A,从三级缓存中通过ObjectFactory#getObject()直接获取A(在没有AOP的场景下,多次获取的是同一个bean)(这里获取到的是每次调用ObjectFactory#getObject()生成的一个新的代理对象),进行依赖注入,并完成实例化流程。)获取到b,实例化A的流程继续,注入到b到a中,进而完成a的实例化。
5.常用的注解有哪些?
Spring:
@Component
这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller
这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service
此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository
这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
@Resource
JDK层面提供的,Spring负责实现。先根据类型查找,如果存在多个 Bean 再根据名称进行查找。
@Autowired
是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找。
@Value 注解
用法:
Q1://直接把当前字符串赋值给当前字段
@value(“xxx”)
Q2://占位符的替换,根据操作系统环境变量、jvm环境变量、yml文件等作为替换,赋值给当前字段
@value("$xxx")
Q3://先解析Spring表达式,将结果赋值给当前字段。注意:解析表达式得到的有可能是字符串,也有可能是一个bean对象。
@value("#{xxx}")
@Qualifier: 当创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,使用@Qualifier 注解和 @Autowired 可以通过指定某一个 bean 的注入来消除歧义。
@RequestMapping 注解
@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注释可应用于两个级别:
- 类级别:映射请求的 URL
- 方法级别:映射 URL 以及 HTTP 请求方法
不常用:
@Bean: 注释在产生一个bean的方法,然后这个Bean对象交给Spring管理。默认是根据类型进行注入的。 @Configuration:用在class上来定义bean。 @ComponentScan: @Configuration注解一起使用,指定Spring扫描注解的package。如果没有指定包,那么默认会扫描此配置类所在的package。 @Conditional:根据满足某一个特定条件创建一个特定的Bean。 @Lazy:用于延迟类上的bean的初始化。 @Import : 第一种用法:@Import({ 要导入的容器中的组件 } ):容器会自动注册这个组件,id默认是全类名 第二种用法:ImportSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多【重点 】 第三种用法:ImportBeanDefinitionRegistrar:手动注册bean到容器 参考链接:(juejin.cn/post/684490…)
6.Spring的事务注解的原理?
两种事务管理,一个是编程式事务,另一个是声明式事务,编程式事务可以将事务管理的范围控制的更为精确,声明式事务这种方式十分的方便,我们只需在方法上加上Transaction注解,以声明特征即可。
加分回答:
- 事务的打开、回滚和提交是由事务管理器来完成的,我们使用不同的数据库访问框架,就要使用与之对应的事务管理器。
- 在Spring Boot中,当你添加了数据库访问框架的起步依赖时,它就会进行自动配置,即自动实例化正确的事务管理器。
- 对于声明式事务,是使用@Transactional进行标注的。
@Transactional
- 这个注解可以标注在类或者方法上。当它标注在类上时,代表这个类所有公共(public)非静态的方法都将启用事务功能。
- 当它标注在方法上时,代表这个方法将启用事务功能。
- 另外,在@Transactional注解上,我们可以使用isolation属性声明事务的隔离级别,使用propagation属性声明事务的传播机制。
- 默认配置下Spring只会回滚运行时、未检查异常(继承自RuntimeException的异常)或者error。 如果配置rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。
事务的传播机制?
支持当前事务:(要求从 易 --> 严格):普通型
- REQUIRED(需要有) 当前方法中没有事务,新建一个事务,如果已经存在一个事务,则加入到这个事务中来。
- SUPPORTS(可以有) 支持当前事务,如果当前没有事务,就以非事务方式执行。
- MANDATORY(必须有)(强制性的) 使用当前的事务,如果当前没有事务,就抛出异常。
不支持当前事务:(要求 ): 强势型
- REQUIRES_NEW 新建事务执行,如果当前存在事务,把当前事务挂起。
- NOT_SUPPORTED 以非事务的方式执行操作,如果当前存在事务,就把当前事务挂起。
- NEVER 以非事务的方式执行,如果当前存在事务,则抛出异常。 嵌套事务: 懂事型 Nested 如果当前存在事务,则嵌套子事务内执行。如果当前没有事务,则执行与Propagation_Required类似的操作。
事务的隔离级别?
- 可重复读(mysql的默认级别)同一个事务内多次读取的同一份数据的内容是一样的
- 读已提交(oracle的默认级别)AB两个事务操作数据的时候,A事务只能读取到B提交的数据。
- 读未提交 AB两个事务的操作数据库的时候,A事务可以读取到B事务未提交的操作。
- 序列化 读的时候加共享锁,可以并发读,但是不能写;写的时候加排它锁,不能并发写/读执行。效率低,场景不多。但是能解决所有问题。
事务的失效场景?
- @Transactional注解应用在public修饰的方法上。
- @Transactional注解属性propagation设置错误
- @Transactional注解属性rollbackFor设置错误
- Spring项目中未配置事务管理器(SpringBoot项目导入mybatis的starter依赖后会自动注入DataSourceTransactionMangeer事务管理器,可以直接使用@Transactional注解)
- 开启多线程(多线程内的方法不被spring事务控制)
- 同一个类中的方法调用,导致@Transactional注解失效。(A方法(未声明事务)内部调用B方法(声明了事务),这样会导致B方法中的事务失效。)
- 异常被try,catch抓住,导致@Transactional注解失效
- 数据库引擎不支持事务。(innodb支持,myisam不支持事务)
Bean 的作用域有哪些?
Spring 中 Bean 的作用域通常有下面几种:
- singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续
getBean()两次,得到的是不同的 Bean 实例。 - request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
- application/global-session (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),,该 bean 仅在当前应用启动时间内有效。
- websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
SpringMVC
1.工作流程? (来源JavaGuide)
- 客户端(浏览器)发送请求,
DispatcherServlet拦截请求。 DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据 uri 去匹配查找能处理的Handler(也就是我们平常说的Controller控制器) ,并会将请求涉及到的拦截器和Handler一起封装。DispatcherServlet调用HandlerAdapter适配执行Handler。Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。Model是返回的数据对象,View是个逻辑上的View。ViewResolver会根据逻辑View查找实际的View。DispaterServlet把返回的Model传给View(视图渲染)。- 把
View返回给请求者(浏览器)
2.核心组件以及作用是什么? (来源JavaGuide)
DispatcherServlet:前端控制器,负责接收请求、分发,并给予客户端响应。HandlerMapping:映射处理器,根据 uri 去匹配查找能处理的Handler,并会将请求涉及到的拦截器和Handler一起封装。HandlerAdapter:适配处理器,根据HandlerMapping找到的Handler,适配执行对应的Handler;Handler:(请求)处理器,处理实际请求的处理器。ViewResolver:视图解析器,根据Handler返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给DispatcherServlet响应客户端
3.常用注解?
SpringMVC
-
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
-
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。[content-type: application/json 才能用requestBody来接]
-
@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
Mybatis
1. 工作流程?
-
1.读取配置文件,配置文件包含数据库连接信息和Mapper映射文件或者Mapper包路径。
-
2.有了这些信息就能创建SqlSessionFactory,SqlSessionFactory的生命周期是程序级,程序运行的时候建立起来,程序结束的时候消亡
-
3.SqlSessionFactory建立SqlSession,目的执行sql语句,SqlSession是过程级,一个方法中建立,方法结束应该关闭
-
4.当用户使用mapper.xml文件中配置的的方法时,mybatis首先会解析sql动态标签为对应数据库sql语句的形式,并将其封装进MapperStatement对象,然后通过executor将sql注入数据库执行,并返回结果。
-
5.将返回的结果通过映射,包装成java对象。
细节点回答 :
- 读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
- 加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
- 构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
- 创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
- Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
- MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
- 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
- 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
2. 缓存有几层?作用域有多大?分别有什么问题?
两层。分别是一级缓存和二级缓存。
一级缓存默认开启,作用域session,二级缓存作用域namespace
3. #{} 和 ${} 的区别是什么?
在MyBatis中$和#的两种占位符。
- 使用
$设置参数时,MyBatis会创建普通的SQL语句,执行SQL时,直接将参数拼接在SQL中,可能会产生SQL注入攻击,但在某些场景中,比如需要动态指定SQL语句中的列名时,就只能使用$占位符了. - 使用
#设置参数时,MyBatis会创建预编译的SQL语句,预编译的SQL语句执行效率高,并且可以防止SQL注入攻击,在实际开发中,大部分情况下使用#占位符
4. 介绍一下MyBatis的缓存机制
一级缓存也称为本地缓存,它默认启用且不能关闭。
一级缓存存在于于SqlSession的生命周期中,即它是SqlSession级别的缓存。
一级缓存生效:
-
确保同一个sqlSession
-
确保查询语句没有改变
-
多次查询之间没有DML语句和主动清空缓存语句 数据操纵语言DML(Data Manipulation Language) 一级缓存失效的情况:
-
不是同一个SqlSession
-
同一个SqlSession但是查询条件发生了变化
-
同一个SqlSession两次查询期间执行了任何一次增删改操作
-
同一个SqlSession两次查询期间手动清空了缓存
-
同一个SqlSession两次查询期间提交了事务
二级缓存存在于SqlSessionFactory 的生命周期中,即它是SqlSessionFactory级别的缓存。
注意: 二级缓存通过用一个SqlSessionFactory创建的SqlSession 查询的结果会被缓存; 此后再查询相同的查询语句,就会从缓存中获取结果。
二级缓存生效:
- 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
- 在映射文件中设置标签
- 二级缓存必须在SqlSession关闭(Close)或者提交(Commit)之后有效
- 查询的数据所转换的实体类型必须实现序列化接口
二级缓存失效: 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。
二级缓存对比一级缓存:
- MyBatis 的二级缓存相对于一级缓存来说,
- 实现了 SqlSession 之间缓存数据的共享,同时粒度更加的细,
- 能够到 namespace 级别,
- 通过 Cache 接口实现类不同的组合,对 Cache 的可控性也更强。
为什么生产环境中不用mybatis自带的一级二级缓存?
-
MyBatis 的一级缓存作用域是 SqlSession ,有多个 SqlSession 或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为 Statement。
-
MyBatis 在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。
如何解决?
在分布式环境下,由于默认的 MyBatis Cache 实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将 MyBatis 的 Cache 接口实现,有一定的开发成本,直接使用 Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。
SpringBoot
1.SpringBoot的工作原理?
@SpringBootApplication注解是sprinBoot启动时的入口,启动之后,注解会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建spring容器中的bean,并且进行自动配置把bean注入SpringIOC中进行管理。
起步依赖?
starter配置,约定大于配置(这里说约定就是默认值)。spring boot将日常企业应用研发中的各种场景都抽取出来,做成一个个的starter(启动器),starter中整合了该场景下各种可能用带的依赖,用户只需要在Maven中引入starter依赖,spring boot就能自动扫描到要加载的信息并启动响应的默认配置。
起步依赖说白了就是Spring Boot通过对常用的依赖进行再一次封装,例如我们平时需要搭建一个Web应用的时候,一般都会导入以下几个依赖,将spring-web和spring mvc分别导入,而使用Spring Boot的话只需要导入一个。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.自动配置的底层原理是什么?
自动配置: 帮我们省略了各种繁杂的配置文件,无序复杂的pom坐标,只需要一个main方法一个注解 就能run。 原理就是通过SpringBootApplication注解完成自动配置。 SpringBootApplication注解中有三个主要的注解:
- SpringBootConfiguration(标志当前类为配置类)
- EnableAutoConfiguration(开启自动导入配置)
- ComponentScan(包扫描)
其中EnableAutoConfiguration注解中导入了Selectmports类,这个类的selectImports方法会读取到Jar包下的meta-inf下spring.factories配置文件,再读取文件中的EnableAutoConfiguration对应的值,就是我们自动装配的默认配置的全类名。
这个全类名的集合经过验证、去重、排出自动装配以及执行监听器等操作后,最终返回String数组,此数组就是我们最终要自动装配的配置类集合,将这个集合返回给SpringBoot,它再通过反射,加载相应的配置,将配置中的组件加载到Spring的IOC容器中进行管理。
SpringCloud
1.SpringCloud常用的组件有哪些?
- Eureka(
AP): 作为注册中心,主要实现服务注册与服务发现机制(and 状态监管、动态路由)。 - Ribbon(Netflix发布):
作为负载均衡的组件,负责服务端和客户端的负载均衡。
(策略:轮询(默认), 随机, 一致性哈希 , 最小连接数, 重试, 加权。)
- Hystrix(豪猪): 作为服务熔断降级(保护微服务)的组件,防止雪崩效应发生。
(雪崩效应: 分布式系统环境下产生的一种故障传播的连锁效应。)
- Feign: 整合了ribbon、Hystrix,具有
负载均衡、熔断的功能。 - (常用)openFeign: 声明式服务调用和负载均衡组件, 因此它的核心是使用注解 + 接口的方式实现服务调用(作为远程调用的客户端,实现服务之间的远程调用)。详解链接
- Zuul: 是Spring Cloud提供的API网关组件。
- (常用)Gateway: 本质上是一个微服务,需要注册到nacos/Eureka上,为SpringBoot应用提供了API网关支持,具有强大的智能路由与过滤器功能。
- Sleuth: 实现服务的链路追踪
- Zipkin: 一个对数据的收集和查找的分布式的跟踪系统。它有助于收集解决服务体系结构中的延迟问题所需的计时数据。
SpringCloudAlibaba
- (常用)nacos(
AP和CP): 作为注册中心和配置中心,实现服务注册发现和服务健康监测及配置信息统一管理。见官方文档?
核心功能:路由、断言、过滤器。详解链接
2.注册中心用过哪些?有什么区别?
Nacos(CP+AP)、Eureka(AP)、Zookeeper(CP)
注册中心本质上是为了解耦 服务提供者和服务消费者。
3.eureka注册中心的工作原理?底层工作原理?
-
- Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息。
-
- Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
-
- Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常
-
- 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
-
- 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
-
- 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
-
- Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地
-
- 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
-
- Eureka Client 获取到目标服务器信息,发起服务调用
-
- Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除。
4.注册中心挂掉是否影响服务与服务之间的调用?
正常的能调用,也有可能不能调用,要看具体场景。
能调用的场景:
-
注册中心挂了,一般会把注册信息放在缓存中。这样可以正常调用。
-
如果缓存也挂了,若是采用的集群模式,也没问题,注册中心会被重新选举其他节点作为master,来提供服务。这样可以正常调用。
-
如果,注册中心,集群,数据库缓存都挂了,调用者本地会保存一份服务调用的列表(包括服务的ip和端口)。consumer和provider就会不经过注册中心直联,这需要我们做一些配置。
影响调用的场景:
服务提供者的ip地址发生了改变,正常情况下,注册中心能够知道到这个服务者的ip地址变化,会做出更新。但是注册中心挂了,服务包就不能被传到注册中心,服务提供者也就不能被更新,就会影响服务间的调用。
(阿坤版↓)
服务掉线分为:主动下线和心跳检测 主动下线:重启之前主动向注册中心声明我要重启了.有请求不要给我,让别的机器服务,重启完毕后再找我
心跳检测:是处理服务非正常下线.如果注册中心不知道该服务挂掉了,一旦调用则会出问题,所以就有了注册中心对其他提供者进行一个心跳检测,每隔30s一次,如果三次都没返回值,则人为该服务下线,赶紧更新服务列表,通知消费者调用其他服务
分两种情况:
1.如果数据库挂了.zk还是能用的.因为zk会缓存注册机列表在缓存里
2.Zk本身是集群,master挂了会选举.如果整个集群都挂了,也没问题.因为调用者会在本地缓存注册中心获取的服务列表,直接就会该列表联系(eureka也行)
5.RPC协议和Http协议的区别?
传输协议
RPC(Remote Procedure Call): 即远程过程调用。可以基于TCP协议,也可以基于HTTP协议
HTTP: 超文本传输协议。它基于 TCP/IP 来传输文本、图片、视频、音频等。
传输效率
RPC:使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率
HTTP:如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装以下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理
性能消耗
RPC:可以基于thrift实现高效的二进制传输
HTTP:大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能
负载均衡
RPC:基本都自带了负载均衡策略
HTTP:需要配置Nginx,HAProxy来实现
服务治理
RPC:能做到自动通知,不影响上游
HTTP:需要事先通知,修改Nginx/HAProxy配置
总结
RPC主要用于公司内部的服务调用,性能消耗低,传输效率高,服务治理方便。HTTP主要用于对外的异构环境,浏览器接口调用,APP接口调用,第三方接口调用等。
RPC 对比的是本地过程调用,是用来作为分布式系统之间的通信,它可以用 HTTP 来传输,也可以基于 TCP 自定义协议传输。
HTTP 协议比较冗余,所以 RPC 大多都是基于 TCP 自定义协议,定制化的才是最适合自己的。
6.http协议的三次握手和四次挥手?为什么需要3次为什么需要4次?
为什么要3次?
三次握手 确认对方是否听得到吗?
- A:你听得到吗?
- B:我听得到!
- A:好,我有话对你说~
为什么要四次?
四次挥手 道别
- A:我走了啊
- B:好的
- A:拜拜
- B:拜拜
7.ribbon的默认负载均衡策略是什么?还知道哪些负载均衡的策略?
-
轮询(默认): 按照一定次序轮流调用。
-
随机: 从服务提供者的列表中随机选择一个服务实例。
-
一致性哈希: 将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。
-
最小连接数: 它是遍历服务提供者列表,选取连接数最小的⼀个服务实例。如果有相同的最小连接数,那么会调用轮询策略进行选取。
-
重试: 按照轮询策略来获取服务,如果获取的服务实例为 null 或已经失效,则在指定的时间之内不断地进行重试来获取服务,如果超过指定时间依然没获取到服务实例则返回 null。
-
加权: 它的实现原理是,刚开始使用轮询策略并开启一个计时器,每一段时间收集一次所有服务提供者的平均响应时间,然后再给每个服务提供者附上一个权重,权重越高被选中的概率也越大。
8.熔断器的工作原理?
原理: 就如同电闸(空气开关)功率过高会跳闸一样。
熔断器的三个状态?
Closed:关闭状态,所以请求正常访问。
Open: 打开状态,所以的请求都会被降级。
Half Open: 半开状态。判断下一次请求情况:
- 如果成功,切换为closed状态
- 如果失败,切换回open状态
如何变化的?
Open 打开状态:默认失败阈值50%,请求次数最低 >= 20次
Half Open 半开状态: 半开状态不是永久的,不久后会进入休眠时间(默认5s),休眠时间过去后,会进入半开状态。
9.网关的全局过滤器的使用场景?
一般用在需要统一处理的 业务需求。比如:
- token、令牌验证(模拟登陆校验)
- 白名单跳过
- 请求限流
10.还用过哪些组件?链路追踪 哨兵(熔断器的优化版本)
zipkin:链路追踪 记录快速定位问题 任务一个环节出了问题可以靠链路追踪
哨兵:通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例
11.nacos作为配置中心是否使用过?
使用过
Dynamic Naming and Configuration Service,Na为naming/nameServer即注册中心,co为configuration即注册中心,service是指该注册/配置中心都是以服务为核心。
Nacos注册中心原理
服务提供者、服务消费者、服务发现组件这三者之间的关系大致如下
1、微服务在启动时,将自己的网络地址等信息注册到服务发现组件(nacos server)中,服务发现组件会存储这些信息。
2、各个微服务与服务发现组件使用一定机制通信(例如在一定的时间内发送心跳包)。服务发现组件若发现与某微服务实例通信正常则保持注册状态(up在线状态)、若长时间无法与某微服务实例通信,就会自动注销(即:删除)该实例。
3、服务消费者可从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口。
4、当微服务网络地址发生变更(例如实例增减或者IP端口发生变化等)时,会重新注册到服务发现组件。
12. Spring Cloud 和dubbo区别?
(1)服务调用方式 dubbo是RPC springcloud Rest Api
(2)注册中心,dubbo 是zookeeper springcloud是eureka,也可以是zookeeper
(3)服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。