手写模拟SpringMvc源码

命运对每个人都是一样的,不一样的是各自的努力和付出不同,付出的越多,努力的越多,得到的回报也越多,在你累的时候请看一下身边比你成功却还比你更努力的人,这样,你就会更有动力。

导读:本篇文章讲解 手写模拟SpringMvc源码,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

MVC框架

MVC是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。

Spring MVC的主要组件

前端控制器 DispatcherServlet

Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。此模块不需要程序员开发。

作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。

处理器映射器HandlerMapping

此功能不需要程序员开发。

作用:根据请求的URL来查找Handler

处理器适配器HandlerAdapter

作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)

视图View

需要程序员开发jsp。View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

手写模拟SpringMvc源码

用户发送请求至前端控制器DispatcherServlet;

DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;

处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;

DispatcherServlet 调用 HandlerAdapter处理器适配器;

HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);

Handler执行完成返回ModelAndView;

HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;

DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;

ViewResolver解析后返回具体View;

DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)

DispatcherServlet响应用户。

手写模拟SpringMvc源码

spring mvc调用到Controller执行的原理

通过加载配置文件web.xml进而加载spring-mvc.xml。

根据配置文件给定的目录来扫描整个项目。

扫描所有加了@Controller注解的类。

当扫描到加了@Controller注解的类之后遍历里面所有的方法。

拿到方法对象之后 解析方法上面是否加了@RequestMapping注解。

定义一个Map集合把@RequstMapping的value 与方法对象绑定起来,即Map<String,Method>。

定义一个Map把声名该方法的类的对象绑定起来,即Map<String,Object>。

拦截到请求之后拿到请求的URI。

处理请求,例如执行指定方法,返回字符串或跳转到相应视图。

目录

手写模拟SpringMvc源码

导入依赖

 <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <!--       解析xml文件-->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>

代码

DispatcherServlet类

public class DispatcherServlet extends HttpServlet {
    private ApplicationContext applicationContext;
    private List<MyHandle> myHandleList=new ArrayList<>();

    @Override
    public void init() throws ServletException {
        String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        System.out.println(contextConfigLocation);
        applicationContext = new ApplicationContext(contextConfigLocation);
        applicationContext.refresh();
        initHandleMappinng(applicationContext);

    }

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

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

    }

    public void initHandleMappinng(ApplicationContext applicationContext){
        if(applicationContext.beanDefinitionConcurrentHashMap.size()==0){
            throw new RuntimeException("Spring容器为空");
        }
        for (Map.Entry<String, BeanDefinition> stringBeanDefinitionEntry : applicationContext.beanDefinitionConcurrentHashMap.entrySet()) {
            Class clazz = stringBeanDefinitionEntry.getValue().getClazz();
            for (Method declaredMethod : clazz.getDeclaredMethods()) {
                boolean annotationPresent = declaredMethod.isAnnotationPresent(RequestMapping.class);
                if(annotationPresent==true){
                    String value = declaredMethod.getAnnotation(RequestMapping.class).value();
                    MyHandle myHandle=new MyHandle(value,declaredMethod,clazz);
                    myHandleList.add(myHandle);
                }
            }
        }
    }
    public void excuteDispatch(HttpServletRequest request,HttpServletResponse response){
        MyHandle handle = getHandle(request);
        if(handle==null){
            try {
                response.getWriter().print("404");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        else {
            Method method = handle.getMethod();
            Class<?>[] parameterTypes = method.getParameterTypes();
            Object[] params=new Object[parameterTypes.length];
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {
                String key = stringEntry.getKey();
                String value = stringEntry.getValue()[0];
                int i = GetRequestParams(method, key);
                if(i>=0)
                    params[i]=value;
                else {
                    //反射获取的是arg0,官方这里用的不是反射机制
                }
            }
            try {
                Object invoke = method.invoke(handle.getClazz().newInstance(), params);
                PrintWriter writer = response.getWriter();
                writer.print(invoke);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public MyHandle getHandle(HttpServletRequest request){
        String requestURI = request.getRequestURI();
        for (MyHandle myHandle : myHandleList) {
            if(myHandle.getUrl().equals(requestURI))
                return myHandle;
        }
        return null;
    }

    public int GetRequestParams(Method method,String name){
        Parameter[] parameters = method.getParameters();
        for (int i=0;i<parameters.length;i++) {
            boolean annotationPresent = parameters[i].isAnnotationPresent(RequestParam.class);
            if(annotationPresent){
                String value = parameters[i].getAnnotation(RequestParam.class).value();
                if(value.equals(name))
                    return i;
            }
        }
        return -1;

    }


}

XmlPaser类

public class XmlPaser {
    public static String getbasePackage(String xml){
        SAXReader saxReader=new SAXReader();
        InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Element componentScan = rootElement.element("component-scan");
            Attribute attribute = componentScan.attribute("base-package");
            String text = attribute.getText();
            return text;
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return "";
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <display-name>Application</display-name>

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>com.example.demo.springmvc.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

代码下载地址:https://download.csdn.net/download/qq_43649937/87558006

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/143067.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!