Advertisement

java面试看这一篇就够了

阅读量:

因为近期工作繁忙,项目进度紧凑,一直以来都未能抽出时间来系统地整理面试题,但这次腾出了一些时间来汇总并整理了答谢大家提供的面试题,也感谢众多小伙伴的支持与参与,正是这份支持是我们继续创作的动力来源,期待能在未来的日子里与更多人分享经验,如觉得有帮助,请多转发、收藏并关注我的动态,考虑到篇幅较长,请读者朋友们及时保存以便查阅

Jason

springboot相关面试话术

1、什么是springboot

Spring Boot 实际上是 Spring 项目中的一个子工程,在编程社区中它常被用来比喻搭建程序的基础架构。它的核心功能就是帮助开发者快速构建大型 Spring 项目的同时最大限度地降低所有的 XML 配置工作量,并确保系统能够实现零配置即可上手的状态。

2、为什么要用springboot

Spring Boot 以其卓越的表现著称,在部署效率方面尤为突出:首先无需外部容器支持即可独立运行,并内置多种Servlet容器如Tomcat、Jetty等;其次启动器启动后即可自动生成所需的组件配置;再者系统能够根据当前类路径下的类和 jar 包自动生成 bean 对象;此外 Spring Boot 完全依赖于条件注解实现功能配置;最后系统提供丰富的监控接口用于实时评估服务健康状况

3、springboot有哪些优点

降低开发时间、测试时间和总体开发努力。
通过JavaCong类的使用能够绕开XML文件的配置问题。
无需手动管理Maven项目的依赖关系以及版本兼容性问题。
设置默认值后将加快进入开发状态的速度。
无需额外配置Web服务器资源。
这表示你可以完全省去启动Tomcat、Glassfish或其他任何容器服务器的需求。
因为没有web.xml文件的存在而减少了配置步骤。
只需在代码中添加带@Configuration注解的对象类即可。
然后为每个Bean对象添加@Bean注解即可。
Spring框架会自动生成该对象实例,并按照常规方式进行管理。
您甚至可以将@Autowired 添加到 bean 方法中以简化操作流程。
基于环境的配置 使用这些属性:
-Dspring.proles.active = {enviornment}
在加载主应用程序属性文件后,
Spring框架会自动生成该对象实例,
并在(application{environment} .properties)中加载后续的应用程序属性文件.
application.yml

spring.active.profile=dev

application-dev.yml

application-test.yml

application-prod.yml

4、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

在启动类中使用的注解主要有以下三个关键点:首先整合了@Configuration注解来负责配置文件的管理;其次启用了自动生成配置功能,并允许对特定自动配置设置进行关闭;最后实现了组件扫描功能,在当前类所在的包及其子目录中进行扫描操作。

5、springboot项目有哪几种运行方式

使用打包命令或通过容器部署并使用Maven/Gradle插件启动主方法

我们可以将其视为启动器工具...它整合了多个可无缝集成到应用中的第三方库...通过这一机制您可以轻松地将Spring与其他技术集成到同一个应用中...无需到处寻找示例代码或下载额外的依赖项库...如果您的项目需要通过JPA访问数据库...只需在项目中添加一个特定的启动器即可实现此功能...这些启动器涵盖了项目中常用的各种第三方库以及必要的功能模块

7、springboot自动配置原理

关于@SpringbootApplication核心注解的相关内容,则是从springboot项目的框架展开论述的。其中包含的关键字段主要有三个:一个是@EnableAutoConfiguration注解,则是该注解的主要功能则是实现自动化配置机制;其主要作用在于当开发者完成基本应用架构搭建后,默认会触发一系列系统性配置操作;前提是项目中已导入了相关的jar包,并且这些jar包中已经包含了如Tomcat和SpringMVC等常用组件;这样一来,在开发一个基于Web的应用程序时,默认情况下就能获得较为完善的配置设置;而无需开发者手动进行繁琐的手动配置操作;此外,默认情况下还集成了一些常用的第三方组件如Redis和Elasticsearch等;这些组件的配置则全部由META-INF/spring.factories文件中的元数据信息自动管理;而文件中的每一个bean类路径都会被反射加载到IOC容器中;具体而言,在JavaConfig的作用下会依次读取并解析相应的配置文件进而构造相应的对象完成初始化工作

2

springcloud相关面试话术

1、什么是Springcloud

可被视为一系列框架的集合...它通过模仿 Spring Boot 的便捷特性来简化分布式系统开发...例如服务发现...功能...其主要目标是为了降低构建和开发 Spring 应用的复杂性...该框架遵循「约定优先于配置」的设计理念...从而使得开发者无需手动配置冗长的 XML 参数设置...而非重复造 unnecessarily复杂的轮子...而是整合了市场上较为成熟且功能完善的组件...将这些组件封装起来后不仅降低了各个模块的成本而且显著提升了整体系统的运行效率$said another way through the integration of a series of key components including Eureka Ribbon Feign etc. it provides a comprehensive solution for building distributed systems.

为什么选择这种方法呢?因为原先项目的架构采用的是集中化的模式。这种设计会导致任何一个小小的bug都可能导致整个系统崩溃。经过调整后,我们需要对系统进行全面升级,因此我们选择了基于传统架构的基础上,引入了微服务模式进行优化。采用微服务架构后,在任务分配效率以及系统的扩展性方面较之前有了显著提升,特别是在处理复杂需求时表现更为灵活可靠。

让我来向大家介绍一下Spring Cloud中的几个核心组件吧。我们的项目中就使用到了其中几个主要功能模块。其中最为关键的功能模块是注册中心Eureka。所有微服务都必须通过Eureka来进行管理流程。系统内部会实现心跳机制,并且还可以提供每个微服务的基本运行状态信息给调用方查询。

随后使用feign实现远程通信。作为一个基于HTTP的远程通信组件,在微服务架构中发挥着重要作用。该组件集成了一个名为Ribbon的负载均衡系统。能够准确识别当前注册中心中的服务实例数量,并根据内部算法平衡域访问这些实例。它的算法采用轮询与随机结合的方式分配请求以确保公平与高效

接着就是。
熔断器hystrix。
当我们在这个项目中使用这个组件时,
特别是在远程调用的情况下,
如果任何一个微服务响应超时或出现异常,
熔断器就会介入处理,
将当前请求终止。
随后会触发我们的回调方法,
并返回回调方法中的数据结果。
这将确保我们的微服务系统能够维持良好的请求链路运行,
并且这样的处理方式将避免用户界面长时间处于等待状态。
从而带来非常良好的用户体验感受。

随后是我们的网关.Zuul.它在我们的项目中扮演着入口角色. incoming requests enter the system through this gateway and first undergo path-based parsing before being routed to the appropriate microservices. Additionally, this gateway serves as an authentication mechanism. Upon logging in, a token is issued to users. When accessing resources, the token is transmitted as a header field within the request. The gateway intercepts these headers and verifies the token's authenticity before allowing access to the backend microservices. This demonstrates how our system integrates authentication seamlessly into its service architecture.

2、服务注册和服务发现是什么意思,springcloud是如何实现的

在微服务架构设计过程中, 我们经常需要处理不同组件之间的交互作用, 这通常会在各个组件的配置文件中记录所有需要请求的相关信息, 包括地址端口等关键参数。然而, 随着项目的规模不断扩大以及新旧功能不断迭代升级, 配置文件中的条目变得越来越多, 相关数据维护的工作量也随之提高。当某些核心业务逻辑发生变更时, 更新相关的配置信息虽然看似直接, 但手动修改配置文档仍然存在一定的风险。为此,Eureka系统提供了一套高效的解决方案:通过Eureka系统进行注册后, 在注册中心可以看到所有运行中的微服务及其相关信息;通过Eureka系统提供的自动发现功能(feign)实现远程调用;由于所有相关业务逻辑都在Eureka服务器上运行并通过该服务器进行交互查找, 因此完全无需担心服务器位置的变化带来的问题

3、负载均衡的意义是什么

我认为负载均衡的核心目的主要在于,在面对单一应用可能出现的高并发或异常情况时能够有效规避可能导致服务中断的风险;通过同时运行多个负载均衡实例可以在一定程度上缓解并提升系统的应对能力;从而确保在关键业务场景下系统的稳定运行。

在我们的项目中,其中服务接入层由nginx进行管理,经过 nginx 处理后,根据相应的域名进行路由,转发至对应的服务端口.由于 nginx 不承担任何业务处理逻辑,仅负责请求转发,因此使得整体处理效率显著提升.

Nginx采用了多种负载均衡策略,在其配置文件nginx.conf中将upstream模块配置为所需的方式即可。

首先是轮训,默认的就是这种方式

第二种权重策略就是基于服务器性能指标来设定较高的权重系数 从而使得Nginx能够处理更多客户端请求

第三种采用的是基于IP哈希的方式,在处理来自不同IP地址的请求时,默认会对该次哈希运算进行计算过程,并将请求结果按照该运算的结果值对应到相应的服务器上;对于随后来自同一IP地址的所有请求,则会被自动分配到这里。

第四种是最少连接数,把请求转发给连接数较少的后端服务器

除了这个之外,我们还可以基于响应速度和url hash进行处理,在项目中我们采用的是权重形式。

在我们的项目中采用微服务架构时, feign和zuul均采用了ribbon这一功能组件. ribbon主要负责在各微服务之间建立交互关系并实现负载均衡功能. 当我们在注册中心完成对微服务的注册且确保其名称一致时,系统会默认将这些微服务视为一个集群. 在发起远程调用或进行路由转发操作的过程中,ribbon会均匀地分配响应服务器的负载. ribbon采用轮询策略作为默认配置,但这种机制也可以根据实际需求进行自定义优化

4、hystrix介绍

在微服务架构中,hystrix扮演着熔断器的角色,并实现了包括资源隔离流量限制控制故障熔断机制触发降级处理以及提供详细的运维监控数据等功能

在微服务架构中存在多个相互调用的服务单元;当基础层的服务出现故障时,可能导致一系列的次生故障,从而可能导致整个系统的完全不可用.这种现象被称为Service Snowdrift Effect. Service Snowdrift Effect是由于'Service Provider'的不可靠而导致'Service Consumer'也不可靠并由此逐步加剧其不可靠性的过程

熔断器的工作原理极为简单,并与电流过载保护装置具有相似性。该机制能够迅速触发故障中断,并在检测到多个相似错误后迫使后续多次尝试均会立即中断。当其在一段时间内检测到多个相似错误时,在随后的所有调用中都会立即触发故障中断,从而防止应用程序不断地尝试执行可能会失败的操作。此外,在发生故障后,在每次故障中断期间的应用程序都会返回缓存存储的数据或直接执行回调操作,并通过这种方式避免因长时间超时而消耗大量 CPU资源。熔断器还允许应用判断错误是否已得到纠正:一旦发现已经纠正,则会在下次尝试时重新启用正常操作功能

当 Hystrix 命令尝试向后端发送请求次数超过设定比例(默认为 50%)时,断路器会切换至开放(Open)状态。此时所有请求将直接失败而不被转发至后端服务。断路器会在未恢复连接的情况下维持开放状态直至预设时间(通常为 5 秒)结束,在此期间它将自动过渡至部分开放(HALF-OPEN)状态。在此期间该机制将评估下一次请求的状态:如果成功,则断路器将恢复闭合(CLOSED)连接;如果未成功,则将继续维持开放(OPEN)状态以等待下次尝试。与家庭电路中的保险装置相仿,Hystrix 的断路器能够有效隔离失效的服务,避免不必要的流量浪费并确保系统的稳定运行

请阐述Eureka和ZooKeeper所提供的服务注册与发现功能有何不同?

ZooKeeper负责保障了一致性和容错能力,并非仅局限于一致性本身;而Eureka则负责保障了可用性与容错能力

ZooKeeper在选举期间注册成功但服务出现故障无法正常运行,在此期间用户无法访问该服务直至投票结束后所有参与方的数据已同步完毕之后方可继续使用该系统

ZooKeeper在选举期间注册成功但服务出现故障无法正常运行,在此期间用户无法访问该服务直至投票结束后所有参与方的数据已同步完毕之后方可继续使用该系统

在Eureka系统中各节点之间处于平等关系,在任意一台活跃的Eureka节点即可确保服务处于可用状态。然而由于该系统的自我保护机制会阻止其从注册列表中删除那些长时间未发送心跳却应已过期的服务项。即使存在故障恢复后仍能处理新增服务的注册与查询请求但不会同步至其他节点(高可用性集群)。当网络环境稳定后,当前实例的新注册信息将逐渐同步至其他节点(达到最终一致性水平)。

Eureka能够有效地处理在面对网络故障时部分节点断开连接的情况,在这种情况下它不会像ZooKeeper那样导致整个注册系统的崩溃。

2、ZooKeeper有Leader和Follower角色,Eureka各个节点平等

ZooKeeper遵循多数存活机制,在分布式系统中实现高可用性;Eureka采用了自主防御机制来应对数据分区带来的挑战。

4、Eureka的核心模块属于微服务架构的一部分,而ZooKeeper则是一个独立的进程,必须单独配置安装

3

ElasticSearch相关面试话术

1、介绍一下ElasticSearch,以及在项目中的应用

基于Lucene的分布式全文搜索引擎是由Java语言开发而成的。该系统采用RESTful web接口设计,在搜索领域具有较高的性能表现,在我们的项目中主要负责获取商品信息的相关数据支持工作。其中商品信息构成较为复杂,并且数据规模庞大,在现有配置下通常能够达到几十万条记录的数量级水平。若采用MySQL进行检索操作,则效率将显著降低,并会对MySQL服务器带来较大的负担

在使用过程中主要需要做几件事:

1、Es服务的安装,中文分词器使用IK分词器,这个主要是运维负责;

2、在项目中集成springDataElasticSearch框架,用来操作ES;

在开发一个实体类时,请确保该类中包含与商品相关的所有字段属性。为此类添加必要的注解信息以记录该索引库的基本数据特征:包括分片数量、副本数量等关键参数。对于某些字段无需附加说明(即默认情况下系统会根据存储的数据推断其类型),而其他字段则需明确标注数据类型及是否进行分词处理等特性。在完成所有字段设置后,请新增一个统一的搜索字段命名为'all'(大写字母),并将常用搜索项如商品标题、副标题及品牌标识等全部包含其中

4、初始全量数据导入

通过springboot测试类完成导入操作;按批次从mysql数据库提取数据;整合处理后的数据存储至es系统。

5、修改、新增、删除等增量数据导入

基于RabbitMQ实现,在商品上架及下架的过程中向MQ发送消息,并完成ES数据同步操作以及静态页面的数据同步操作。

6、使用es实现搜索

采用all机制进行关键词分词与检索,在matchQuery框架下完成该过程。该方法将输入的关键字先进行分词处理后,在matchQuery框架下完成关联性语义分析与结果候选生成,并根据设定规则对候选结果进行排序筛选以输出最终结果。具体而言,在项目中配置了一个all字段,默认情况下该字段包含所有可能参与分词的关键字或字段信息,并仅对该all字段进行分词处理,并在关键字搜索时对该字段的内容进行匹配。通过规格参数聚合来实现实体商品搜索功能中的相关展示与渲染;通过布尔逻辑运算实现对商品规格、品牌以及分类信息的有效筛选;通过布尔查询实现规格参数、品牌、分类信息的有效关联性语义分析并输出最终结果;同时支持基于此功能实现的商品库存管理相关业务逻辑开发及数据统计分析功能;此外还实现了基于此功能的商品推荐算法开发及个性化服务功能支持;最后实现了基于此功能的商品浏览界面优化及用户体验提升功能支持 2. 采用Elasticsearch技术的主要原因是什么?

由于商城中的数据未来规模将非常庞大,在这种情况下采用传统的模糊查询方式将会导致无法承受的性能损耗。具体而言,在执行模糊查询之前就需要对相关配置进行特殊设置,并由此产生的后果是不再建立索引这一关键操作。在百万级别规模的数据库中执行全表逐一扫描这样的操作无疑会导致检索效率低下。因此为了提高搜索效率我们转而采用基于Elasticsearch(ES)的全文检索技术在这种系统中我们只需要将频繁被查询的商品相关字段如商品名称描述价格以及商品id等信息存储到专门的倒排索引中ES内部就具备了高效的倒排索引机制这种机制的基本原理是将待检索的关键字进行分词处理后记录下每个词条对应的文档id在检索阶段则可以通过分词后的关键字定位到每个词条的相关文档id并通过id来定位到对应的数据记录从而实现了高效的全文检索操作这种方法也是全文检索领域中最常用也是最有效的实现方案。

3、 什么是桶(bucket)?什么是度量(metrics)?

这个系统会通过某种方法对数据进行分类管理,默认情况下会将相似的数据归为一类,在 Elasticsearch 中这类分类结构被称为 bucket(容器)。每个数据集在 Elasticsearch 中都会被赋予一个默认的 bucket 标识符(ID),具体来说就是这个 container 的名称标识符。例如根据国籍将人划分为不同的国家 bucket……或者我们按照年龄段对人进行划分:年龄范围从 0-1 岁、1-2 岁等。此外该系统还支持多种分类策略如基于日期的时间段分类策略、基于数值值的区间分类策略、基于词条内容的内容类型分类策略以及结合数值值与日期范围的复合型分类策略等等

在分组完成后的一般情况下,在组内执行聚合计算。这些在 Elasticsearch 中被称为度量指标。具体来说,包括取平均值、找出最大值与最小值、计算百分比以及累加等。

4、es内部存储的存储结构

es内部默认采用分布式存储架构,在创建索引库时需指定分片数量与副本数量参数。其中分片数量决定了数据如何分布在各个分片上;所有分片数据总量等于索引库总数据量;增加分片数量可提高数据分散程度;在搜索过程中es会同时检索各分片中的数据并返回结果;副本数量指的是在索引填充时同步复制的数量;提升副本数量会增加存储空间需求;建议遵循生产规范设置为5个分片及2个副本,默认配置即可满足常规需求。

4

页面静态化相关面试话术

首先说说为什么要进行页面静态化

从这一部分可以看出,该模块会预先设置并展示固定的30条数据结果。目前该模块的流量已经非常显著了,在整个平台上的访问量来看,这个数值已经是远高于预期水平。因此,在每次请求详情页时直接获取数据的方式显然不够高效

其次这个详情页面来说不会经常地发生变动因此每次从服务端获取的数据基本上都是稳定的这样一来我们就必须想办法解决如何快速响应如此庞大的流量需求

在我们的项目中,默认情况下服务端与前端都采用nginx进行反向代理。具体来说,则是基于两个关键点展开解决方案。首先是利用模版引擎技术,在用户体验首次访问某个特定数据的具体页面时(当用户首次访问某个数据的具体页面时),我们系统会通过thymeleaf技术自动生成静态HTML页面(通过thymeleaf技术自动生成静态HTML页面),响应并返回给前端(响应并返回给前端)。接着,在第二次访问该数据的具体页面时(接着,在第二次访问该数据的具体页面时),系统会通过 nginx 配置机制(通过 nginx 配置机制)先检查指定目录下是否存在已生成的静态HTML文件(先检查指定目录下是否存在已生成的静态HTML文件)。如果发现存在,则直接从该目录中调用相应文件进行展示(如果发现存在,则直接从该目录中调用相应文件进行展示);如果未找到,则会将请求转发至微服务端以获取最新的原始数据(如果不存在,则会将请求转发至微服务端以获取最新的原始数据)。

然后在网上的时候,在线内容会结合CDN技术,并指向由nginx代理提供静态页面的路径,在此过程中能够显著提升用户体验。

在同时创建静态页面的过程中会遇到一个问题:即当数据库发生修改时,需要将其同步到静态网页中。针对这一需求,在系统架构设计中我们选择了RabbitMQ来进行异步处理。具体而言,在数据库数据修改后,系统会通过MQ发送消息给静默化服务接收到消息后会重新生成一遍HTML页面从而实现了与数据库数据的实时同步

5

rabbitmq相关面试话术

1、介绍一下rabbitmq

RabbitMQ是一款基于AMQP协议、由Erlang语言实现的消息传递系统。其核心理念在于生产者不会将消息直接投递给队列,在消息投递给客户端之前会先进入交换机进行中转处理,并由交换机将消息转发至相应的队列。该系统对路由配置、负载均衡策略以及数据持久化功能均提供了良好的支持。

它里边有5种数据传递方式

该模型较为基础,在其架构中包含单个生产者、一个消息队列以及单个消费者。值得注意的是,在这种设计下,消息队列仅能被单个消费者监听。因此,在生产者向消息队列发送消息后方能实现的消息传递中只有一个消费者能够接收该消息。

第二种方式采用工作模式,在这种结构中存在单一的生产者节点和一个消息队列。该系统支持多个消费节点同时监控这个消息队列。然而,在实际运行过程中发现一个问题:当生产者向消息队列发送消息时,并不能保证只有一个消费节点能够接收该消息。

在采用交换机模式的三种架构中,在这三种模式中,在这种架构下,在这种配置下,在这种设置下,在这种配置下,在这种架构中,在这种模式里,在这种情境中,在这种环境下,在这种配置里

首先是基于广播机制的分发模式(Fanout),即扇出型传播方式。生产机构发消息至交换机,在此过程中后者会将信息传递至所有已绑定于当前交换机的队列中。这些接收到信息的监听队列对应的消费者均可获取数据;若无相应队列绑定至该交换机,则该消息会被MQ系统丢弃。

接下来介绍的是direct类型的一种特定实现方式——定向模式或路由模式。在该模式下,当将队列绑定到交换机上时,在生产者发送消息给交换机的时候(即当生产者发送消息给交换机时),系统会自动根据生产者所指定的.routing key(即其对应的.routing key)进行路由转发。具体而言,在这种情况下(即在这种情况下),交换机会根据接收到的消息中的.routing key值来决定向哪个队列进行转发(即相应的队列消费者能够接收到相应的消息)。需要注意的是,在这种情况下(即在这种情况下),如果换行没有找到对应的.routing key,则该消息会被丢弃(即如果系统未找到与之匹配的.routing key,则会丢弃该消息)。

该模式采用topic机制进行消息路由配置。当将队列绑定至交换机时,默认状态下也会指定自己的routing key值(即路由键)。生产者在发送消息至交换机时,则需要同时指定目标路由键值(即目标路由键),以便正确路由消息到对应的队列中。通常情况下,该routing key由多个单词通过.分隔符构成(如:my.rout.key)。在通配符设计中:

  1. #号表示任意长度的子键匹配(如:my.rout#)
  2. 号表示精确匹配单个词项(如:my.rout.
    具体来说:
  • 如果生产者指定的通配符为my.rout# ,则会匹配到以下所有可能的routing键值:
    • my.rout.a
    • my.rout.a.b
    • my.rout.a.b.c 等等
  • 如果生产者指定通配符为my.rout.* ,则只能匹配到单一词项构成的目标路由键值(如:my.rout.a 或 my.rout.b 等)
    值得注意的是,在实际配置中可以选择定义多个目标路由键值与队列进行绑定。交换机会根据指定的通配规则自动将消息分配至符合条件的目标队列中,并相应地将消费者资源分配至这些目标队列上以处理消息接收任务。如果某个队列无法找到符合其目标路由键值对应的可用目标队列,则系统会丢弃该消息

在生产环境中使用时,在 RabbitMQ 系统中实施消息持久化策略以防止 MQ 故障导致的消息丢失问题。具体而言,在 RabbitMQ 中我们需要对交换机、队列以及消息均进行持久化存储设置,并确保其会被保存到磁盘上以避免突然的电源中断等意外情况导致的数据丢失。

2、如何保证消息确定消息发送成功,并且被消费成功,有什么保障措施

无需记忆这些常见问题的具体表述方式,在考试中遇到类似题目时无需死记硬背即可应对。常见的提问方式有多种,在本题中主要涉及两个主要方面:一是确保消息发送的成功性,并且在实际考试中可能会以以下几种形式提出问题:比如在消息发送出现故障时如何解决;二是保证消息消费的成功性,并且在实际应用中可能会以以下几种方式进行询问:比如在消息消费过程中出现问题如何处理等

在消息发送过程中必须确保其成功到达 RabbitMQ 中的消息传输系统中包含了事务管理与确认机制。其中事物的概念类似于数据库事务的概念:即开启事务并执行其逻辑操作后提交到目标存储层;若在此过程中发生任何异常事件则会触发回滚机制;在回滚过程中可以通过引入相应的处理逻辑来实现重传或日志记录等功能;同时建议配置生产者确认机制:即在消息发送之后系统会为其分配唯一的标识码;当消息被交换机转发至队列后 RabbitMQ 会向生产者发送ack确认;若队列未接收到消息则会返回错误回执给生产者;生产者可以根据接收到的反馈结果尝试重新发送或记录日志信息;通过这种方式可以看出 RabbitMQ 在保证消息严格一致性的同时确实会对性能产生一定影响:如果应用场景要求严格的一致性则有必要采取上述配置措施;但若消息本身的重要性较低或者容许出现偶尔丢失的情况则可以选择不配置相关功能从而能够有效提升系统的性能表现

除了这一点之外,在完成信息包发送成功后还需要保证信息包在消费者端能够被成功消费。若在消费者端遇到信息包消费异常且未做相应的处理措施,则可能导致信息包丢失。此时可采用以下两种解决方案:一种是对消费者端的异常处理机制进行优化;另一种是增加对信息包状态的监控频率以及时发现并纠正问题

首先,在消费端部署手动ACK确认机制。当消息被消费完成后进行手动确认通知MQ系统已完成接收。如果MQ未收到ACK确认信息,则该条消息会被标记为unacked状态。通过查看项目日志或访问MQ管理界面(MQ Dashboard),我们可以观察到当消费者断开线缆后的消息会在队列中等待重新接收;一旦消费者重新连接在线缆状态下他们将能够再次接收到相关的信息。

第二种方法是通过数据库来实现的。当生产者发送消息成功后,在数据库中进行存储操作,并记录该消息的内容及其发生时间,并将其状态标记为未消耗状态;而当消费者处理完毕后,则会定期从数据库中检索超时未被处理的消息,并将其重新提交到队列中进行处理。这种方法能够有效解决消息消费失败的问题;但同时也带来了更高的依赖程度,并可能导致消息被多次处理的情况出现;因此我们可以在确保消息传输成功的前提下将这一逻辑转移至消费者端的处理流程中:即当生产者正常发送消息时,在接收端将其存储到myqsl队列并标记为未消耗状态;同时通过ack机制确认其已收到并准备进行处理;一旦消息被成功消费,则会将数据库中的状态更新为已消耗状态;而消费端则应配置定时任务执行类似的操作:定时从数据库中检索超时未被处理的消息并重新提交给生产者队列进行重传

这些解决办法都需要基于实际情况制定;如果消息必须保持强一致性,则不允许出现任何错误;如前所述,则应按照前述方法添加相应的配置。

我们项目中的mq主要用于数据同步使用。当mysql数据发生变化时,必须将修改同步至es索引库以及静态页面。在我们的配置中,采用了生产者确认模式,并为消费者设置了人工ack确认机制。

3、如何保证消息不被重复消费

在生产者端发送消息时,在数据变动部分执行MD5加密处理,并配置一个唯一ID。每次发送的数据均有一个递增的唯一ID(相当于版本号的功能)。在消费者端收到消息后首先查询数据库中对应的MD5值:如果发现数据库中的当前记录已被耗用,则不会对其进行处理;如果发现数据库中不存在该条记录或记录的状态未被耗用,则会重新对这条消息进行消费。

4、RabbitMQ 宕机了怎么处理

RabbitMQ 提供了消息的永续性功能(机制),它能够将内存中的信息永久存储于硬盘上,在兔兔服务重新启动的情况下也不会导致数据丢失。就队列管理而言,则分为永续性和非永续性两类:前者会在磁盘上建立长期存储并持续维护原有状态(即使服务重启),而后者则不具备这一特性,在服务重启时将会消失。从性能角度来看,则是非永续性的运行效率更高(因为它们无需存储于磁盘),即非永续化的性能优于永续性表现;而如果从数据可靠性考虑,则必须保证信息不会因服务中断或系统故障而丢失(因此永续性的优势在于数据始终存在)。因此,在实际应用中应当依据具体情况充分考虑其适用场景

6

认证授权相关面试话术

1、你给我说一下授权认证(登陆注册)的逻辑

对于这一部分而言相对简单我们可以支持的注册功能包括用户名密码注册、手机验证码登录以及微信绑定账户的登录流程

用户名密码注册登陆我们系统规定的是用户名不得重复,注册的时候,会去做一下重复校验,向后台提交注册信息的时候,密码都会经过md5加密传输,到后台会首先用加密工具生成32位的盐值,然后把用户名通过md5加密之后,用户名的md5和密码的md5和盐值结合之后,生成md5值,然后一起存入数据库,用户登录的时候,按照首先根据用户名去数据库查找用户,找出来用户之后,根据相同的逻辑计算加密之后的密码和数据库的密码对比,对比一致则登陆成功手机号注册登陆(推荐使用,方便快捷)这里用到了阿里的短信服务功能,注册的时候,手机号码校验通过之后,向用户手机发送验证码,后台将验证码和手机号对应关系存入redis,用户提交注册之后,验证码跟redis中对比即可微信登陆绑定系统用户注册这里结合微信登陆使用的,微信登陆之后,如果发现对应openid没有绑定系统用户,需要提示用户去绑定,然后才能注册常识:微信开发,有两个平台,微信开放平台,主要用于app端以及web端扫码登录等开发,app中,微信登陆,微信支付,微信分享等微信公众平台,主要用于微信网页开发,公众号开发,公众号中网页登陆,微信分享,微信支付等微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret。申请微信登录且通过审核后,可开始接入流程。就是你的网站要想实现微信扫码登陆功能首先要在微信备案通过,它才会给你个AppID和AppSecret。1、用户点击网站微信登陆图标。2、网站带上AppID和回调域名参数请求微信OAuth2.0授权登陆。3、第二步通过后,微信返回二维码供用户扫码。4、用户扫码确定授权。5、微信带上code参数回调java后端回调地址。6、java后端获取到code后,在带上带上AppID和AppSecret和code再去调微信接口获取access_token。7、获取access_token后就可以解析用户的一些基本信息,比如:微信用户头像、用户名、性别、城市等一些基本参数。因为是app登陆,需要用到微信开放平台的接入功能,微信登陆采用的auth2.0的验证机制,在开放平台里注册了账号并通过企业认证,获取了AppID 和 AppSecret之后,第一步我们的服务器先获取code,传给移动端,移动端跟微信交互,用户确认授权之后,然后移动端请求我们后台获取用户信息,我们后台会先去用code获取access_token,然后在通过access_token获取用户信息,同时会返回用户的openId,我们会根据这个openId去我们的数据库查,是否已经获取过用户信息,如果获取过用户信息,看一下最后获取时间,因为每3天更新一次,所以这里会看一下是否需要重新获取如果没有获取过用户信息,会通过access_token获取用户信息,提示绑定系统用户,access_token失效时间为2个小时,因为微信有接口请求次数限制,2小时之内不会再去请求微信的access_token微信app登陆web端微信扫码登录因为我们系统是微服务架构,所以这里使用jwt实现了单点登录,因为平台有很多,有web端、管理端,还有一个清结算平台,实现单点登录会更方便用户使用,登录之后,给用户颁发了一个token令牌,每次请求的时候,都会在请求头里携带这个token,经过我们的网关的时候,会对这个token做一个权限认证,认证通过,然后才能请求到我们的微服务具体的接口

2、说一下jwt

在微服务集群架构中,每个服务对外提供的接口均为Rest风格规范.而Rest风格体系的一个核心标准便是:服务实现无状态特性.即:

服务端无需存储任何关于客户端请求者的相关信息,在每次请求时都需要提供自我描述的信息以识别客户端的身份。通常这种情况下使用的是token作为登录凭证。这样处理的好处在于能够有效防止未授权访问并提升系统的安全性。例如,在这种机制下服务端能够快速验证客户端的身份并进行授权访问控制。

客户端的所有请求操作均不涉及服务端存储的信息。任何一次或任意多次请求都不需要访问到同一台集群的状态以实现一致性和可靠性要求;而透明的服务架构则允许支持任意次数弹性伸缩以应对负载波动需求;在本项目中采用的是无状态登录技术方案,在这种架构下使用token作为身份认证机制;该token由jwt算法生成并分为三部分:头部、载体(内容)、签名;其中头部用于存储识别信息载体内容则包含用户的基本字段(如id和username);而签名是基于头信息与体数据结合使用RAS算法进行非对称加密处理后得到。

3、说一下auth2.0机制

其实在一种权限管理机制下运行着这一过程。由数据的所有者授予该系统一份访问权限凭证后,系统将随后生成一个临时访问令牌(Token)。这个Token取代传统密码方式,被第三方应用程序所使用即可完成授权流程。

令牌(token)与密码(password)的功能是一样的,并且都可以用来登录系统,在某种程度上它们之间也存在一定的差异。

(1)该系统中的令牌具有短暂的有效期,在达到指定时间后会自动失效,并且不能自行更改。密码则通常保持很长时间不变,并且无需更改即可维持原样。

(2)可由数据所有者撤销该令牌,并在使用后立即失效。就如例子所示,在线用户可随时取消快递员的令牌。密码通常不被他人所撤销。

(3)令牌具有权限范围(scope),例如仅限于小区二号门这一特定区域。在网络服务中,仅读类型的令牌相比具备读写权限的令牌更为安全可靠。密码通常代表完整的权限配置。

基于这一系列设计的巧妙构思下,在任何情况下都能够提供一个安全可靠的解决方案。

请记住:只要有知道了 tokens 就可以直接进入系统。通常情况下 系统不会进行额外的身份确认 因此 为了确保安全起见 tokens 必须严格保密 任何泄露都会带来相同的危害 即使 tokens 和密码的安全性相同 那么 tokens 的有效期也应该设置得非常短暂。

具体来说,auth2.0一共分成四种授权类型

第一类是基于授权码的模式。这种模式是最常用且安全度最高的方法,在实际应用中被广泛应用。它特别适合那些具有服务端支持的Web应用环境。该模式的核心在于将授权管理与身份验证分开处理:一方面由前端发送由用户提供的信息(如注册信息),另一方面则由服务端接收并验证这些信息以确认用户身份。在这个过程中,“授权码”作为关键的安全凭证被生成并传递给客户端设备(如手机)。这种分离化的管理架构不仅能够有效提升系统的安全性(因为客户端无法直接访问敏感资源),还可以简化系统架构设计并提高运行效率。具体来说,“授权码”的生成通常依赖于特定算法(如哈希算法),而验证过程则通过调用预先配置好的API来实现。“回调地址”这一概念则用于建立客户端与服务端之间的交互通道:当客户端发起登录请求时会自动触发服务端上的特定回调函数,并附带包含必要的验证信息(如上文所述)。这种方式不仅可以实现跨平台的身份验证功能(如常见的第三方登录方式如微信登录等),还能在不同版本之间无缝衔接并保持一致的安全性标准

也就是隐藏式、密码式以及客户端凭证这三种模式吧?我在大概了解了一下这些概念,并未真正操作过。

7

nginx相关面试话术

1、介绍一下nginx

Nginx 是一个高效率的 HTTP 逆向代理服务器,并提供负载均衡、静态与动态分离等功能

我先来说说反向代理功能吧

反向代理是指由代理服务器响应用户的请求,并将该请求转发给内部服务器群,在这些服务器中获取所需数据后返回给客户端系统。这种机制使得远程客户端无需直接连接至被控服器即可实现访问与交互。反向代理的核心在于:前端负责执行服务。

反向代理的情况下,则主要涉及对一个服务器模块的配置。具体而言,在该模块内部需设置 server_name 以及指定相应的端口号,并根据需求设置 forward rules for the location。此外还可以设置代理后的静态资源。

再来探讨一下负载均衡的相关知识吧。在实际应用中,负载均衡的核心机制是通过代理服务器将接收到的请求均匀地分配到各个服务器上,以实现资源的最佳利用和性能的最大化。在这一过程中,我们主要关注的是如何有效缓解网络拥塞问题、提升单个节点的服务能力以及确保数据传输的安全性与稳定性等多重目标。其中,服务就近原则通常会使得响应更加迅速且效率更高,从而以更高的整体服务质量为用户提供更好的访问体验。此外,通过合理的负载均衡策略配置,后台 server 的繁忙请求量能够得到有效的分流与管理,避免出现大规模并发导致的服务中断或性能瓶颈现象发生。值得注意的是,默认情况下系统会优先采用轮询策略作为其分配机制的基础,这也是为什么在 many 现实场景下这种策略能够展现出较高的适用性和稳定性原因

正确设置upstream模块中的负载均衡策略,在此基础之上为每个服务器指定相应的IP地址与端口组合,并在服务器模块中根据预设的转发策略将流量发送至该upstream模块即可完成负载均衡的配置工作

2、nginx如何处理http请求

Nginx这一块的处理流程融合了多进程和异步机制的应用,在具体实现中采用了一种高效的同步方式

首先呢是多进程机制

每当服务器接收一个客户端请求时,在处理过程中就会有主进程(Master process)负责创建一个工件(Worker process),该工件会与之建立通信并进行交互;当该连接断开时,则这个工件也随之终止。

该方法的优势在于各子进程之间互不影响且无需加锁,在避免因使用锁而导致的性能损失的同时降低了程序设计的复杂性以及开发成本。此外该方法可实现各子进程间的完全分离与独立运行,在主进程中一旦出现异常退出情况其他从进程中即可正常处理而主进程中则迅速切换至新的子进程中从而最大限度地保障了服务的连续性与稳定性。其主要缺点在于操作系统生成子进程中需进行内存复制等操作这会带来一定的资源消耗与时间开销。因此在处理大量请求时可能会导致系统整体性能有所下降

还有就是异步非阻塞机制

每个工作进程 使用 异步非阻塞方式 ,可以处理多个客户端请求 。

当某个工作进程接收到客户端的请求后,在调用IO进行处理时发现无法立即获得结果,则会转而去处理其他请求(这就是非阻塞的方式);而客户端在同一时间段内同样不需要等待响应就可以进行其他操作(这就是异步操作)。

一旦 IO 完成返回操作后, 系统会立即向该工作进程发出通知信号; 该进程接收到相关通知信息后会暂且搁置当前处理的事务以应对客户端的需求.

3、nginx常用命令

启动:nginx

当我们修改配置了之后,重启:nginx -s reload

停止nginx:nginx -s stop

4、什么是动静分离,为什么要动静分离

从我的理解来看,这主要是将前端的静态资源与后端的请求进行分离。这种做法的主要目的是为了提高静态资源的访问速度。通常前后端分离的技术在项目中较为常见。通过分离后,我们可以将静态资源托管到CDN服务器中,这样不仅能够实现用户就近访问资源,还能显著提升带宽容量.

5、如何保证nginx高可用

由于Nginx是我们项目的核心入口节点,在保障其正常运行方面具有至关重要的作用。因此,在我们的架构设计中,默认会部署Nginx集群,并结合KeepAlive技术实现两台服务器之间的负载均衡与故障切换。为了确保每个服务都能快速响应请求并提供稳定访问,在实际部署过程中我们采用了一种基于虚拟IP地址的负载均衡策略:通过生成一个虚拟IP地址(Virtual IP)来映射到实际服务器上的公网IP地址。这种设计不仅能够有效提升系统的扩展性与容错能力,在某台服务器出现故障时系统会自动将绑定到该机器上的虚拟IP地址转移到另一台健康的服务器上。

8

前端相关面试话术

1、介绍下VUE(如果分开问你的话,就分开说)

在用户的认知中

vue常用的指令包括常见的如 v-for 、 v-if 和 v-show 等。
用于绑定事件的指令是 v-on 。
通常可简写为 @ 符号 。
用于绑定属性的指令是 v-bind 。
通常可简写为冒号:

另外关于Vue生命周期的知识中提到过一个重要的钩子函数——created事件,在组件创建后会自动触发该钩子函数。我们在服务端初始化数据以支持后续的数据准备过程时通常会使用该 hook 函数来处理相关操作。根据具体需求有时候我们会采用不同的策略:比如当页面整体框架渲染完成后才进行数据加载,则可以在 mounted 事件处执行相应的操作以完成数据同步;这种机制类似于内置JavaScript API中的onload方法用于实现类似功能

除此之外,在实际开发中也存在一些特殊需求场景需要处理。常见的情况是开发者会采用分层架构来进行模块化设计,在这种架构下通常会遇到一个问题:如何实现跨层级的数据交互与功能关联?这个问题可以通过动态绑定属性的方式进行处理,在子组件中通过props接收数据与方法。但需要注意的是,在某些情况下(如基于DOM的传统UI框架),由于其对DOM树的直接控制能力不足(尤其是针对现有结构难以进行增删改查操作),导致其无法直接修改父节点对应的业务对象值。这就要求我们必须设计一种间接的方式来实现这一功能:即先让父节点具备某种特定的方法接口(通常以@符号前缀的方式进行声明),然后由子节点通过@特定属性名的方式获取并引用这些接口;最后当需要执行相关操作时可以通过$emit指令触发相关操作以完成跨层级的数据更新与业务逻辑变更

另外一般vue项目都是通过npm管理的,npm呢就相当于与前端的maven,主要是帮助我们管理js依赖的,我们在想要添加js依赖的时候,比如axios,可以通过npm install -g exios命令来下载就行了,也不需要我们从网上手动下载了,另外结合webpack打包的工具,在开发以及部署的时候方便很多了,不过这些都是我们专门的前端工程师来做的,用vue的脚手架搭建框架,以及配置路由等等,我们实际去写的时候,都是往里边填代码,我这边平时就是好琢磨,就研究了一下,现在来说,简单的框架搭建,以及npm管理来说,都不是问题。

2、说说你了解过的UI框架

遵循Vue风格的MVVM理念,在实际应用中最为常见的便是ElementUI;除此之外,还有Vuetify和iview等工具可供选择。

遵循jQuery风格的手动DOM元素操作,并包含Bootstrap、La UI以及早期版本的Easy UI等

如今移动端开发框架越来越受欢迎的应用程序开发平台之一是Flutter应用程序开发平台。其中一个是Flutter应用程序开发平台是由谷歌推出的一个完全免费使用且功能开放的移动界面技术平台。

3、jquery元素选择器都有哪些

("#id")(".clazz")$("标签名")

9

工作流相关面试话术

1、工作流话术

工作流这块儿。在实际操作中采用activiti较为常见。此外还有其他的一些工作流引擎,在网上的资料上大概了解了一下。其中像JBPM以及workflow等工具的实际应用情况较为有限。而activity目前来讲在数据库系统中涉及23个相关表

当使用该功能时,首先要配置包含23张表的数据库结构。接着加载activity的配置文件。在选择加载方式时存在两种可能性。嗯,在编写这个演示脚本的过程中,我采用了Spring框架来解析XML配置文件作为基础设置。该XML文档中包含核心引擎管理器ProcessEngineConfiguration以及数据库连接信息等关键参数设置。将这些设置整合到Spring的核心配置中完成初始化。

接下来需要定义的是一个流程。为了实现这一目标,我们借助Eclipse插件采用绘制流程图的方式实现了简单的理由请假功能的设计,并最终输出了包含该请假管理功能的一个压缩文件包。

下一步需要将该流程部署至Activity中。具体操作如下:首先利用processEngine获取待部署的类;接着为该流程命名并配置必要的参数;最后将该压缩包配置文件部署至activity中运行;执行上述步骤后系统将返回对应流程的唯一标识符

接下来必须启动一个流程实例,在系统已经部署完成的情况下,当有人提交请假请求时,则应当启动一个新的流程实例。每个流程实例都会被分配一个独一无二的ID号码,并且每个实例都有其独特的运行状态信息。为了使系统更加灵活高效,在设计变量时可以区分全局变量与局部变量这两种类型:全局变量会对所有正在运行中的流程产生影响;而局部变量仅限于特定 workflow 的操作范围之内。这些变量会在整个 workflow 的执行过程中持续发挥作用,并根据其属性进行传递下去。随后这个 workflow 示例会继续向下一个节点传递任务,在接收任务后同样通过 taskservice 进行处理工作;最终直到任务被完整执行完毕。

总体而言呢,这个activity通过利用代码实现了对一些流程性问题的简化处理。然而,在其运行过程中还会遇到较为复杂的环节。例如,在如何实现多任务协同处理方面以及如何处理复杂的节点问题上都需要进一步探索和完善。这些正是我对activity工作流的基本认识和理解。

10

spring相关面试话术

1、介绍一下spring

关于Spring的知识,在实际项目开发中我们一直都在应用它。不论是基于SSH的架构还是基于SSM的框架,“Spring Boot”都实现了良好的集成。其核心理念主要包括三点:IOC控制反转、“AOP切面编程”。

让我先介绍一下IOC是什么。它指的是Spring框架中的逆向控制模式。通过将类的管理权移交给Spring框架来进行协调,在我们配置应用时,在Spring的核心配置文件中设置相关参数。并预先设置好了Bean标签名以及完整的类路径信息;如果需要传递特定的属性或数据,则应在配置文件中相应地进行参数设置。这样Spring框架就会利用反射机制自动生成相应的对象实例并将它们注入到容器环境中进行管理。

在应用中使用时,请结合依赖注射技术进行操作:将希望使用的类导入到相应的位置是可以的。具体而言主要有以下几种方式:构造器注入、getset 注入以及注解式注入。目前我们主要采用 @autowired 和 @resource 标签来进行依赖管理。

然后就是AOP切面编程技术,在不影响源代码的前提下增加对代码功能的提升。通过预先在配置文件中标明切点位置,并设计相应的逻辑流程即可完成代码功能的提升。该提升机制支持在切点运行前、运行中以及运行后阶段分别实施额外的功能扩展,在不影响源码的同时灵活应对多种业务需求变化,在.NET平台项目中通常将该技术应用于权限控制、日志管理以及事务处理等领域

2、AOP的实现原理

这部分内容了解了spring的核心机制,并了解到其底层采用的是基于动态代理的技术实现。关于动态代理的概念是:一种技术框架下不会直接修改类文件中的字节码代码结构;相反,在每次程序运行时会在内存中临时为每个需要被切点增强的目标方法生成一个独立的AOP(面向切面编程)对象。这种AOP对象会包含目标对象的所有相关方法,并且在其特定切点处增加额外的功能模块;随后会自动调用原始目标对象对应的方法实现流程。

在Spring AOP框架中实现动态代理的主要方式主要包括两种途径:基于JDK的动态代理机制以及基于CGLIB的动态代理机制:

JDK 动态代理仅能实现接口层面的代理功能,并不具备对类级别的代理能力。核心InvocationHandler 接口及 Proxy 类负责将横切逻辑与业务流程有机整合;而 Proxy 则通过动态创建符合接口规范的对象来生成目标类的代理实例。若所涉代理类未遵循InvocationHandler 接口,则 Spring AOP系统将默认采用 CGLIB 进行目标类的动态代理操作。CGLIB(Code Generation Library)作为一套代码生成型库,在运行时能够自动生成并配置指定类型对象的子类实例,并对其中关键方法进行重写以增强功能特性;这种基于继承机制的动力态代理方式存在一定的局限性:若目标对象被明确标记为 final属性,则无法借助CGLIB完成其动力态代理过程。然而,在当前业务场景中并未涉及过final类型的目标对象;我们主要针对Controller层面接口权限以及日志记录等模块进行了代理操作;同时也在Service层面实现了事务管理系统的统一协调功能

Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext

该 IoC 容器专门用于管理 Bean 类型的基础实例,并全面支持 IoC 服务流程。换句话说,该容器是一个创建并初始化 Bean 实例的工厂,在其生命周期中会为每个 Bean 实例创建实例并启动其生命周期事件(如构造函数、销毁函数等)。该容器不仅负责为每个 Bean 实例创建实例并启动其生命周期事件(如构造函数、销毁函数等),还负责启动相应的生命周期事件(如构造函数、销毁函数等)。

ApplicationContext 被定义为 BeanFactory 的一个延伸类,并被称为开发环境。它不仅继承了 BeanFactory 的全部功能,并且还增添了国际化支持、资源管理、事件处理等功能。

他俩的主要差别在于:当 Bean 的某一个属性未被实例化时,在通过 BeanFactory 加载后进行首次 getBean() 调用时会触发异常;然而,在ApplicationContext 初始化阶段会自动执行相关验证工作以确保所有依赖的属性均已成功注入。

因此,在实际开发中,通常都选择使用 ApplicationContext

4、@Autowired 和 @Resource的区别

@Autowired通常会按照类型进行默认注入。若未发现该类型的定义,则系统会尝试根据类名进行自动注入。当需要指定具体类名时,默认情况下只需添加注解即可实现功能。
如果在使用过程中发现无法自动识别某个类型的属性或字段,请可以通过手动添加 "@Qualifier("特定属性或字段的类名")" 来完成相应的配置。

@Resource注解同样可以从容器中注入Bean,默认情况下会按照名称进行注入。
如果没有找到对应名称,则会根据类型进行查找。
另外,在注解中可以直接指定name属性为 '@/resource(name="类名")'

5、springbean的生命周期

生命周期这块无非就是从创建到销毁的过程

Spring 容器负责管理 singleton bean scope 中的 bean 对象 lifecycle,在此 singleton bean scope 下, Spring 可以准确掌握 singleton bean scope 中的 bean 对象生成时间点、初始化过程完成时间点以及销毁时间点。

而针对那些配置为 prototype 作用域的 Bean,在 Spring 中只负责初始化工作。一旦容器生成相应的实例后,则将该实例交由客户端代码进行管理。值得注意的是,在这种情况下,Spring 容器将不再关注自身的生命周期。每当客户端发起对配置为 prototype 作用域的 Bean 的请求时,Spring 容器都会动态生成新的实例,并且无需处理这些被配置为 prototype 作用域的对象的生命 cycle。

整体来说就4个步骤:实例化bean,属性赋值,初始化bean,销毁bean

第一步是创建一个Bean实例。容器会根据BeanDefinition获取必要的信息来创建Bean实例,并利用依赖注入技术完成Bean中所有属性值的配置注入。随后进行属性赋值的过程中,默认会调用Reflection来实现赋值功能。接着是初始化Bean之前的工作流程:如果在配置文件中定义了init-method属性,则会调用指定的初始化方法;如果配置文件中定义了init-method属性,则会调用指定的初始化方法;最后是释放Bean资源的过程:最后是释放Bean资源,并与初始化方法类似地为destroy-method指定函数,在Bean销毁前执行必要的操作。

Spring 容器中的 bean 可以分为 5 个范围:

singleton遵循单例模式运作的Bean在Spring容器中只有一个实例,并且默认作用域。主要分布在Controller、Service和DAO层。

prototype:prototyped model(原型模式),每当Spring容器读取基于prototyped model定义的Bean对象时,默认会生成新的实例。

(3)request:对于一个 HTTP 请求而言,在此期间容器会返回与该 Bean 相关联的一个实例。而对于每个新的 HTTP 请求,则将分配给不同的实例,并且其作用域仅限于当前的 HTTP Request。

在每次 HTTP Session 中运行时(即当启动一个新请求时),容器都会为该 Bean 分配同一实例(即同一虚拟机)。而当处理不同的 HTTP 请求时,则会依次分配新的实例(即新的虚拟机),这些虚拟机的作用域仅限于当前正在处理的那个 HTTP Session 期间。

global-session:Global scope refers to the same instance of a Bean that a container returns within a global HTTP session.

7、事务的传播特性

分析显示,在不同操作类型之间进行交互时(即在相互调用的过程中),系统的传递机制得以实现。在处理事务时,在系统中定义了特定的行为模式来决定是否生成新的事务操作,并指导如何执行这些操作。

8、事务的隔离级别

Spring事务的核心其实是数据库对事务的支持。如果没有数据库对事务的支持,则Spring不具备实现事务功能的能力。实际应用中,默认情况下应用必须通过基于日志的机制进行提交与回滚操作。隔离级别分为四种类型

Read Uncommitted(未提交模式):允许另一个交易实例查看该交易实例尚未提交的数据,默认最低级别的隔离级别,在任何情况下都无法保证一致性。
Read Committed(已提交模式):确保只有当一个交易实例完成数据提交操作才会被另一个交易实例访问,并且能够看到该交易实例对其现有记录的更新操作。
Repetutable Read(可重复性读取):保证在一个交易实例完成数据提交后才会被另一个交易实例访问,并且无法查看该交易实例对其现有记录的更改操作。
Serializable(串行化):规定在一个具体操作期间内不会发生不可恢复性冲突或幻影现象的设计模式名称。
9、Spring框架中使用的主要设计模式有哪些?

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring采用了其AOP功能基于JDK提供的动态代理机制以及CGLIB实现的字节码生成技术。

(4)模板方法:旨在解决代码重复出现的问题。例如RestTemplate、JmsTemplate以及JpaTemplate等

观察者模式:定义了一种基于对象键的一对多依赖关系,在这种模式下,在某个事件触发后会自动通知相关的多个目标组件进行相应的处理或更新操作;例如,在Spring框架中,默认情况下实现了该模式的技术方案即为Listener类的实现--ApplicationListener

10、spring中如何处理bean在线程并发时线程安全问题

通常情况下,在Spring框架中实现大部分Bean对象成为singleton只需要满足特定条件即可;然而,在某些特殊场景下,默认配置可能无法满足需求。通过使用ThreadLocal机制来处理这些Bean中的非线程安全状态,在Spring中实现了对这些问题的有效解决。

Thread-Local 和线程同步技术都是为了解决多线程中共享变量引起的访问冲突问题。其中同步技术采用了一种'时间换空间'的技术手段,在这种机制下仅提供了一份共享变量给所有参与竞争的线程使用,在这种情况下不同线程在进行操作前需获取互斥锁以保证数据一致性;而没有互斥锁保护的其他无阻塞策略则导致未获取到互斥锁的其他线程则需依次排队等待处理以避免数据混乱状态的发生。而 Thread-Local 则采用了另一种'空间换时间'的技术手段

ThreadLocal通过创建为每个线程专用的局部变量实例来实现对共享数据的安全隔离。由于每个线程都有独立的本地变量实例可用,在这种情况下就不必单独进行同步操作。通过将不可靠的数据封装到ThreadLocal内部对象中,开发者能够确保在多线程环境中数据访问的安全性。

在我们的项目中,该拦截器实现了类似的逻辑,在我们的微服务架构中,网关不仅负责用户登录操作,还承担鉴权任务。当具体处理各个微服务时,我们需要通过token来解析用户的相关信息。在预处理阶段(preHandler),我们使用threadlocal来管理相关变量。随后,在所有的controller和service执行过程中,直接从threadlocal中获取用户的相关信息,并在完成后及时清理这些变量以避免内存占用问题。

11

springMVC相关面试话术

话术

1、介绍一下springMVC

作为一个视图层框架 springmvc 采用的是 mvc 模型,在实际应用中非常便捷地实现了接收与处理 request 和 response 的功能 这种架构设计使得开发团队能够更加高效地完成日常开发任务 在其内部结构中 springmvc 提供了多个关键组件共同构成了完整的功能模块

它的核心组件是DispatcherServlet,在接收用户的网络请求时会返回响应信息。它的功能相当于一个中间件或控制中枢,在协调整个处理流程的同时统一管理各组件间的交互关系,并通过减少各组件之间的依赖性来提升系统的可扩展性。

处理器映射器(HandlerMapping):该组件的作用是基于请求的URL路径,并通过注解或XML配置设置完成匹配。

还有就是处理器适配器(HandlerAdapter):其主要功能是通过映射器获取相关信息,并依据预先设定好的处理流程运行相关任务,并最终返回一个ModelAndView对象。

最后是视图解析器(ViewResolver):它负责执行解析操作,并且利用ModelAndView对象的View信息将逻辑视图名转换为真实的显示视图Name并返回给用户

接下来我给你说下springmvc的执行流程吧

2、springMVC的执行流程

(1)用户发送请求至前端控制器 DispatcherServlet;

(2)DispatcherServlet 处理请求时会利用 HandlerMapping 处理器映射器来完成请求处理以获取 Handle;

(3)处理器映射器依据请求 URL 定位具体处理器 并创建相应的处理器对象及拦截器(若有则同时创建)最终将它们一并返回给 DispatcherServlet

(4)DispatcherServlet 调用 HandlerAdapter 处理器适配器;

(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);

(6)Handler 执行完成返回 ModelAndView;

HandlerAdapter负责将Handler处理后的结果传递给DispatcherServlet

DispatcherServlet 负责将 ViewModel 传递给 ViewResolver 完成解析;

(9)ViewResolver 解析后返回具体 View;

(10)DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)

(11)DispatcherServlet 响应用户。

3、springMVC接收前台参数的几种方式

当进行数据传递时:

  • 如果采用ur1拼接方法,则可以直接通过目标接收;
  • 同样支持string和int两种类型;
  • 当向后端发送数据时:
    • 如果是js对象形式,则需附加@requestBody标记;
    • 必须确保目标中至少包含一个字段;
    • 并且所有指定的数据项都存在于目标结构中;
  • 对于get请求方式而言,在处理数据时可以选择普通对象或字符串/整数类型;
  • 当采用form表单提交数据时,在处理接受的数据类型上同样可以选择普通对象或字符串/整数类型;
  • springMVC中的常用注解包括:@PathVariable, @RequestBody, @RequestEntity, @ResponseMessage等

@RequestMapping:表示暴露于网络中的资源实体及其操作途径;通过@method字段参数来标识 HTTP 方法类型

@GetMapping、@PostMapping:规定了请求方式的方法的请求路径

@RequestParam:接收单一参数的

@PathVariable:用于从路径中接收参数的

@CookieValue:用于从cookie中接收参数的

@RequestBody:用于接收js对象的,将js对象转换为Java对象

@ResponseBody:返回json格式数据

该注解用于部署在类上,在前后端分离架构中常与@ResourceBody结合使用,在前端框架较少直接引用该注解时通常作为接口部署并频繁使用,在此类场景下通常表明该类将返回所有数据以JSON格式呈现。

等等

5、spring如何整合springMVC

简而言之,在SSM框架中SpringMVC实现了技术整合的方式就是在web.xml文件中设置核心控制器DispatcherServlet;这种设计能够对指定类型请求进行拦截;随后,在springMVC.xml文件中设置扫描器功能以便识别并包含带@controller注解的对象类;如今,在SSM框架中,默认采用注解式开发方式;其中不仅包括基本的控制类如@Service、@Repository、@Repository等;还包括更复杂的控制结构如AOP面向切面编程中的@Aspect;另外还会根据需求设置响应体映射信息以实现特定业务逻辑;除此之外还需要配置视图解析器以协调处理后的跳转功能;其中包括设定页面路径前缀和文件扩展名等内容;同时为了满足上传需求还需要进行multipart数据格式的参数配置如单个上传文件的最大体积限制以及每日最大上传量限制等。

12

mybatis相关面试话术

1、介绍一下mybatis,说一下它的优点和缺点是什么?

Mybatis is a semi-ORM (Object-Relational Mapping) framework for managing persistence, integrating JDBC seamlessly into the development process so that developers can focus solely on SQL statements without worrying about drivers, connections, or statement creation. It allows for the direct execution of native SQL operations without requiring traditional SQL code writing.

优点:

采用基于SQL语句的编程方法具有很高的灵活性,并未对应用程序或数据库原有设计架构产生任何改变。将所有SQL指令存储于XML格式中实现了对SQL指令与程序代码之间耦合关系的有效解除了,并提供了一套基于XML的标准标签体系以实现功能目标。该系统不仅支持编写动态生成的SQL语句,并允许对生成的 SQL 语句进行重用以提高开发效率

2:很好的与各种数据库兼容;

支持对象与数据库ORM字段的关系映射功能实现,并提供对象关系映射标签的支持;同时能够对对象关系组件进行维护。

相较于JDBC来说,本系统去除了冗余代码;无需手动开启连接;能够很好地与Spring框架集成。

缺点:

编写SQL语句是一项具有较高复杂性的任务;尤其是在涉及大量字段和关系表的情况下(即关联表较多时),开发人员需具备相应的技能。

2:SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库;

2、MyBatis与Hibernate有哪些不同?

首先Hibernate属于完全面向对象的持久层框架,MyBatis属于部分自动化处理的持久层框架.

在开发方面,Hibernate提供了封装好的SQL语句,在使用时可以直接调用,并显著提高了系统的开发效率。而Mybatis则属于半自动化工具,在操作SQL时仍需手动编写代码。面对大型复杂的项目时,在处理大规模数据查询需求上可能不如PostgreSQL等数据库高效,并且复杂的SQL语句较多。因此,在处理大型复杂项目时选择Hibernate可能不是一个理想的选择。

在SQL优化方面:Hibernate自动生成SQL,在某些情况下会产生较为繁琐的语句,这可能会导致性能消耗增加;而Mybatis则需要手动编写SQL,在一定程度上能够避免不必要的查询操作,并从而提升系统运行效率。

对象管理方面:Hibernate 是一个全面的对象-关系映射框架,在开发过程中无需过分关注底层细节;只需专注于对象管理和业务逻辑设计即可;而 Mybatis 则需要独立配置其特定的映射关系以实现数据层对接。

在Hibernate的应用场景下,二级缓存参数设置首先通过SessionFactory生成相应的配置文件完成详细设定,并且接着,在具体的表-对象映射关系中指定对应的缓存类型。对于MyBatis而言,二级缓存参数设置则是在每个单独的表与对象映射关系中分别进行细致的参数调整。这样做的好处是可以根据不同表的特点和需求灵活设置各自的缓存策略。

总体来说:Mybatis 精巧、便捷(易于使用)、高效(快速运行)、简单明了(无需复杂的配置)、直接高效(提供良好的性能),部分自动化;Hibernate 功能强大(支持复杂的业务需求),高度可靠(稳定性高)、非自动化的部分实现

3、#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。

Mybatis在处理参数引用时, 会将sql中的参数引用替换成?号, 使用PreparedStatement的set方法来赋值;

Mybatis在处理{}时,就是把{}替换成变量的值。

使用#{}可以有效的防止SQL注入,提高系统安全性。

4、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

第一种方法:在查询的sql语句中对字段名进行别名为指定,并使其与实体类属性名称保持一致。

第二种方法:该方法基于建立字段与属性的一一对应关系

第三种方法:在实体类通过@Column注解也可以实现;

一般来说,在开发中会有一个XML映射文件,并为它创建对应的DAO接口。那么这个DAO接口的工作原理是什么呢?如果在这些方法的参数不同时是否能够实现重载?

在数据库开发中,Dao接口与Mapper接口之间存在对应关系。具体而言,在映射开发过程中:映射文件中的namespace字段名称对应着DAO或mapper类中的全限定名;而DAO或mapper类的方法名称则对应于映射文件中相应Mapper类中的Statement对象标识符;最后,在处理事务操作时,在DAO或mapper类方法内部所接收的所有参数将被转换为传递给数据库执行sql语句所需的参数集合,并将其作为输入传递给数据库执行sql语句所需的参数集合。

该Mappper接口并未提供对应的具体类。当调用该Mappper接口的方法时,在此过程中会将访问权限名称与方法名称连接生成唯一的键值。在Mybatis框架中,默认情况下每个