手写 简易 Spring MVC xml

手写实现简易的Spring MVC xml版本。

代码:https://github.com/kuotian/springmvc_me

  1. 用户请求:localhost\addUser2
  2. DispatcherServlet接收请求,通过HandlerMapping去查找合适的Handler
  3. 根据处理器获取相应的适配器,执行相应的处理器的方法去处理请求
  4. 返回执行结果

目录
  • 1. 使用Servlet实现
  • 2. 使用Servlet的弊端 及 解决方案
    • 分析使用Servlet实现BS结构服务处理的弊端
    • 解决方案
  • 3. 手写简易Spring MVC
    • DispatcherServlet
      • AbstractHttpServlet
      • DispatcherServlet
    • HandlerMapping
      • HandlerMapping
      • BeanNameUrlHandlerMapping
      • SimpleUrlHandlerMapping
    • HandlerAdapter
      • HandlderAdapter
      • HttpRequestHandlerAdapter
    • Handler
      • SimpleControllerHandler
      • HttpRequestHandler
      • AddUserHandler
      • QueryUserHandler
    • springmvc.xml
    • web.xml
    • 测试处理请求流程:

1. 使用Servlet实现

localhost/addUser

package com.hdu.springmvc.servlet;

public class AddUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain;charset=utf8");
        resp.getWriter().write("添加成功");
    }

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

localhost/queryUser

package com.hdu.springmvc.servlet;

public class QueryUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain;charset=utf8");
        resp.getWriter().write("查询成功");
    }

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

2. 使用Servlet的弊端 及 解决方案

分析使用Servlet实现BS结构服务处理的弊端
  1. 对于程序员来说,会编写大量的Servlet代码,很不爽。
  2. Servlet是由tomcat产生的,产生过多的Servlet对象,会导致tomcat本身启动的时候会有压力。
解决方案
  1. 编写Servlet基类BaseServlet,抽取相同的逻辑。业务处理逻辑写在子类的Servlet。

    请求url:
    localhost/userSersvlet?method=add
    localhost/userSersvlet?method=query

    BaseServlet{
    	doGet(){
    		获取method参数值
    		根据参数值调用响应的方法
    	}
    }
    	
    UserServlet extends BasServlet{
    	add(){}
    	query(){}
    }
    
  2. 编写全局Servlet去接收所有Servlet请求,然后在该Servlet中进行请求分发,由处理器类去处理具体的请求。 ---> Spring MVC

    其中,处理器类不需要实现Servlet接口,它只是一个普通的JavaBean。不需要产生额外的Servlet类。

    DispatcherServlet{
    	doGet(){
    		url
    		if("/queryUser".equals(url)){
    			找相应的处理器去处理
    		}
    	}
    }
    //接口(标准或者规范)
    UserHandler{
    	xxx
    }
    

3. 手写简易Spring MVC

DispatcherServlet

作用:

​ 接收请求、响应结果
​ 查找处理器
​ 执行相应的处理器(调用处理器的方法去处理请求)

手写 简易 Spring MVC xml_第1张图片

AbstractHttpServlet
package com.hdu.springmvc.servlet;

public abstract class AbstractHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doDispatch(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
    
    /**
     * 抽象模板设计模式的钩子方法
     */
    public abstract void doDispatch(HttpServletRequest request, HttpServletResponse response);
}
DispatcherServlet
package com.hdu.springmvc.servlet;
public class DispatcherServlet extends AbstractHttpServlet {

        private DefaultListableBeanFactory beanFactory;
        // 处理器映射器的策略集合
        private List handlerMappings;
        // 处理器适配器的策略集合
        private List handlerAdapters;

        public void init(ServletConfig config){
            // 从web.xml中获取springmvc的配置文件路径
            String contextConfigLocation = config.getInitParameter("contextConfigLocation");
            // 初始化spring容器,需要提前一次性初始化bean实例
            initSpringContainer(contextConfigLocation);
            // 初始化策略集合
            initHandlerMappings();
            initHandlerAdapters();
        }

        private void initSpringContainer(String contextConfigLocation) {
            beanFactory = new DefaultListableBeanFactory();
            XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
            Resource resource = new ClassPathResource(contextConfigLocation);
            reader.loadBeanDefinitions(resource);
        }
        private void initHandlerMappings() {
            // 从spring容器中,初始化所有的HandlerMapping的策略
            handlerMappings = new ArrayList<>(beanFactory.getBeansOfType(HandlerMapping.class).values());
        }
        private void initHandlerAdapters() {
            handlerAdapters = new ArrayList<>(beanFactory.getBeansOfType(HandlderAdapter.class).values());
        }

    @Override
    public void doDispatch(HttpServletRequest request, HttpServletResponse response) {
        try {
            // 根据请求查找处理器类(HandlerMapping)
            Object handler = getHandler(request);
            // 去执行处理器类的方法(HandlerAdapter)
//            // 使用策略模式+适配器模式去优化以下代码
//            if (handler instanceof HttpRequestHandler) {
//                ((HttpRequestHandler) handler).handleRequest(request, response);
//            } else if (handler instanceof SimpleControllerHandler) {
//                ((SimpleControllerHandler) handler).handleRequest(request, response);
//            }
            if(handler == null){
                return;
            }
            // 先找处理器适配器
            HandlderAdapter ha = getHandlerAdapter(handler);
            if (ha == null) {
                return;
            }
            // 再去调用处理器适配器的统一处理请求方法
            ModelAndView mv = ha.handleRequest(handler, request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object getHandler(HttpServletRequest request) throws Exception {
        String uri = request.getRequestURI();

        // 使用策略模式
        if (handlerMappings != null && handlerMappings.size() > 0) {
            for (HandlerMapping handlerMapping : handlerMappings) {
                Object handler = handlerMapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

    private HandlderAdapter getHandlerAdapter(Object handler) {
        // 如果HandlerAdapter1能处理handler,则返回HandlerAdapter1
        // 如果HandlerAdapter2能处理handler,则返回HandlerAdapter2
        // 如果HandlerAdapter3能处理handler,则返回HandlerAdapter3
        if (handlerAdapters != null && handlerAdapters.size() > 0) {
            for (HandlderAdapter handlderAdapter : handlerAdapters) {
                // 判断该处理器适配器是否支持该处理器
                if (handlderAdapter.supports(handler)) {
                    return handlderAdapter;
                }
            }
        }
        return null;
    }
}

HandlerMapping

作用:请求映射和查找请求

建立映射的方式有多种,所以说HandlerMapping应该有多个。每个HandlerMapping负责的映射来源是不一样的。

  • BeanNameUrlHandlerMapping:通过bean标签的name属性和bean标签对应的实例建立映射关系
  • SimpleUrlHandlerMapping:手动建立映射。(充数用)

手写 简易 Spring MVC xml_第2张图片

HandlerMapping
package com.hdu.springmvc.handlermapping.iface;

// 定义处理器映射器的编写规范
public interface HandlerMapping {
    /**
     * 根据请求查找处理器
     * @param request
     * @return
     * @throws Exception
     */
    Object getHandler(HttpServletRequest request) throws Exception;
}
BeanNameUrlHandlerMapping
package com.hdu.springmvc.handlermapping;

// 通过bean标签的name属性和bean标签对应的实例建立映射关系
public class BeanNameUrlHandlerMapping implements HandlerMapping, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;
    // uri和处理器对象的映射集合
    private Map mappings = new HashMap<>();

    /**
     * BeanNameUrlHandlerMapping的初始化方法
     */
    public void init(){
        // 从spring容器中(BeanFactory)获取所有的handler的BeanDefinition对象
        // Spring 容器中所有 JavaBean 的名称
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            // 判断bean的name属性,是否是以/开头
            if( beanDefinitionName.startsWith("/") ) {
                // 取出bean的name属性,并且获取bean实例
                Object bean = beanFactory.getBean(beanDefinitionName);
                // 建立映射关系
                mappings.put(beanDefinitionName, bean);
            }
        }
    }

    @Override
    public Object getHandler(HttpServletRequest request) throws Exception {
        String uri = request.getRequestURI();
        return mappings.get(uri);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory)beanFactory;
    }
}
SimpleUrlHandlerMapping
package com.hdu.springmvc.handlermapping;

public class SimpleUrlHandlerMapping implements HandlerMapping, BeanFactoryAware {
    private DefaultListableBeanFactory beanFactory;
    // uri和处理器对象的映射集合
    private Map mappings = new HashMap<>();
	
    // 手动填充
    public void init() {
        mappings.put("/addUser3", new AddUserHandler());
        mappings.put("/queryUser3", new QueryUserHandler());
    }

    @Override
    public Object getHandler(HttpServletRequest request) throws Exception {
        String uri = request.getRequestURI();
        return mappings.get(uri);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }
}

HandlerAdapter

作用:将DispatcherServlet类中使用的Handler类,适配成统一的HandlerAdapter类型。
手写 简易 Spring MVC xml_第3张图片

HttpRequestHandler ---> HttpRequestHandlerAdapter --->HandlerAdapter 类型

HandlderAdapter
package com.hdu.springmvc.handleradapter.iface;

// DispatcherServlet类中希望见到的统一的目标接口
public interface HandlderAdapter {
    /**
     * 处理请求
     * @param handler 处理器类
     */
    ModelAndView handleRequest(Object handler, HttpServletRequest request, HttpServletResponse response) throws Exception;

    /**
     * 就是判断该适配器是否适合该处理器,方便策略模式使用时进行调用
     * @param handler
     */
    boolean supports(Object handler);
}
HttpRequestHandlerAdapter
package com.hdu.springmvc.handleradapter;

public class HttpRequestHandlerAdapter implements HandlderAdapter {
    @Override
    public ModelAndView handleRequest(Object handler, HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            ((HttpRequestHandler) handler).handleRequest(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpRequestHandler);
    }
}

Handler

是一个普通的Java类,它不是Servlet类。

作用:处理请求。

  • HttpRequestHandler接口(规范大家如何编写Handler类去处理请求)

    ​ void handleRequest(request,response);

  • SimpleControllerHandler接口

    ​ ModelAndView handleRequest(request,response);

对于处理器类的处理结果,有可能还需要处理,则把处理结果和最终显示的视图名称封装到一个对象中。Handler类的编写方式有多种,而且类型都无法统一。需要有个适配器处理。

手写 简易 Spring MVC xml_第4张图片

SimpleControllerHandler
// 定义处理器的编写规范
// 这种规范要求返回一个返回值ModelAndView对象
public interface SimpleControllerHandler {
    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
HttpRequestHandler
public interface HttpRequestHandler {
    void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
AddUserHandler
package com.hdu.springmvc.handler;

public class AddUserHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/plain;charset=utf8");
        response.getWriter().write("AddUserHandler添加成功");
    }
}
QueryUserHandler
package com.hdu.springmvc.handler;

public class QueryUserHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/plain;charset=utf8");
        response.getWriter().write("QueryUserHandler添加成功");
    }
}

springmvc.xml




    
    
    
    

    
    
    

    
    

web.xml



    
        AddUserServlet
        com.hdu.springmvc.servlet.AddUserServlet
    
    
        AddUserServlet
        /addUser
    

    
        QueryUserServlet
        com.hdu.springmvc.servlet.QueryUserServlet
    
    
        QueryUserServlet
        /queryUser
    


    
        DispatcherServlet
        com.hdu.springmvc.servlet.DispatcherServlet
        
            contextConfigLocation
            springmvc.xml
        
    
    
        DispatcherServlet
        /
    


测试处理请求流程:

localhost\addUser 直接编写Servlet处理

localhost\addUser2 --->DispatcherServlet --->BeanNameUrlHandlerMapping--->HttpRequestHandlerAdapter---> HttpRequestHandler 的 AddUserHandler

localhost\addUser3 --->DispatcherServlet --->SimpleUrlHandlerMapping---> AddUserHandler

你可能感兴趣的:(手写 简易 Spring MVC xml)