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

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

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

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

作用:

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

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<HandlerMapping> handlerMappings;
        // 处理器适配器的策略集合
        private List<HandlderAdapter> 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:手动建立映射。(充数用)

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<String, Object> 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<String, Object> 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类型。

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类的编写方式有多种,而且类型都无法统一。需要有个适配器处理。

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

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

    <!-- 首先配置handler,交给spring容器去管理该bean -->
    <!-- 其次配置name属性为uri,便于建立映射关系 -->
    <bean name="/addUser2"
          class="com.hdu.springmvc.handler.AddUserHandler"></bean>
    <bean name="/queryUser2"
          class="com.hdu.springmvc.handler.QueryUserHandler"></bean>

    <!-- 配置处理器映射器 -->
    <bean class="com.hdu.springmvc.handlermapping.BeanNameUrlHandlerMapping"
          init-method="init"></bean>
    <bean class="com.hdu.springmvc.handlermapping.SimpleUrlHandlerMapping"
          init-method="init"></bean>

    <!-- 配置处理器适配器 -->
    <bean class="com.hdu.springmvc.handleradapter.HttpRequestHandlerAdapter"></bean>
</beans>

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">
    <servlet>
        <servlet-name>AddUserServlet</servlet-name>
        <servlet-class>com.hdu.springmvc.servlet.AddUserServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddUserServlet</servlet-name>
        <url-pattern>/addUser</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>QueryUserServlet</servlet-name>
        <servlet-class>com.hdu.springmvc.servlet.QueryUserServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>QueryUserServlet</servlet-name>
        <url-pattern>/queryUser</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>com.hdu.springmvc.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

测试处理请求流程:

localhost\addUser 直接编写Servlet处理

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

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

posted on 2020-06-18 17:46  kuotian  阅读(170)  评论(0编辑  收藏  举报