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的框架入口功能和请求处理的总控功能。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值