• 15.springmvc源码解读之手写springmvc(简易版本)


    springmvc大致原理

    课程标题《一节课纯手写springmvc框架》
    课程内容:
    1.springmvc底层原理实现
    2.dispatcherservlet原理
    3.springmvc底层工作流程
    4.一节课纯手写springmvc框架

    手写springmvc原理

    1.SpringIOC容器初始化时开始遍历所有的bean对象 判断 bean对象 类上是否有加上

    @Controller注解,如果类上有加该注解的话 则该类就是为我们控制类;

    2.在容器初始化时会建立所有url和controller的对应关系,利用java反射机制,查找该控制类中所有方法,判断方法上是否有加上@RequestMapping注解,如果有加上该注解的话 保存到Map中(key=/mayiktDemo01,MayiktController#mayiktDemo01())

    3.定义DispatcherServlet 接受客户端所有请求 从该map集合中查找到具体的控制类 方法 调用(java

    反射机制。)

    springmvc 请求处理流程

    所有请求过来先达到我们的DispatcherServlet 分发执行具体的方法

    springmvc 结合web.xml springmvc .xml

    1.自定义注解(标记哪些类是为控制类、url映射方法)

    思考:用户访问路径:/mayiktDemo01 如何查找到 MayiktController#mayiktDemo01();

    提前通过Map集合映射关系(key=/mayiktDemo01,MayiktController#mayiktDemo01())

    2.spring ioc容器加载完毕之后 开始遍历所有的bean对象 判断 bean对象 类上是否有加上

    MayiktController注解,如果类上有加该注解的话 则该类就是为我们控制类;

    3.利用java反射机制 查找该类中所有方法 判断方法上是否有加上@MayiktRequestMapping 如果

    有加上该注解的话 则 采用map集合存放URL映射的关系。

    4.定义DispatcherServlet 接受客户端所有请求 从该map集合中查找到具体的控制类 方法 调用(java

    反射机制。)

    import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;

    	protected void initHandlerMethods() {
            //从springioc容器中查找到所有的bean的名称
    		for (String beanName : getCandidateBeanNames()) {
    			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                    //根据bean的名称 从ioc容器中查找到具体的bean对象
    				processCandidateBean(beanName);
    			}
    		}
    		handlerMethodsInitialized(getHandlerMethods());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    Class<?> beanType = null;
    		try {
                // 从ioc容器查找到该对象
    			beanType = obtainApplicationContext().getType(beanName);
    		}
    		catch (Throwable ex) {
    			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
    			if (logger.isTraceEnabled()) {
    				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
    			}
    		}
           //判断该对象类型 是否控制类 如果是的情况下
    		if (beanType != null && isHandler(beanType)) {
                //
    			detectHandlerMethods(beanName);
    		}
    	protected boolean isHandler(Class<?> beanType) {
    		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Nq8w2OH-1660837592257)(https://cdn.nlark.com/yuque/0/2022/png/25438525/1658843830899-d7a8d071-8025-469b-abdd-85adfabd2df8.png)]

    maven依赖

     <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
        <!-- 整合springmvc框架依赖  -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.2.10.RELEASE</version>
        </dependency>
    
      </dependencies>
      <!--
           使用maven tomcat插件运行
           -->
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <configuration>
              <port>85</port>
              <path>/</path>
              <ignorePackaging>true</ignorePackaging>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>8</source>
              <target>8</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    自定义注解

    控制器注解

    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface MayiktController {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    URL映射注解

    package com.mayikt.ext;
    
    import org.springframework.web.bind.annotation.Mapping;
    
    import java.lang.annotation.*;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface MayiktRequestMapping {
        String value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    响应json数据

    package com.mayikt.ext;
    
    import java.lang.annotation.*;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MayiktResponseBody {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试接口

    package com.mayikt.controller;
    
    import com.mayikt.ext.MayiktRequestMapping;
    import com.mayikt.ext.MayiktResponseBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @com.mayikt.ext.MayiktController
    public class MayiktController {
        /**
         * 1.需要将我们的控制类注入到IOC容器;
         * 2.循环遍历判断每个 bean对象 是否在类上加上@Controller注解
         * 3.如果有加上@Controller注解 , 则将它存入到springmvc容器中
         * 4.利用java反射机制 遍历springmvc容器中  url与控制类方法 关联
         */
    
        /**
         * 访问该接口返回json数据
         *
         * @return
         */
        @MayiktRequestMapping("/mayiktSpringMvc")
        @MayiktResponseBody
        public String mayiktSpringMvc() {
            return "ok";
        }
    
        /**
         * 访问该接口返回json数据
         *
         * @return
         */
        @MayiktRequestMapping("/mayikt66")
        @MayiktResponseBody
        public String mayikt66() {
            return "mayikt66";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    URL映射(初始化)

    package com.mayikt.init;
    
    import com.mayikt.ext.MayiktController;
    import com.mayikt.ext.MayiktRequestMapping;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @Component
    public class MayiktAbstractHandlerMethodMapping implements ApplicationContextAware, InitializingBean {
        private ApplicationContext applicationContext;
    
        /**
         * 初始化 url与具体控制类方法 映射
         * spring控制类名称 handler
         *
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            //1.从ioc容器获取所有bean的对象名称
            String[] beanDefinitionNames = this.applicationContext.getBeanDefinitionNames();
            //2.从ioc容器获取到具体bean对象
            Arrays.stream(beanDefinitionNames).forEach((beanName) -> {
                Object handler = this.applicationContext.getBean(beanName);
                if (handler != null) {
                    Class<?> handlerClass = handler.getClass();
                    //3.判断该类上是否有加上该控制器注解
                    MayiktController mayiktController = handlerClass.getDeclaredAnnotation(MayiktController.class);
                    if (mayiktController != null)
                        detectHandlerMethods(handler, handlerClass);
                }
            });
    
    
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        private void detectHandlerMethods(Object handler, Class<?> handlerClass) {
            // 4.使用java反射机制获取所有的方法 判断方法上是否有加上MayiktRequestMapping
            Method[] declaredMethods = handlerClass.getDeclaredMethods();
            Arrays.stream(declaredMethods).forEach((method -> {
                //判断方法上是否有加上MayiktRequestMapping
                MayiktRequestMapping mayiktRequestMapping = method.getDeclaredAnnotation(MayiktRequestMapping.class);
                if (mayiktRequestMapping != null) {
                    // 注册url
                    // map集合 key url value 控制类、方法
                    String reqURL = mayiktRequestMapping.value();
                    // 注册存放url
                    MayiktMappingRegistContainer.getRegistUrl().put(reqURL+".do", new MayiktMappingRegistration(handler, method, reqURL));
                }
    
            }));
        }
    }
    
    
    package com.mayikt.init;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    public class MayiktMappingRegistContainer {
        private static Map<String, MayiktMappingRegistration> registUrl = new HashMap<>();
    
        public static Map<String, MayiktMappingRegistration> getRegistUrl() {
            return registUrl;
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    MayiktDispatcherservlet分发

    package com.mayikt.ext;
    
    import com.mayikt.init.MayiktMappingRegistContainer;
    import com.mayikt.init.MayiktMappingRegistration;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.lang.reflect.Method;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    @WebServlet("*.do")
    public class MayiktDispatcherServlet implements Servlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
            PrintWriter writer = httpServletResponse.getWriter();
            try {
                // 1.获取客户端访问url
                String requestURI = httpServletRequest.getRequestURI();
                // 2.再根据该url从 映射map集合查找对应的 handler和方法
                MayiktMappingRegistration mayiktMappingRegistration
                        = MayiktMappingRegistContainer.getRegistUrl().get(requestURI);
                if (mayiktMappingRegistration == null) {
                    // 没有对应的 映射handler和方法
                    httpServletResponse.setStatus(404);
                    writer.print("404");
                    return;
                }
                // 3.利用反射机制调用 handler和方法
                Object handler = mayiktMappingRegistration.getHandler();
                Method handlerMethod = mayiktMappingRegistration.getHandlerMethod();
                // 调用 映射方法
                Object result = handlerMethod.invoke(handler, null);
                // 4.判断方法上是否有加上MayiktResponseBody
                MayiktResponseBody mayiktResponseBody = handlerMethod.getDeclaredAnnotation(MayiktResponseBody.class);
                if (mayiktResponseBody != null) {
                    writer.print(result);// 返回json数据
                } else {
                    // 视图页面跳转
                    httpServletRequest.getRequestDispatcher((String) result).forward(httpServletRequest, httpServletResponse);
                }
    
            } catch (Exception e) {
    
            } finally {
                if (writer != null) {
                    writer.close();
                }
    
            }
        }
    
        @Override
        public String getServletInfo() {
            return null;
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    package com.mayikt.ext;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    public class MayiktMappingRegistContainer {
        private static Map<String, MayiktMappingRegistration> registry = new HashMap<>();
    
        public static Map<String, MayiktMappingRegistration> getRegistry() {
            return registry;
        }
    
    }
    
    package com.mayikt.ext;
    
    import java.lang.reflect.Method;
    
    /**
    * @author songchuanfu
    * @qq 1802284273
    */
    public class MayiktMappingRegistration {
        /**
         * 控制器类
         */
        private Object handler;
        /**
         * 具体对应的方法
         */
        private Method handlerMethod;
        /**
         * 请求url
         */
        private String mappingUrl;
    
        public MayiktMappingRegistration(Object handler, Method handlerMethod, String mappingUrl) {
            this.handler = handler;
            this.handlerMethod = handlerMethod;
            this.mappingUrl = mappingUrl;
        }
    
        public Object getHandler() {
            return handler;
        }
    
        public void setHandler(Object handler) {
            this.handler = handler;
        }
    
        public Method getHandlerMethod() {
            return handlerMethod;
        }
    
        public void setHandlerMethod(Method handlerMethod) {
            this.handlerMethod = handlerMethod;
        }
    
        public String getMappingUrl() {
            return mappingUrl;
        }
    
        public void setMappingUrl(String mappingUrl) {
            this.mappingUrl = mappingUrl;
        }
    
        public MayiktMappingRegistration() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    相关代码

    📎mayikt-mvcdemo01.rar

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		//获取HttpServletRequest
            HttpServletRequest processedRequest = request;
            //处理器执行链由处理器对象和拦截器组成
    		HandlerExecutionChain mappedHandler = null;
    		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.
    				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;
    				}
    
    				// Actually invoke the handler.
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				if (asyncManager.isConcurrentHandlingStarted()) {
    					return;
    				}
    
    				applyDefaultViewName(processedRequest, mv);
    				mappedHandler.applyPostHandle(processedRequest, response, mv);
    			}
    			catch (Exception ex) {
    				dispatchException = ex;
    			}
    			catch (Throwable err) {
    				// As of 4.3, we're processing Errors thrown from handler methods as well,
    				// making them available for @ExceptionHandler methods and other scenarios.
    				dispatchException = new NestedServletException("Handler dispatch failed", err);
    			}
    			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    		}
    		catch (Exception ex) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    		}
    		catch (Throwable err) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler,
    					new NestedServletException("Handler processing failed", err));
    		}
    		finally {
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				// Instead of postHandle and afterCompletion
    				if (mappedHandler != null) {
    					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    				}
    			}
    			else {
    				// Clean up any resources used by a multipart request.
    				if (multipartRequestParsed) {
    					cleanupMultipart(processedRequest);
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
  • 相关阅读:
    android studio环境搭建让你的开发之旅更加简单
    阿里云X魔搭社区Create@AI创客松第四届冠军:MumuLab
    使用Seata实现分布式事务
    springboot:validator之自定义注解校验
    3D nunuStudio脚本开发入门
    计算机组成原理中的诸如4k*8位,8K*8位之类的是什么意思
    科普ChatGPT
    【C++】初阶模板
    弘辽科技:网店提升销量先提升流量吗?怎么提升流量?
    Spark SQL
  • 原文地址:https://blog.csdn.net/u014001523/article/details/126415946