阿里面试:看过框架源码吗?举例说明一下

前两天有朋友面试"淘汰集团",也就是"淘宝"+"天猫"的组合,最后被面试官问到了这道题:"你看过哪些开源框架的源码?举例说明一下"。

诚然,这是一道比较考验应聘者基本功的问题,也是很好区分"好学生"和"普通学生"的一道经典的开放性问题。

那这个问题应该怎么回答呢?

解答思路

我这给大家提供两个思路吧:

  1. 可以回答比较常见的,你比较熟悉的源码,例如 Spring Boot 收到请求之后,执行流程的源码。
  2. 还可以回答 Spring Cloud 微服务中,某个组件执行的流程源码,这样能很好的体现你对微服务比较熟悉,因为微服务在公司中应用比较广泛,所以回答的好,是一个极大的加分项。

1.Spring Boot 源码分析

Spring Boot 在收到请求之后,会先执行前端控制器 DispatcherServlet,并调用其父类 FrameworkServlet 中的 service 方法,其核心源码如下:

java 复制代码
/**
 * Override the parent class implementation in order to intercept PATCH requests.
 */
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
        processRequest(request, response);
    } else {
        super.service(request, response);
    }
}

继续往下看,processRequest 实现源码如下:

java 复制代码
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 // 省略一堆初始化配置
   
   try {
       // 真正执行逻辑的方法
       doService(request, response);
   }
   catch (ServletException | IOException ex) {
       ...
   }
}

doService 实现源码如下:

java 复制代码
protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;

doService 是抽象方法,由其之类 DispatcherServlet 来重写实现,其核心源码如下:

java 复制代码
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 省略初始化过程...
    try {
        doDispatch(request, response);
    }
    finally {
		// 省略其他...
    }
}

此时就进入到了 DispatcherServlet 中的 doDispatch 方法了:

java 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取原生请求
    HttpServletRequest processedRequest = request;
    // 获取Handler执行链
    HandlerExecutionChain mappedHandler = null;
    // 是否为文件上传请求, 默认为false
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
            // 检查是否为文件上传请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);
            // Determine handler for the current request.
            // 获取能处理此请求的Handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // Determine handler adapter for the current request.
            // 获取适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            // 执行拦截器(链)的前置处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 真正的执行对应方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        // 忽略其他...
}

通过上述的源码我们可以看到,请求的核心代码都在 doDispatch 中,他里面包含的主要执行流程有以下这些:

  1. 调用 HandlerExecutionChain 获取处理器:DispatcherServlet 首先调用 getHandler 方法,通过 HandlerMapping 获取请求对应的 HandlerExecutionChain 对象,包含了处理器方法和拦截器列表。
  2. 调用 HandlerAdapter 执行处理器方法:DispatcherServlet 使用 HandlerAdapter 来执行处理器方法。根据 HandlerExecutionChain 中的处理器方法类型不同,选择对应的 HandlerAdapter 进行处理。常用的适配器有 RequestMappingHandlerAdapter 和 HttpRequestHandlerAdapter。
  3. 解析请求参数:DispatcherServlet 调用 HandlerAdapter 的 handle 方法,解析请求参数,并将解析后的参数传递给处理器方法执行。
  4. 调用处理器方法:DispatcherServlet 通过反射机制调用处理器方法,执行业务逻辑。
  5. 处理拦截器:在调用处理器方法前后,DispatcherServlet 会调用拦截器的 preHandle 和 postHandle方法进行相应的处理。
  6. 渲染视图:处理器方法执行完成后,DispatcherServlet 会通过 ViewResolver 解析视图名称,找到对应的 View 对象,并将模型数据传递给 View 进行渲染。
  7. 生成响应:View 会将渲染后的视图内容生成响应数据。

2.Spring Cloud 源码

Spring Cloud 组件有很多,你可以挑一个源码实现比较简单的组件来讲,这里推荐 Spring Cloud LoadBalancer,因为其核心源码的实现比较简单。

Spring Cloud LoadBalancer 中内置了两种负载均衡策略:

  1. 轮询负载均衡策略
  2. 随机负载均衡策略

轮询负载均衡策略的核心实现源码如下:

java 复制代码
// ++i 去负数,得到一个正数值
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
// 正数值和服务实例个数取余 -> 实现轮询
ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
// 将实例返回给调用者
return new DefaultResponse(instance);

随机负载均衡策略的核心实现源码如下:

java 复制代码
// 通过 ThreadLocalRandom 获取一个随机数,最大值为服务实例的个数
int index = ThreadLocalRandom.current().nextInt(instances.size());
// 得到实例
ServiceInstance instance = (ServiceInstance)instances.get(index);
// 返回
return new DefaultResponse(instance);

小结

开源框架的源码在面试中经常会被问到,但只因如此,就去完整的看某个框架的源码,其实还是挺难的。第一,框架中的源码很多,很难一次性看懂。第二,即使能看懂,看完之后也会很快忘记(因为内容太多了)。此时,不如挑一些框架中的经典实现源码来看,其性价比更高,既能学到框架中的精髓,又能搞定面试,是一个不错的选择。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关推荐
曹牧7 分钟前
文档格式:OFD
java
豆角焖肉32 分钟前
Maven进阶与搭建私服
java·maven
大不点wow42 分钟前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
噢,我明白了1 小时前
Java中日期和字符串的处理
java·开发语言·日期
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot
jun_bai1 小时前
Orthanc服务器使用java上传dicom影像文件
java·运维·服务器