打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
DispatcherServlet web框架入口与总控

      在传统的servlet开发模式下,一个web应用必然需要有对应的应用的配置,即web.xml文件。web.xml是应用的入口,针对特定请求进行相应的处理类的配置:

<!--配置Servlet--><servlet>       <servlet-name>FristServlet</servlet-name>       <servlet-class>FristServlet</servlet-class></servlet><!--映射Servlet -- ><servlet-mapping>         <servlet-name>FristServlet</servlet-name>         <url-pattern>/test</url-pattern>  </servlet-mapping> 

      其中包括了处理类的定义<servlet/>,和请求与处理的映射配置<servlet-mapping />,当web容器启动时首先会读取web.xml,根据文件配置内容进行相关servlet类的加载和实例化,servlet标签中<load-on-startup></load-on-startup>定义了该类是否在容器启动时加载,其值大于等于0时为加载,(据说值越大,加载优先级越低),当类加载后会调用其init()方法。而其其它没有此项配置的servlet类,则会在第一次被请求时进行加载和实例化,即容器根据URL匹配到映射配置,然后检查该类没有实例化,则进行实例化,并调用init()方法,然后处理请求。

      传统方式下,当应用逐渐变大,servlet数量大量增加时,web.xml文件配置将变得复杂而庞大,不利于开发。于是各种解决此问题的web框架应运而生,包括struts,struts2,springmvc等,将相关的处理方法集中在一个处理类中,通过通配符进行匹配,简化对外的配置,同时提供各种功能强大的请求参数拦截和包装功能,简化开发。

       web框架到底是一个什么存在呢,我觉得其实就是一个应用,实现了对原有servlet功能的包装,提供更多简便的功能:请求参数拦截与包装,进行请求与处理类的对应关系的维护,DispatcherServlet则实现了对容器创建,请求发起到请求处理结束的全过程的功能的串联。

/** * @PROJECT_NAME smartweb * @PACKAGE_NAME org.smartweb.web * @USER takou * @CREATE 2018/4/5 **/@WebServlet(loadOnStartup = 0,urlPatterns = "*.do")public class DispatcherServlet extends HttpServlet {    private static final Logger LOGGER = LoggerFactory.getLogger(DispatcherServlet.class);    @Override    public void init(ServletConfig config) throws ServletException {        BeanContainerBuilder.buildWebContainer();        ServletContext context = config.getServletContext();        ServletRegistration jsp = context.getServletRegistration("jsp");        jsp.addMapping(ConfigUtil.getJspPath() + "*");        ServletRegistration asset = context.getServletRegistration("default");        asset.addMapping(ConfigUtil.getAsset() + "*");    }

    通过init()方法在web容器启动时调用,初始化框架相关内容,通过buildWebContainer()实现

/** * @PROJECT_NAME smartweb * @PACKAGE_NAME org.smartweb.container * @USER takou * @CREATE 2018/4/5 **/public final class BeanContainerBuilder {    private static Class<?>[] containers = new Class<?>[]{BeanContainer.class,WebController.class};    /**     * @Description 构建bean容器     * @Param       []     * @Return      void     * @Author      takou     * @Date        2018/4/6     * @Time        下午12:17     */    public static void buildWebContainer() {        for (Class<?> cls : containers) {            ClassUtil.loadClass(cls.getName(),true);        }    }}

    其中包括了ioc对bean的管理以及对请求与处理类的映射关系管理

/** * @PROJECT_NAME smartweb * @PACKAGE_NAME org.smartweb.web * @USER takou * @CREATE 2018/4/5 **/public final class WebController {    private static final Map<Request,Handler> ACTION_MAP = new HashMap<Request, Handler>();    private static final Set<Class<?>> controllerSet = BeanContainer.getControllerSet();    static {        //扫描所有controller,建立request和handler的对应关系        for (Class<?> cls : controllerSet) {            Method[] methods = cls.getDeclaredMethods();            for (Method method : methods) {                if (method.isAnnotationPresent(Action.class)) {                    Action action = method.getAnnotation(Action.class);                    String reqMethod = action.method();                    String reqResource = action.resource();                    Request request = new Request(reqMethod,reqResource);                    Handler handler = new Handler(method,cls);                    ACTION_MAP.put(request,handler);                }            }        }    }    public static Handler getHandler(String method, String resource) {        Request request = new Request(method,resource);        return ACTION_MAP.get(request);    }    public static Map<Request, Handler> getActionMap() {        return ACTION_MAP;    }}

    此处通过Action注解实现对请求与处理方法的映射配置,并放入ACTION_MAP中进行管理,而handler包含了处理方法和所属Class,请求过来时,由URL获得handler,

@Override    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //获得请求的方法和请求的资源        String method = req.getMethod().toLowerCase();        String resource = req.getServletPath();        //获得处理请求的action        Handler handler = WebController.getHandler(method,resource);        
    handler配置的Class从ioc容器中获得实例,然后进行调用            
@Override    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //获得请求的方法和请求的资源        String method = req.getMethod().toLowerCase();        String resource = req.getServletPath();        //获得处理请求的action        Handler handler = WebController.getHandler(method,resource);        if (handler == null) {            handler = WebController.getHandler("get","/customer/goToIndex");        }        Object obj = BeanContainer.getBean(handler.getCls());        Method reqMethod = handler.getMethod();        //拦截请求参数,进行封装        Map<String,String[]> param = req.getParameterMap();        //调用目标方法        Object object = null;        try {            ModelAndView view = new ModelAndView();            view.setReqParam(param);            object = reqMethod.invoke(obj,view);        } catch (IllegalAccessException e) {            LOGGER.error(reqMethod.getName() + " illegal access",e);            throw new RuntimeException(e);        } catch (InvocationTargetException e) {            LOGGER.error(reqMethod.getName() + " invoke failure",e);            throw new RuntimeException(e);        }        //处理调用后的返回结果,进行封装        if (object instanceof ModelAndView) {            ModelAndView view = (ModelAndView) object;            view.setRequest(req);            view.setResponse(resp);            view.forward();        } else if (object instanceof Data) {            //处理json数据...            Data data = (Data) object;            //Object jsonObj = data.getModel();            //String json = JSONValue.toJSONString(jsonObj);            resp.setCharacterEncoding("utf-8");            resp.setContentType("application/json");            PrintWriter writer = resp.getWriter();            //JSONValue.writeJSONString(data.getModel().toString());            writer.write(data.getModel().toString());            writer.flush();            writer.close();        }    }

    统一请求处理方法的声明,便于反射调用时的参数传递,这里就包括了对请求参数拦截和包装的具体功能

//拦截请求参数,进行封装        Map<String,String[]> param = req.getParameterMap();        //调用目标方法        Object object = null;        try {            ModelAndView view = new ModelAndView();            view.setReqParam(param);            object = reqMethod.invoke(obj,view);        } catch (IllegalAccessException e) {            LOGGER.error(reqMethod.getName() + " illegal access",e);            throw new RuntimeException(e);        } catch (InvocationTargetException e) {            LOGGER.error(reqMethod.getName() + " invoke failure",e);            throw new RuntimeException(e);        }

    调用完成后,对返回结果进行分类包装处理,返回静态资源,页面跳转或返回json数据等

//处理调用后的返回结果,进行封装        if (object instanceof ModelAndView) {            ModelAndView view = (ModelAndView) object;            view.setRequest(req);            view.setResponse(resp);            view.forward();        } else if (object instanceof Data) {            //处理json数据...            Data data = (Data) object;            //Object jsonObj = data.getModel();            //String json = JSONValue.toJSONString(jsonObj);            resp.setCharacterEncoding("utf-8");            resp.setContentType("application/json");            PrintWriter writer = resp.getWriter();            //JSONValue.writeJSONString(data.getModel().toString());            writer.write(data.getModel().toString());            writer.flush();            writer.close();        }
由此,一个请求处理完成,可见DispatcherServlet的框架入口功能和请求处理的总控功能。





本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Spring 4 官方文档学习(十一)Web MVC 框架
[Java] SpringMVC工作原理之二:HandlerMapping和HandlerAdapt...
看透 Spring MVC 源代码分析与实践——俯视 Spring MVC
深入底层,仿SpringMVC自己写框架
Ext框架学习 (三) Ext.Ajax类
SpringMVC源码剖析(一)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服