SpringMVC框架源码解析之三:手写一个简单的MVC框架

本文旨在通过手写一个名为YYMVC的简单MVC框架,深入理解SpringMVC的工作原理。框架实现包括前端控制器、请求映射注册、处理器、注解处理、视图接口和拦截器等核心组件。建议读者沿着框架启动和请求执行两条主线分析源码。测试部分使用了内嵌Tomcat进行。
摘要由CSDN通过智能技术生成

SpringMVC框架源码解析之三:手写一个简单的MVC框架

为了加上对SpringMVC的理解,本文通过手写一个简单的MVC框架,来直观的理解MVC的原理。

如下为MVC框架要支持的功能:

在这里插入图片描述

源码位于:https://gitee.com/cq-laozhou/spring-stack-source-code-analysis/tree/master/src/main/java/com/zyy/sc/analysis/yymvc

话不多说,直接进入主题。

YYMVC框架源码

建议读者按照两条线来分析源码:第一条线是看框架的启动过程,第二条线再看请求的执行过程。

对于YYMVC框架来说,启动过程(或者servlet初始化)集中在init()方法中。而请求的执行流程集中在doDispatch()方法中。

注意,YYMVC只支持JDK8及以上版本。

前端控制器

这儿直接贴出写完的代码,实际写代码的情况是,不断的修改和完善。

package com.zyy.sc.analysis.yymvc;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * Created by zhouyinyan on 2020/1/14.
 *
 * 前端控制器
 *
 */
@Slf4j
public class YYServlet extends HttpServlet {

    //Spring容器,提供直接注入外部的ApplicationContext,或者通过指定主配置类,自己新建一个ApplicationContext。
    private ApplicationContext context;

    //spring的主配置类,用于初始化spring容器
    private Class springConfigClass;

    //注册器
    private HandlerRegistry handlerRegistry = new DefaultHandlerRegistry();

    //urlPath工具
    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    //方法参数名称工具
    private ParameterNameDiscoverer parameterNameDiscoverer ;

    //拦截器列表
    private List<Interceptor>  interceptors = new ArrayList<>();

    /**
     * 初始化
     *  注册handler
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        //init spring context
        if(Objects.isNull(getContext())){
            Assert.notNull(springConfigClass, "请提供Spring的主配置类,或者注入Spring容器到YYServlet中");
            context = new AnnotationConfigApplicationContext(springConfigClass);
        }

				//找出容器中所有的bean名称,然后看是否有@Controller注解,如果有的话,从它的所有方法中找出有@ReqMapping注解的方法,然后封装为Handler,注册到handlerRegistry上。
        //register handlers
        String[] allBeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class);
        Arrays.stream(allBeanNames).forEach(beanName -> {
            Class<?> type = context.getType(beanName);
            if(Objects.nonNull(type) && isHandler(type)){
                detectHandler(beanName);
            }
        });

//        parameterNameDiscoverer = context.getBean(ParameterNameDiscoverer.class);
        if(Objects.isNull(parameterNameDiscoverer)){
            parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        }

        //init interceptors
        String[] interceptorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Interceptor.class);
        Arrays.stream(interceptorNames).forEach(name -> {
            interceptors.add(context.getBean(name, Interceptor.class));
        });

    }

    /**
     * 找出给出bean的所有方法,如果有ReqMapping注解,这注册url和handler到handlerRegistry中。
     * @param beanName
     */
    private void detectHandler(String beanName) {
        Class<?> type = context.getType(beanName);
				//借用MethodIntrospector.selectMethods方法(这个方法是个模板方法
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值