程序员社区

动手撸一个 mvc 框架3


title: 动手撸一个 mvc 框架3
date: 2020/04/24 15:44


本节内容

继续上节,将找到 RequestMapping 对象并执行整个流程进行实现

请求来了

1、FrameworkServlet 对请求进行的处理

重写了父类的 doGet 和 doPost 方法,将其共同引向一个方法

// ------> 请求来了

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doGet(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doPost(req, resp);
}

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) {

    // 准备一些环境(本地化、异步、还有一个什么参数不知道干啥用的)


    // 调用处理方法
    this.doService(request, response);

    // 触发一个事件
}


protected abstract void doService(HttpServletRequest request, HttpServletResponse response);

2、DispatcherServlet 实现 doService 方法

public class DispatcherServlet extends FrameworkServlet {

    // 处理器映射器集合
    private List<HandlerMapping> handlerMappings;

    /**
     * This implementation calls {@link #initStrategies}.
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * 初始化此servlet使用的策略对象。
     */
    protected void initStrategies(ApplicationContext context) {
//        initMultipartResolver(context);
//        initLocaleResolver(context);
//        initThemeResolver(context);

        // 初始化处理器映射器,通过处理器映射器找到对应的方法进行执行
        this.initHandlerMappings(context);
//        initHandlerAdapters(context);
//        initHandlerExceptionResolvers(context);
//        initRequestToViewNameTranslator(context);
//        initViewResolvers(context);
//        initFlashMapManager(context);
    }

    private void initHandlerMappings(ApplicationContext context) {
        String[] bdNames = context.getBeanDefinitionNames(HandlerMapping.class);
        this.handlerMappings = Arrays.stream(bdNames)
                .map(beanName -> context.getBean(beanName, HandlerMapping.class))
                .collect(Collectors.toList());
    }

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) {

    }

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
        HandlerExecutionChain mappedHandler = this.getHandler(request);
        if (mappedHandler == null || mappedHandler.getHandler() == null) {
            return;
        }
    }

    /**
     * 根据请求获取【处理链】
     */
    private HandlerExecutionChain getHandler(HttpServletRequest request) {
        for (HandlerMapping handlerMapping : handlerMappings) {
            HandlerExecutionChain handler = handlerMapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }

        return null;
    }

}

HandlerExecutionChain

public class HandlerExecutionChain {

    private final Object handler;

    public HandlerExecutionChain(Object handler) {
        this.handler = handler;
    }

    public Object getHandler() {
        return handler;
    }
}

3、RequestMappingHandlerMapping#getHandler()

public abstract class AbstractHandlerMapping implements HandlerMapping {
    /**
     * 返回此请求的处理程序和所有拦截器。可以根据请求URL,会话状态或实现类选择的任何因素进行选择。
     */
    @Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) {

        // 根据请求获取处理程序
        Object handler = this.getHandlerInternal(request);
        if (handler == null) {
            return null;
        }

        // 如果是实现了 Controller 接口的情况,则从 bf 中取出
        // if (handler instanceof String) {
        //     String handlerName = (String) handler;
        //     handler = getApplicationContext().getBean(handlerName);
        // }

        // 这个地方和拦截器有关
//        return this.getHandlerExecutionChain(handler, request);
        return null;
    }

    /**
     * 查找给定请求的处理程序,如果未找到特定请求,则返回 null。
     */
    protected abstract Object getHandlerInternal(HttpServletRequest request);
}

RequestMappingHandlerMapping 的实现

/**
 * 查找给定请求的处理程序,如果未找到特定请求,则返回 null。
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) {
    List<Match> matches = new ArrayList<>();

    String lookupPath = request.getRequestURI();
    List<RequestMappingInfo> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    // 如果找到匹配的了,就进行校验,看看是否符合当前请求
    if (directPathMatches != null) {
        this.addMatchingMappings(directPathMatches, matches, request);
    }
    // 如果没有找到合适的,说明可能是 @PathVariable 的情况,则把所有的 RequestMappingInfo 交给它进行寻找匹配的。
    if (matches.isEmpty()) {
        this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    // 如果匹配的不为空,则取出第一个将它的 handlerMethod 进行返回
    if (CollUtil.isNotEmpty(matches)) {
        Match bestMatch = matches.get(0);
        return bestMatch.handlerMethod;
    }

    throw new RuntimeException("没有为当前请求找到处理器!");
}

/**
    * 对请求方法、请求路径(包括 @PathVariable)【@RequestMapping 相关的内容】进行校验
    */
private void addMatchingMappings(Collection<RequestMappingInfo> mappingInfos, List<Match> matches, HttpServletRequest request) {
    for (RequestMappingInfo mappingInfo : mappingInfos) {
        RequestMappingInfo info = mappingInfo.getMatchingCondition(request);
        if (ObjectUtil.isNotNull(info)) {
            matches.add(new Match(info, this.mappingRegistry.getMappings().get(mappingInfo)));
        }
    }
}

private static class Match {

    private final RequestMappingInfo mapping;

    private final HandlerMethod handlerMethod;

    public Match(RequestMappingInfo mapping, HandlerMethod handlerMethod) {
        this.mapping = mapping;
        this.handlerMethod = handlerMethod;
    }

    @Override
    public String toString() {
        return this.mapping.toString();
    }
}
赞(0) 打赏
未经允许不得转载:IDEA激活码 » 动手撸一个 mvc 框架3

一个分享Java & Python知识的社区