Java 后端开后端开发面面试题——附校招附校招简历(春(春
招)招)
@[toc]
说明:明:
这份份 Java 后端开后端开发面面试题是是 ChatGPT 根据我的校招根据我的校招简历自自动生成的有生成的有针对性的高性的高频面面试
题,分,分为项目目经验考察和考察和专业技能考察两部分。技能考察两部分。
第一章第一章 项目目经验
一、一、OpenAI 大模型大模型应用服用服务体系体系
同学你好,你做的这个项目我非常感兴趣,我们公司也有这样的 OpenAI 业务对接,正好可以结
合你做的这个《OpenAI 大模型项目》聊一下。
1、你的、你的这个个项目的背景和需求来自哪里?目的背景和需求来自哪里?
校招身份校招身份举例例
答案:答案: 面试官您好,此项目的最核心背景和诉求,是我希望找到一个可以真实锻炼技术应用的
场景。并且可以基于此项目的设计、开发、上线、运维等一系列动作,提高编程思维和落地能
力。而此项目的只是一个载体,在项目中我所运用到的微信对接、登录鉴权、异步接口、下单支
付、异步发货、账户管理等场景可以运用到其他任何一个项目中使用。所以我选择开发 这样一
个项目。
并且此项目运用了 DDD 分层架构,领域驱动设计实现,对于各个场景都遵守了设计原则和设计
模式,解决各类复杂场景的实现。如;生成式服务流程中运用模板模式、策略模式、工厂模式,
解决对话过程中所需的规则过滤、模型校验、账户状态、账户扣减等开发流程。【项目提问过程
中,有时候会让绘制下项目的分层结构、核心流程,之后会基于你画的这些进行提问】。
通过以上项目的学习我锻炼到了相关项目所用到的核心技术使用,架构设计和落地实现。而此项
目的学习,也为我以后在工作中解决实际场问题,打下了牢固的基础。
2、、项目目为什么使用什么使用 DDD 架构,有什么好架构,有什么好处??
答案:答案: 首先是 DDD 的结构分层更加清晰(DDD 是一种软件设计方法,软件设计方法涵盖了范
式、模型、框架、方法论),与 MVC 相比避免了 PO、VO 对象被乱用的可能。而这也是在
DDD 中将行为和逻辑封装到一个领域内进行处理,也就是常说的充血模型结构。这样的结构方
式,就可以更好的做到业务流程松耦合,功能实现高内聚。
那么在这个 OpenAI 项目中,按照业务流程涵盖了 鉴权登录 、 OpenAI 、 下单 、 微信 ,4 个大的
核心场景。这 4 个核心场景恰好是 4 个领域,每个领域可以独立开发设计,再通过上层进行编
排使用。如果是小项目直接由 trigger 触发器层的进行编排,如果是较大型复杂项目可以增加
case 编排层,再由 trigger 层调用。【层之间是防腐,防腐避免了对象和服务被污染】。
相对比与 MVC 结构,这样的架构设计,不会因为引入更多的功能,系统的复杂度也随之提高。
因为所有的流程都被拆解了,每个功能都聚合到自己的领域内,这样的复杂度不会增加,并且也
更好维护。
3、充血模型和、充血模型和贫血模型分血模型分别合适什么合适什么场景?景?
答案:答案: 在 DDD 架构中,充血模型,主要的价值在于解决具有生命周期的流程。如生成式对话、
商品下单支付、用户登录授权等流程。因为这些流程中具有较复杂的场景模型和唯一 ID,所以
采用充血模型结构,会很适合的将状态和行为封装到同一的领域包中进行聚合开发实现。这样的
实现方式,也为以后扩展、迭代、维护做了良好的基建,避免工程过于腐化。——
注意关于 DDD 的知识,可以把这里的 5 个视频都刷下。 https://bugstack.cn/md/road-map/mvc.html
而贫血模型则比较适合 Querys 场景,因为这些场景只是数据的汇总查询,没有唯一 ID 和生命
周期。所以比较适合在工程中提供 query 模块,使用贫血模型开发。
4、、项目开目开发中你是怎么提交代中你是怎么提交代码的?的?
答案:答案: 首先我是在自己的 Gitcode 仓库中创建了一个空的项目地址,之后复制项目地址
https://github.com/MYXHcode/chatgpt-data 。在本地创建 OpenAI SpringBoot 工程,以及工程
中 app、domain、infrastructure、trigger、types 5 个 modules 模块。在之后在 idea 点开 Git
菜单创建本地仓库,再把仓库中需要提交的内容右键 Add 添加。最后 Ctrl + Shift + K 推送代
码,推送时配置复制的 git 地址。
这个过程中我会注意不要把一些本地文件如 .idea 、 编译文件 等提交上去,这些文件可以添加
到 .gitignore 文件中忽略提交。后续的开发中,会按照 时间-姓名-功能 的规范拉取开发分支,
编写代码和提交。开发验证完毕后合并 master 分支进行部署。【如果多人开发,可以把开发分
支合并到 test 分支进行部署测试】。
5、、这个个项目有部署上目有部署上线吗?怎么部署的,部署后内存占用如何,?怎么部署的,部署后内存占用如何,请描述下。描述下。
答案:答案: 项目上线了,并且对项目部署了 Prometheus + Grafana 监控组件,以及配置了前端百度
统计 PV、UV。部署的方式是先购买了一台 2c4g 5M 带宽的云服务器以及申请备案了域名,之
后在前后端应用配置 Dockerfile 打包镜像推送到 DockerHub,之后编写 docker compose 含环
境(MySQL、Redis 等)脚本,在云服务器执行部署的。因为本项目的登录采用了公众号登
录,所以在部署后把服务端接口地址,配置到公众号控制台进行验签和接收验证码登录。
整个项目部署完成后,占用了 53%~61%的服务器内存,Tomcat 配置了最大连接数是 250,
OpenAI 调用接口熔断为 6 秒【OpenAi 有时候会有超时】,同时在前端也配置了 50 秒主动断
开。压测过接口的响应,按照目前的服务器可以压测到 50 ~ 80 TPS【随着不同的文本量提问,
会有波动。OpenAI 响应有时候会需要 7-10 秒完成】,日常测试接口响应平均值在 3~10 秒。
—— 这些数据来自于压测后 Grafana 监控的展示【星球内提供了 Grafana 监控配置面板】。
这里为什么后端有超时熔断,前端也加了 50 秒超时主动断开。因为 OpenAI 接口的响应是
ResponseBodyEmitter 异步应答,当返回一个数据块以后,代表已经有响应,则不会计算服务
端的超时。但第一次应答后,后面的数据如果卡主了,仍可能一直无应答。所以前端加上主动超
时断开会更稳妥。【一般情况下,1~5 秒,服务端开始应答】。
6、你的、你的项目目对接了哪些接了哪些 OpenAI?怎么?怎么对接的?接的?
答案:答案: 在项目的开发阶段对接了 ChatGPT 和国内智谱 AI ChatGLM,两款 AI 产品,都有文生
文、文生图、多模态的图文理解等功能。对接的方式是采用会话模型(MyBatis Session)流
程,使用 retrofit2 + OkHttp3 框架,封装 OpenAI HTTP 接口。提供统一的出入参,并使用工厂
模式,构建 OpenAI 启动阶段所需的验证、日志、执行流程。并最终对外提供 OpenAI 会话服
务。
星球大模型项目的 OpenAI SDK 提供了两种,一种是独立的 ChatGPT-SDK-Java、ChatGLM-
SDK-Java,以及一个综合的 OpenAI-SDK-Java 对接了国内外 90%的大模型。这里你可以按照
自己的学习积累程度来描述。此外这些 SDK 也已经发布到了 Maven 中央仓库,外部人员也可
以使用【有不少伙伴参与了 SDK 开发,你也可以讲自己参与了一起开发或者是你独立内部开发
的】。
7、因、因为你的你的项目是前后端分离的,接口跨域怎么做的?目是前后端分离的,接口跨域怎么做的?
答案:答案: 首先我们知道,Web 跨域(Cross-Origin Resource Sharing,CORS)是一种安全机
制,用于限制一个域下的文档或脚本如何与另一个源的资源进行交互。这是一个由浏览器强制执
行的安全特性,旨在防止恶意网站读取或修改另一个网站的数据,这种攻击通常被称为“跨站点
脚本”(Cross-Site Scripting,XSS)。
所以在我的前后端分离项目中,通过配置 @CrossOrigin 注解来解决跨越问题。开发阶段
Access-Control-Allow-Origin: \* 、上线阶段 Access-Control-Allow-Origin : https://myxh-
chatqpt.site
8、、请描述下商品下描述下商品下单支付支付场景。以及怎么保景。以及怎么保证的的补偿。。
答案:答案: 下单支付场景在整个项目中是一块非常核心的流程,首先是系统设计采用了 DDD 架构,
对商品下单按照业务流程拆解出来了单独的领域模块。在设计实现上,以购物车为下单入参的实
体对象,出参为支付单实体。保存的是订单的聚合信息。
因为本身下单是一个较为复杂的流程,所以在编码实现上采用了模板模式,定义出下单的标准过
程。商品下单的流程需要先查询是否存在 已下单未支付 和 已下单但无支付单 的订单,对这样两种
订单分别进行处理。已下单未支付,在有效期内未关单的直接返回给用户直接支付。已下单但无
支付单则调用(微信/支付宝沙箱/蓝兔)创建支付订单,保存库表记录后返回给前端用户进行支
付。此外的流程则直接执行购物车商品 ID 查询,组装聚合订单数据,创建支付单,保存库表记
录和返回给用户。在用户支付完成后,接收支付回调消息,推送(MQ/Redis 发布订阅/Guava
事件)信息,由系统中 trigger 模块下的监听处理接收支付成功消息,完成商品的发货处理。
那么这里可能发生的调单情况,接收回调消息处理失败。则由定时任务扫描库表订单超过 15 分
钟未支付的订单,查询支付平台(微信/支付宝沙箱/蓝兔)是否已支付,如果支付则发送事件消
息走后续的补货流程。另外如果超过 15 分钟以上未支付则进行本地关单,不对支付平台关单
(支付平台有自己的时间),这样可以让用户的体验更加舒服。用户超时后支付,仍可以走后续
的发货流程。但如果用户刷新界面,则获取创建新的支付单。
9、你的、你的订单表也是一个表也是一个频繁使用的表,那么繁使用的表,那么库表有哪些核心字段,索引有哪表有哪些核心字段,索引有哪
些?些?
答案:答案: 有用户 ID(用的公众号创建的 openid)、商品 ID、商品名称、商品金额、订单 ID、下
单时间、订单状态、支付单类型(微信、支付宝)、支付单号、支付时间、交易单号、交易状态
等。表中对订单 ID、用户唯一创建了唯一索引,对订单状态和订单时间创建组合索引(提高扫
描效率)。
10、我看到、我看到 OpenAI 的体的体验,都是,都是渐进式展示的,式展示的,这块后端使用了什么接口后端使用了什么接口
形式?形式?
答案:答案: 这部分是使用 SpringBoot 应用提供的 HTTP 接口,返回的是 ResponseBodyEmitter 异
步请求处理协议。它是 SpringMVC 所提供的一个异步响应提,当你控制器中返回一个
ResponseBodyEmitter 实例时,Spring MVC 会开启一个异步请求处理,这样就可以在单个请求
中发送多个 OpenAI 应答数据块。这样的应答方式是非常适合 OpenAI 这样需要大批量应答数据
的场景。此外因为服务端的接口需要 Nginx 转发,所以在 Nginx 端还需要关闭分块解码
(chunked_transfer_encoding)、关闭转发缓冲(proxy_buffering)、关闭应答缓存
(proxy_cache),这样最终才能是一个渐进式的展示效果。
11、你的、你的项目中目中对接了接了 ChatGPT 和和 ChatGLM 两个模型,那么使用了什么两个模型,那么使用了什么
设计模式?模式?
答案:答案: 关于 ChatGPT、ChatGLM 两个 OpenAI 服务,在项目中定义了一个通信渠道策略接
口,接口方法返回统一的格式数据。两款 OpenAI 服务分别实现自己接口处理。之后两个实现的
策略模式注入到 Map 中,Key 是一个枚举值。当前端选择不同的模型进行问答时,则根据模型
的枚举值从 Map 中选择出对应的策略处理类。这样即使后续拓展其他的 OpenAI 服务也非常容
易扩展。
12、你在、你在项目中有支付目中有支付购买的次数,那么的次数,那么对应就会有就会有额度扣减、度扣减、账户的校的校
验、、还有模型的使用有模型的使用类型,型,这些是怎么些是怎么实现的?的?
答案:答案: 其实除了账户、额度、模型,还有敏感词过滤,在这部分实现中我定义了统一的
ILogicFilter 过滤接口,分别实现不同的过滤诉求。在通过工厂的封装,装配上不同的过滤规则
类。用户进行问答后,会对用户的信息分别进行校验。这部分也就是整体 OpenAI 应答中使用的
模板、工厂、策略三个设计模式。另外像是这样的调用验证方式,也可以使用责任链的方式处
理。
之后这里在说下敏感词,敏感词对接了通用的敏感词库,但校验的过于严格同时不是动态的,所
以可能不准。后来又对接了云服务厂商的敏感词过滤服务+图片审核服务。可以配置广告、舆
情、敏感类等都可以配置过滤。
13、你是怎么、你是怎么处理异常的?理异常的?
答案:答案: 项目中在对接 OpenAI 接口、数据库、缓存、下单调用等,是有可能出现超时、数据接
口更新、数据库连接、缓存数据问题等异常,这些异常属于功能异常。是在每个领域模型内可能
发生的问题情况。为了让异常保持统一,具备业务语意,所以在 types 层了定义业务异常类