SpringMVC 源码分析 以及手写简单的SpringMVC框架

发布于:2022-12-21 ⋅ 阅读:(421) ⋅ 点赞:(0)

什么是Spring MVC

简单而言,Spring MVC是Spring在Spring Container Core和AOP等技术基础上,遵循上述Web MVC的规范推出的web开发框架,目的是为了简化Java栈的web开发。@pdai

        简单来说,Spring Web MVC 是一种基于Java 的实现了Web MVC 设计模式的请求驱动类型的轻量级Web 框架,即使用了MVC 架 构模式的思想,将 web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开 发,Spring Web MVC 也是要简化我们日常Web 开发的。

一、Spring MVC的请求流程

Spring Web MVC 框架也是一个基于请求驱动的Web 框架,并且也使用了前端控制器模式来进行设计,再根据请求映射 规则分发给相应的页面控制器(动作/处理器)进行处理。

核心架构的具体流程步骤

  1. 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为 HandlerExecutionChain 对象(包含一 个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新 的映射策略;
  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器, 即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处 理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
  5. ModelAndView 的逻辑视图名——> ViewResolver,ViewResolver 将把逻辑视图名解析为具体的View,通过这种策 略模式,很容易更换其他视图技术;
  6. View——>渲染,View 会根据传进来的Model 模型数据进行渲染,此处的Model 实际是一个Map 数据结构,因此 很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet,由DispatcherServlet 返回响应给用户,到此一个流程结束。

二、自实现 SpringMVC

上文已经认识到SpringMvc核心业务逻辑,所以按照此思路,我们依次来实现自己的SpringMvc的DispatcherServlet、HandlerMapping、HandlerAdapter,实现简单的mvc框架

1、项目准备

新建一个新的web项目

 依赖准备

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
    </dependencies>

 配置文件

 web.xml文件

 spring-servlet.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.qiu"/>

    <bean id="/helloServlet" class="com.qiu.springmvc.demo.HelloServlet"/>

</beans>

2、请求处理映射器 HandlerMapping

首先通常的 request请求有多种形式,常见的有以下两种:

a、@Controller注解

 b、自定义的Servlet,通过注册到spring容器,由依赖注入使用。

 所以,我们至少定义两种处理器

public interface HandlerMapping extends InstantiationAwareBeanPostProcessor {
    Object getHandler(String url);
}

这里继承InstantiationAwareBeanPostProcessor,是为了实现 postProcessAfterInstantiation

 这样一来,对象一旦初始化完成,我们就能够将对应的请求对象,加载到各自对应的处理器的Map中,等待后续处理请求。

BeanHandlerMapping

@Component
public class BeanHandlerMapping implements HandlerMapping {

    private static Map<String, Object> map = new HashMap<>();

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.startsWith("/")) {
            map.put(beanName, bean);
        }
        return HandlerMapping.super.postProcessAfterInstantiation(bean, beanName);
    }

    @Override
    public Object getHandler(String url) {
        return map.get(url);
    }
}

 AnnotationHandlerMapping 

通过注解的方式,会有很多很多的方法,这些方法对应一个个请求。因此,为了方便处理,我们自定义一个封装对象 RequestMappingInfo 。

public class RequestMappingInfo {
    private Object object;
    private Method method;
    private String url;

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
@Component
public class AnnotationHandlerMapping implements HandlerMapping {

    private static Map<String, RequestMappingInfo> map = new HashMap<>();

    @Override
    public Object getHandler(String url) {
        return map.get(url);
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        Method[] methods = bean.getClass().getDeclaredMethods();
        for (Method method : methods) {
            RequestMappingInfo info = createRequestMappingInfo(bean, method);
            map.put(info.getUrl(),info);
        }
        return HandlerMapping.super.postProcessAfterInstantiation(bean, beanName);
    }

    private RequestMappingInfo createRequestMappingInfo(Object bean, Method method) {
        RequestMappingInfo info = new RequestMappingInfo();
        if (method.isAnnotationPresent(RequestMapping.class)) {
            info.setMethod(method);
            info.setObject(bean);
            info.setUrl(method.getAnnotation(RequestMapping.class).value());
        }
        return info;
    }
}

 3、处理适配器 HandlerAdapter 

获取到了对应的处理器,但是不同处理器,处理方式也不一样。基于封装的思想,我们要定义适配器类,适配各类处理器实现方式。

public interface HandlerAdapter {
    public boolean support(Object handler);

    public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

 ServletHandlerAdapter 

@Component
public class ServletHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean support(Object handler) {
        return handler instanceof Servlet;
    }

    @Override
    public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ((Servlet) handler).service(request, response);
        return null;
    }
}

 AnnotationHandlerAdapter 

@Component
public class AnnotationHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean support(Object handler) {
        return handler instanceof RequestMappingInfo;
    }

    @Override
    public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String, String[]> parameterMap = request.getParameterMap(); //获取请求参数列表
        RequestMappingInfo info = (RequestMappingInfo) handler; //具体方法、url、对象
        Parameter[] parameters = info.getMethod().getParameters(); //具体方法所需参数
        Object[] paramsValue = new Object[parameters.length]; 
        int index = 0;
        for (Parameter parameter : parameters) {
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                if (parameter.getDeclaredAnnotation(RequestParam.class).value().equals(entry.getKey())) {
                    paramsValue[index++] = entry.getValue()[0];
                }
            }
        }
        //通过反射,执行方法
        return info.getMethod().invoke(info.getObject(), paramsValue);
    }
}

4、自定义注解

@RequestMapping

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    String value() default "";
}

@RequestParam 

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestParam {
    String value() default "";

}

5、DispatcherServlet(核心)

先贴代码,下图讲实现思路

@Component
public class Servlet extends HttpServlet {

    private String contextConfiguration;

    private Collection<HandlerMapping> handlerMappings;
    private Collection<HandlerAdapter> handlerAdapters;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object handler = getHandlerMapping(req);
        if (handler == null) {
            resp.setStatus(404);
            return;
        }
        HandlerAdapter adapter = getAdapterHandler(handler);
        Object result = null;
        PrintWriter writer = resp.getWriter();
        try {
            result = adapter.handle(req, resp, handler);
        } catch (Exception e) {
            e.printStackTrace();
            resp.setStatus(500);
        }
        writer.println(result);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config.getInitParameter("contextConfiguration"));
        Map<String, HandlerMapping> beans = context.getBeansOfType(HandlerMapping.class);
        Map<String, HandlerAdapter> adapterMap = context.getBeansOfType(HandlerAdapter.class);
        handlerMappings = beans.values();
        handlerAdapters = adapterMap.values();
    }

    private Object getHandlerMapping(HttpServletRequest request) {
        String contextPath = request.getContextPath(); //获取上下文路径
        Object target = null;
        if (handlerMappings != null) {
            for (HandlerMapping mapping : handlerMappings) {
                System.out.println("request-path:" + request.getRequestURI().substring(contextPath.length()));
                target = mapping.getHandler(request.getRequestURI().substring(contextPath.length()));
                if (target != null) {
                    return target;
                }
            }
        }
        return target;
    }

    private HandlerAdapter getAdapterHandler(Object handler) {
        if (handlerAdapters != null) {
            for (HandlerAdapter handlerAdapter : handlerAdapters) {
                boolean flag = handlerAdapter.support(handler);
                System.out.println(flag);
                if (flag) {
                    return handlerAdapter;
                }
            }
        }
        return null;
    }
}

 首先获取到映射器和处理器

 Servlet的生命周期,init初始化方法中,加载出spring容器,加载对应的数据。spring配置文件路径来自上文的web.xml文件中。

 接下来

 

 返回结果

 6、测试请求类

以上已经完成基本框架,接下来编写两种请求类

  • 自定义的Servlet:
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("...........helloServlet");
        PrintWriter writer= resp.getWriter();
        writer.println("...........helloServlet");
    }

}
  • 基于注解
@Controller
public class HelloController {

    @RequestMapping("/test")
    public String test() {
        System.out.println("............HelloController");
        return "test";
    }

    @RequestMapping("/test-name")
    public String test(@RequestParam("name") String name) {
        System.out.println("............HelloController >>>>>>" + name);
        return name == null ? "test-name" : "test-name:" + name;
    }

}

三、测试

1、基于注解

 2、Servlet

 OK!完结撒花……


SpringMvc - https://www.pdai.tech/md/spring/spring-x-framework-springmvc.html


网站公告

今日签到

点亮在社区的每一天
去签到