互联网架构-SpringMVC源码深度解析-030:完全高仿SpringMVC框架

1 纯手写SpringMVC框架代码演示

在这里插入图片描述

2 创建DispatcherServlet前端控制

引入maven依赖

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.0</version>
</dependency>

初始化DispatcherServlet

public class HttpServletBean extends HttpServlet {

    /**
     * SpringMVC思路:
     * 在项目启动时候定义好控制层和url映射关联存放到Map集合中
     * 1.扫包获取class中的方法,判断是否有加上@RequestMapping注解,如果有的话存放到map集合中
     * 2.key:url:value 方法
     * 访问请求,根据url查找对应的执行方法,再通过java反射执行。
     */

    @Override                                                       
    public void init() throws ServletException {
        // 初始化springmvc bean的对象,url与方法关联
        initServletBean();
    }

    protected void initServletBean() {
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)  {
        doService(req,resp);
    }

    protected void doService(HttpServletRequest req, HttpServletResponse resp) {
    }
}
public class FrameworkServlet extends HttpServletBean{

    @Override
    protected void initServletBean() {
        onRefresh();
    }

    protected void onRefresh() {
    }

    @Override
    protected void doService(HttpServletRequest req, HttpServletResponse resp) {

    }
}
public class DispatcherServlet extends FrameworkServlet {
    @Override
    protected void onRefresh() {
        initStrategies();
    }

    private void initStrategies() {
        System.out.println("DispatcherServlet容器开始初始化了!");
    }

    @Override
    protected void doService(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("蚂蚁课堂 666");
    }
}

3 创建ServletContainerInitializer

注册DispatcherServlet到Servlet容器中
Resource目录下创建META-INF/services/javax.servlet.ServletContainerInitializer文件
内容:com.mayikt.servlet.web.SpringServletContainerInitializer

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

    /**
     * onStartup servlet容器初始化的时候调用该方法
     *
     * @param classInfos     获取WebApplicationInitializer所有子类信息
     * @param servletContext
     * @throws ServletException
     */
    public void onStartup(Set<Class<?>> classInfos, ServletContext servletContext) throws ServletException {
        for (Class<?> classInfo : classInfos) {
            // classInfo都是WebApplicationInitializer类的子类
            try {
                Method method = classInfo.getMethod("onStartup", ServletContext.class);
                Object object = classInfo.newInstance();
                method.invoke(object, servletContext);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
public interface WebApplicationInitializer {
    void onStartup(ServletContext servletContext) throws ServletException;
}
public class AbstractDispatcherServletInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext servletContext) throws ServletException {
        // 1.开始注册DispatcherServlet
        ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet", new DispatcherServlet());
        dispatcherServlet.addMapping("/"); // 拦截所有的请求
    }
}

断点启动tomcat
在这里插入图片描述

4 解决注册Servlet类不生效的原因

启动tomcat,注册Servlet类不生效,原因是web.xml配置冲突。
删除webapp/WEB-INF下面的三个xml文件。

断点启动tomcat:
在这里插入图片描述

5 HandlerMapping对象初始化

注解类

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

配置类

@ComponentScan("com.mayikt.controller")
public class SpringMvcConfig {
}

控制层

@Controller
public class PayController {
    
    @RequestMapping("/pay")
    public String pay() {
        return "pay";
    }
}

存放url映射对应的value

public class HandlerMethod {
    // 请求方法对应的bean对象
    private Object bean;
    private Method method;


    public HandlerMethod(Object bean, Method method) {
        this.bean = bean;
        this.method = method;
    }

    public Object getBean() {
        return bean;
    }

    public Method getMethod() {
        return method;
    }
}

RequestMappingHandlerMapping

public class RequestMappingHandlerMapping {

    // 初始化SpringMVC bean对象、url与方法关联存放到Map集合中
    private Map<String, HandlerMethod> registry = new HashMap<String, HandlerMethod>();

    public void initHandlerMappings() {
        ComponentScan componentScan = SpringMvcConfig.class.getDeclaredAnnotation(ComponentScan.class);
        String springMvcPackage = componentScan.value();
        if (StringUtils.isEmpty(springMvcPackage)) {
            return;
        }
        // 1.使用java反射机制,查找该包下com.mayikt.controller有哪些控制类
        Set<Class<?>> classes = ReflexUtils.getClasses(springMvcPackage);
        // 2.循环遍历每个类
        for (Class<?> classInfo : classes) {
            // 3.判断类上面是否有Controller注解
            Controller controller = classInfo.getDeclaredAnnotation(Controller.class);
            if (controller == null) {
                continue;
            }
            // 4.遍历控制层类中方法是否有加上RequestMapping注解
            Method[] declaredMethods = classInfo.getDeclaredMethods();
            for (Method method : declaredMethods) {
                RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
                if (requestMapping == null) {
                    continue;
                }
                String url = requestMapping.value();
                // 存放hashMap集合,key url,value Method
                registry.put(url, new HandlerMethod(newInstance(classInfo), method));
            }
        }
    }

    private Object newInstance(Class classInfo) {
        try {
            Object value = classInfo.newInstance();
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    public HandlerMethod getHandlerMethod(String url) {
        return registry.get(url);
    }

}

DispatcherServlet 初始化的时候装配RequestMappingHandlerMapping

public class DispatcherServlet extends FrameworkServlet {
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    public DispatcherServlet() {
        requestMappingHandlerMapping = new RequestMappingHandlerMapping();
    }

    @Override
    protected void onRefresh() {
        initStrategies();
    }

    private void initStrategies() {
        requestMappingHandlerMapping.initHandlerMappings();
    }

    @Override
    protected void doService(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("蚂蚁课堂 666");
    }
}

6 纯手写SpringMVC执行流程01

HandlerExecutionChain

public class HandlerExecutionChain {

    HandlerMethod handlerMethod;
    // 拦截器

    public HandlerExecutionChain(HandlerMethod handlerMethod) {
        this.handlerMethod = handlerMethod;
    }

    public ModelAndView handler() throws InvocationTargetException, IllegalAccessException {
        // 1.使用java反射机制执行请求方法
        Method method = handlerMethod.getMethod();
        Object bean = handlerMethod.getBean();
        Object viewName = method.invoke(bean, null);
        ModelAndView modelAndView = new ModelAndView((String) viewName);
        return modelAndView;
    }
}

ModelAndView

public class ModelAndView {

    // 跳转页面名称
    private String viewName;

    public ModelAndView(String viewName) {
        this.viewName = viewName;
    }

    public String getViewName() {
        return viewName;
    }
}

DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    public DispatcherServlet() {
        requestMappingHandlerMapping = new RequestMappingHandlerMapping();
    }

    @Override
    protected void onRefresh() {
        initStrategies();
    }

    private void initStrategies() {
        requestMappingHandlerMapping.initHandlerMappings();
    }

    @Override
    protected void doService(HttpServletRequest req, HttpServletResponse resp) {
        doDispatch(req, resp);
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) {
        try {
            // 1.处理请求url
            String requestURI = req.getRequestURI();
            // 2.根据url查找对应的Handler
            HandlerExecutionChain handler = getHandler(requestURI);
            // 3.使用java的反射机制执行该方法,返回对应的ModelAndView
            ModelAndView modelAndView = handler.handler();
            // 4.开始渲染视图层
            render(modelAndView, req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private HandlerExecutionChain getHandler(String url) {
        HandlerMethod handlerMethod = requestMappingHandlerMapping.getHandlerMethod(url);
        if (handlerMethod == null) {
            return null;
        }
        HandlerExecutionChain handlerExecutionChain = new HandlerExecutionChain(handlerMethod);
        return handlerExecutionChain;
    }

    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        throw new Exception("没有查找到对应的请求");
    }

    public void render(ModelAndView modelAndView, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String viewName = modelAndView.getViewName();
        req.getRequestDispatcher("/WEB-INF/view/" + viewName + ".jsp").forward(req, resp);
    }
}

7 纯手写SpringMVC执行流程02

webapp/WEB-INF/view/pay.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
纯手写低配版springmvc 蚂蚁课堂666
</body>
</html>

运行测试:
在这里插入图片描述
断点调试流程:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值