2021-Java后端工程师面试指南-(SpringBoot+SpringCloud)(上)

简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

Tips


面试指南系列,很多情况下不会去深挖细节,是小六六以被面试者的角色去回顾知识的一种方式,所以我默认大部分的东西,作为面试官的你,肯定是懂的。

www.processon.com/view/link/6…

上面的是脑图地址


叨絮


分布式系统开发,微服务架构的一种主流实现方式,当然在面试中是必不可少的拉。

然后下面是前面的文章汇总


什么是SpringBoot呢


简而言之,从本质上来说,Spring Boot 就是 Spring,它做了那些没有它你自己也会去做的 Spring Bean 配置。基于约定大于配置的一个理论


说说SpringBoot的特点吧

  • 开发基于 Spring 的应用程序很容易。
  • Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
  • Spring Boot 不需要编写大量样板代码、XML 配置和注释。
  • Spring 引导应用程序可以很容易地与 Spring 生态系统集成,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
  • Spring Boot 遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
  • Spring Boot 应用程序提供嵌入式 HTTP 服务器,如 Tomcat 和 Jetty,可以轻松地开发和测试 web 应用程序。(这点很赞!普通运行 Java 程序的方式就能运行基于 Spring Boot web 项目,省事很多)


说说@SpringBootApplication 这个注解吧

可以看出大概可以把 @SpringBootApplication 看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @ComponentScan: 扫描被@Component (@Service,@Controller)注解的bean,注解默认会扫描该类所在的包下所有的类。
  • @Configuration:允许在上下文中注册额外的bean或导入其他配置类。

-所以说 @SpringBootApplication 就是几个重要的注解的组合,为什么要有它?当然是为了省事,避免了我们每次开发 Spring Boot 项目都要写一些必备的注解。这一点在我们平时开发中也 经常用到,比如我们通常会提一个测试基类,这个基类包含了我们写测试所需要的一些基本的注解和一些依赖。


知道SpringBoot的钩子函数吗,如何对你项目的启动和死亡做监控。

  • 启动的时候,比如CommandLineRunner 重写它的run方法,就能在启动的时候做一个钩子函数,比如链接钉钉等
  • 意外宕机也是可以的,   @PreDestroy 这个注解也能实现,在宕机之前回调这个方法,实现钉钉机器人等。


了解spring boot 中的spring factories 机制吗?

Spring Factories.这种机制实际上是仿照java中的SPI扩展机制实现的。

spring -core 包里定义了SpringFactoriesLoader 类,这个类实现了检索META-INF/spring.factories文件,并获取指定接口的配置的功能。 在这个类中定义了两个对外的方法: -loadFactories 根据接口类获取其实现类的实例,这个方法返回的是对象列表

  • loadFactoryNames 根据接口获取其接口类的名称,这个方法返回的是类名的列表。


说说springBoot的自动配置原理吧

首先我们知道SpringBoot项目的启动注解@SpringBootApplication  中有一个@EnableAutoConfiguration,这个就是开启springBoot的自动注册机制 可以看到,在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader.loadFactoryNames方法进行扫描具有META-INF/spring.factories文件的jar包


最后再加上我们的EnableAutoConfiguration 读取我们在配置文件中的文件就可以实现自动配置了,就比如我们的springboot Admin,我们的client只要配置下配置文件就能成功了,原因就是这个


上面这些都是Spring Boot中的自动配置相关类;在启动过程中会解析对应类配置信息。每个Configuation类都定义了相关bean的实例化配置。都说明了哪些bean可以被自动配置,什么条件下可以自动配置,并把这些bean实例化出来。如果我们自定义了一个starter的话,也要在该starter的jar包中提供 spring.factories文件,并且为其配置org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类。所有框架的自动配置流程基本都是一样的,判断是否引入框架,获取配置参数,根据配置参数初始化框架相应组件


说说SpringBoot的启动流程吧

其实这块很大一部分和spring的启动流程有重叠的,但是,我们还是从头到尾来过一遍,当复习了。


SpringBoot的启动主要是通过实例化SpringApplication来启动的,启动过程主要做了以下几件事情:配置属性、获取监听器,发布应用开始启动事件初、始化输入参数、配置环境,输出banner、创建上下文、预处理上下文、刷新上下文(加载tomcat容器)、再刷新上下文、发布应用已经启动事件、发布应用启动完成事件。

实例化SpringApplication时做了什么

  • 推断WebApplicationType,主要思想就是在当前的classpath下搜索特定的类
  • 搜索META-INF\spring.factories文件配置的ApplicationContextInitializer的实现类
  • 搜索META-INF\spring.factories文件配置的ApplicationListenerr的实现类
  • 推断MainApplication的Class

SpringApplication的run方法做了什么?

  • 创建一个StopWatch并执行start方法,这个类主要记录任务的执行时间
  • 配置Headless属性,Headless模式是在缺少显示屏、键盘或者鼠标时候的系统配置
  • 在文件META-INF\spring.factories中获取SpringApplicationRunListener接口的实现类EventPublishingRunListener,主要发布SpringApplicationEvent
  • 把输入参数转成DefaultApplicationArguments类
  • 创建Environment并设置比如环境信息,系统熟悉,输入参数和profile信息
  • 打印Banner信息
  • 创建Application的上下文,根据WebApplicationTyp来创建Context类,如果非web项目则创建AnnotationConfigApplicationContext,在构造方法中初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
  • 在文件META-INF\spring.factories中获取SpringBootExceptionReporter接口的实现类FailureAnalyzers
  • 准备application的上下文
  • 初始化ApplicationContextInitializer
  • 执行Initializer的contextPrepared方法,发布ApplicationContextInitializedEvent事件
  • 如果延迟加载,在上下文添加处理器LazyInitializationBeanFactoryPostProcessor
  • 执行加载方法,BeanDefinitionLoader.load方法,主要初始化了AnnotatedGenericBeanDefinition
  • 执行Initializer的contextLoaded方法,发布ApplicationContextInitializedEvent事件
  • 刷新上下文(后文会单独分析refresh方法),在这里真正加载bean到容器中。如果是web容器,会在onRefresh方法中创建一个Server并启动。

refresh方法 和spring的有点不同

srping中的onrefesh方法是空的,这个里面是需要去加载web容器的如tomcat jetty等,具体的方法还是一样的,这边就不说了,可以去看ssm那篇


说说SpringCloud容器和SpringBoot容器的关系呗

首先说一点就是 如果是SpringBoot呢?他是可以单独使用的,而SpringCloud是不能单独使用的,它必须依赖SpringBoot。

在我们SpringCloud的项目中呢,整个项目的容器分为三层

  • BootStrap Spring 容器:由SpringCloud 监听器创建,用来初始化 SpringCloud 上下文
  • SpringBoot Spring 容器:由SpringBoot创建,也是项目中常用的Spring容器。
  • 微服务 Spring相关容器:Feign和Ribbon配置类对应的上下文,由配置容器抽象工厂 NamedContextFactory 创建,用于容器隔离。

主要流程

首先 SpringBoot 项目启动,触发监听器,如果引入了SpringCloud 中的BootstrapApplicationListener,则开始初始化 SpringCloud 相关的上下文:Bootstrap ApplicationContext,将其设置为祖先容器,然后继续创建其子容器:SpringBoot Application。


说说分布式系统开发的痛点,业界是怎么设计的这些解决方案

首先分布式系统开发,目前主流的架构就是微服务架构,如果说你做微服务架构的话,无论你怎么去选型,怎么去设计,首先你总归要碰到以下的几个问题

  • 这么多的服务,客户端如何去访问,你就好比说我们几百个服务,难道前端要在代码中调用几百个地址,而况服务地址多了,我们也不好去管理这些ip和端口,
  • 服务与服务之间,如何去通信,那是不是得处理我们服务内部之间的调用方式,
  • 服务挂了怎么办,你不能因为一个服务挂了,导致整个项目出现问题,导致服务雪崩吧
  • 服务与服务是如何做到服务的发现与注册的,你不能说那个服务挂了,我是如何去通知其他服务的。也就是服务的治理


说说你们公司的SpringCloud的组件吧

  • Spring Cloud 核心组件:Eureka 服务发现和注册中心
  • Spring Cloud 核心组件:Feign 服务与服务直接的调用
  • Spring Cloud 核心组件:Ribbon 负载均衡
  • Spring Cloud 核心组件:Hystrix 熔断 降级
  • Spring Cloud 核心组件:Zuul SpringCloudGateway 服务网关


聊聊Eureka吧


首先什么是Eureka

首先,eureka在springcloud中充当服务注册功能,相当于dubbo+zk里面得zk,但是比zk要简单得多,zk可以做得东西太多了,包括分布式锁,分布式队列都是基于zk里面得四种节点加watch机制通过长连接来实现得,但是eureka不一样,eureka是基于HTTprest来实现的,就是把服务的信息放到一个ConcurrentHashMap中,然后服务启动的时候去读取这个map,来把所有服务关联起来,然后服务器之间调用的时候通过信息,进行http调用。eureka包括两部分,一部分就是服务提供者(对于eureka来说就是客户端),一部分是服务端,客户端需要每个读取每个服务的信息,然后注册到服务端,很明显了,这个服务端就是接受客户端提供的自身的一些信息。 目前eureka是ap的 但是呢 zk是cp的,至于分布式理论下次有空再聊哈。


聊聊eureka中一些重要的概念呗

在Eureka的服务治理中,会涉及到下面一些概念:

  • 服务注册:Eureka Client会通过发送REST请求的方式向Eureka Server注册自己的服务,提供自身的元数据,比如ip地址、端口、运行状况指标的url、主页地址等信息。Eureka Server接收到注册请求后,就会把这些元数据信息存储在一个双层的Map中。
  • 服务续约:在服务注册后,Eureka Client会维护一个心跳来持续通知Eureka Server,说明服务一直处于可用状态,防止被剔除。Eureka Client在默认的情况下会每隔30秒发送一次心跳来进行服务续约。
  • 服务同步:Eureka Server之间会互相进行注册,构建Eureka Server集群,不同Eureka Server之间会进行服务同步,用来保证服务信息的一致性。
  • 获取服务:服务消费者(Eureka Client)在启动的时候,会发送一个REST请求给Eureka Server,获取上面注册的服务清单,并且缓存在Eureka Client本地,默认缓存30秒。同时,为了性能考虑,Eureka Server也会维护一份只读的服务清单缓存,该缓存每隔30秒更新一次。
  • 服务调用:服务消费者在获取到服务清单后,就可以根据清单中的服务列表信息,查找到其他服务的地址,从而进行远程调用。Eureka有Region和Zone的概念,一个Region可以包含多个Zone,在进行服务调用时,优先访问处于同一个Zone中的服务提供者。
  • 服务下线:当Eureka Client需要关闭或重启时,就不希望在这个时间段内再有请求进来,所以,就需要提前先发送REST请求给Eureka Server,告诉Eureka Server自己要下线了,Eureka Server在收到请求后,就会把该服务状态置为下线(DOWN),并把该下线事件传播出去。
  • 服务剔除:有时候,服务实例可能会因为网络故障等原因导致不能提供服务,而此时该实例也没有发送请求给Eureka Server来进行服务下线,所以,还需要有服务剔除的机制。Eureka Server在启动的时候会创建一个定时任务,每隔一段时间(默认60秒),从当前服务清单中把超时没有续约(默认90秒)的服务剔除。
  • 自我保护:既然Eureka Server会定时剔除超时没有续约的服务,那就有可能出现一种场景,网络一段时间内发生了异常,所有的服务都没能够进行续约,Eureka Server就把所有的服务都剔除了,这样显然不太合理。所以,就有了自我保护机制,当短时间内,统计续约失败的比例,如果达到一定阈值,则会触发自我保护的机制,在该机制下,Eureka Server不会剔除任何的微服务,等到正常后,再退出自我保护机制。

从这些概念中,就可以知道大体的流程,Eureka Client向Eureka Server注册,并且维护心跳来进行续约,如果长时间不续约,就会被剔除。Eureka Server之间进行数据同步来形成集群,Eureka Client从Eureka Server获取服务列表,用来进行服务调用,Eureka Client服务重启前调用Eureka Server的接口进行下线操作。


说说Eureka的一些原理和服务流程


服务提供者

1、启动后,向注册中心发起register请求,注册服务

2、在运行过程中,定时向注册中心发送renew心跳,证明“我还活着”。

3、停止服务提供者,向注册中心发起cancel请求,清空当前服务注册信息。


服务消费者

1、启动后,从注册中心拉取服务注册信息

2、在运行过程中,定时更新服务注册信息。

3、服务消费者发起远程调用:


注册中心

1、启动后,从其他节点拉取服务注册信息(节点之间的数据同步)。

2、运行过程中,定时运行evict任务,剔除没有按时renew的服务(包括非正常停止和网络故障的服务)。

3、运行过程中,接收到的register、renew、cancel请求,都会同步至其他注册中心节点。


相关文章
|
3天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
13 0
|
3天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
6 0
|
4天前
|
监控 Java 数据库连接
总结Spring Boot面试知识点
Spring Boot是一个基于Spring框架的开源项目,它简化了Spring应用的初始搭建以及开发过程。通过提供“约定优于配置”的方式,Spring Boot可以帮助开发者快速构建出生产级别的Spring应用。
13 0
|
5天前
|
Java
三个可能的Java面试题
Java垃圾回收机制自动管理内存,回收无引用对象的内存,确保内存有效利用。多态性允许父类引用操作不同子类对象,如Animal引用可调用Dog的方法。异常处理机制通过try-catch块捕获和处理程序异常,例如尝试执行可能导致ArithmeticException的代码,catch块则负责处理异常。
28 9
|
10天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
22 0
|
16天前
|
Java
【JAVA面试题】static的作用是什么?详细介绍
【JAVA面试题】static的作用是什么?详细介绍
|
16天前
|
Java
【JAVA面试题】final关键字的作用有哪些
【JAVA面试题】final关键字的作用有哪些
|
16天前
|
JavaScript 前端开发 Java
【JAVA面试题】什么是引用传递?什么是值传递?
【JAVA面试题】什么是引用传递?什么是值传递?
|
16天前
|
安全 Java
【JAVA面试题】什么是对象锁?什么是类锁?
【JAVA面试题】什么是对象锁?什么是类锁?
|
3天前
|
存储 监控 API
构建高效微服务架构:后端开发的现代实践
【5月更文挑战第9天】 在本文中,我们将深入探讨如何在后端开发中构建一个高效的微服务架构。通过分析不同的设计模式和最佳实践,我们将展示如何提升系统的可扩展性、弹性和维护性。我们还将讨论微服务架构在处理复杂业务逻辑和高并发场景下的优势。最后,我们将分享一些实用的工具和技术,以帮助开发者实现这一目标。