MVC架构探究及其源码实现(4)-前端控制器

前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制器既可以使用Filter实现(Struts2采用这种方式),也可以使用Servlet来实现。这里我们就采用后一种方式来实现我们的MVC框架。

 ds

1.配置web.xml,使得我们的前端控制器可以拦截所有符合要求的用户请求,这里我们的前端控制器能处理所有以.do结尾的用户请求。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5"> 

    <description>MVC Sample</description>
    <display-name>MVC</display-name>
    
    <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>com.google.mvc.web.servlet.DispatcherServlet</servlet-class>
    </servlet>   

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

  2.FrameworkServlet实现。
FrameworkServlet是DispatcherServlet的直接父类,继承自HttpServlet,主要用来初始话WebApplicationContext,把不同的Http请求操作委托给同一个方法去处理。

package com.google.mvc.web.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import com.google.mvc.web.context.WebApplicationContext;

public abstract class FrameworkServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = Logger.getLogger(FrameworkServlet.class);
	private WebApplicationContext webApplicationContext;	
	
	@Override
	public void init() throws ServletException {
		
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("----------Initializing servlet '" + getServletName() + "'----------");
		}

		this.webApplicationContext = initWebApplicationContext();
		
		initServletBean();

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("----------Servlet '" + getServletName() + "' configured successfully----------/n/n");
		}

	}	
	
	private WebApplicationContext initWebApplicationContext() {		
		WebApplicationContext wac = new WebApplicationContext(getServletContext());
		wac.init();	
		onRefresh(wac);
		return wac;		
	}

	protected void onRefresh(WebApplicationContext context) {
		// For subclasses: do nothing by default.
	}
	
	protected void initServletBean(){
		
	}
	
	protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
	

	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		try {
			doService(request, response);
		} catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		} catch (IOException ex) {
			failureCause = ex;
			throw ex;
		} catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		} finally {
			if (failureCause != null) {
				LOGGER.error("Could not complete request", failureCause);
			} else {
				long processingTime = System.currentTimeMillis() - startTime;
				if (LOGGER.isDebugEnabled()) {
					LOGGER.info("Successfully completed request, cost " + processingTime + " ms/n");
				}
			}
		}
	}

	@Override
	protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		processRequest(request, response);
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}

	@Override
	protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		processRequest(request, response);
	}

	@Override
	protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		processRequest(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		processRequest(request, response);
	}

	@Override
	protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		processRequest(request, response);
	}

	@Override
	protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		processRequest(request, response);
	}

	@Override
	public void destroy() {
		if(LOGGER.isDebugEnabled()){
			LOGGER.info("Servlet destory");
		}
		super.destroy();
	}

	public WebApplicationContext getWebApplicationContext() {
		return webApplicationContext;
	}
	
	

}

3.DispatcherServlet实现。
package com.google.mvc.web.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import com.google.mvc.web.context.WebApplicationContext;

public class DispatcherServlet extends FrameworkServlet {

	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = Logger.getLogger(DispatcherServlet.class);
	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
	private static final Properties defaultStrategies = new Properties();

	private List<HandlerMapping> handlerMappings;
	private List<HandlerAdapter> handlerAdapters;
	private List<ViewResolver> viewResolvers;

	static {
		try {
			defaultStrategies.load(DispatcherServlet.class.getResourceAsStream(DEFAULT_STRATEGIES_PATH));
		} catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

	@Override
	protected void onRefresh(WebApplicationContext wac) {
		initHandlerMappings(wac);
		initHandlerAdapters(wac);
		initViewResolvers(wac);
	}

	private void initHandlerMappings(WebApplicationContext wac) {
		Map<String, HandlerMapping> map = wac.beansOfType(HandlerMapping.class);
		if (!map.isEmpty()) {
			this.handlerMappings = new ArrayList<HandlerMapping>(map.values());
		}
		if (this.handlerMappings == null) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
			this.handlerMappings = getDefaultStrategies(wac, HandlerMapping.class);
		}
	}

	private void initHandlerAdapters(WebApplicationContext wac) {
		Map<String, HandlerAdapter> map = wac.beansOfType(HandlerAdapter.class);
		if (!map.isEmpty()) {
			this.handlerAdapters = new ArrayList<HandlerAdapter>(map.values());
		}
		if (this.handlerAdapters == null) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
			}
			this.handlerAdapters = getDefaultStrategies(wac, HandlerAdapter.class);
		}
	}

	private void initViewResolvers(WebApplicationContext wac) {
		Map<String, ViewResolver> map = wac.beansOfType(ViewResolver.class);
		if (!map.isEmpty()) {
			this.viewResolvers = new ArrayList<ViewResolver>(map.values());
		}
		if (this.viewResolvers == null) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
			}
			this.viewResolvers = getDefaultStrategies(wac, ViewResolver.class);
		}
	}

	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("DispatcherServlet with name '" + getServletName() + "' received request for ["
					+ request.getRequestURI() + "]");
		}
		doDispatch(request, response);
	}

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Bound request context to thread: " + request);
		}

		Object handler = getHandler(request);
		HandlerAdapter ha = getHandlerAdapter(handler);
		ModelAndView mv = ha.handle(request, response, handler);

		// Do we need view name translation?
		if (mv != null && !mv.hasView()) {
			mv.setViewName(getDefaultViewName(request));
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
		}
	}

	protected <T> List<T> getDefaultStrategies(WebApplicationContext wac, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		List<T> strategies = new ArrayList<T>();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			StringTokenizer token = new StringTokenizer(value, ",");
			while (token.hasMoreTokens()) {
				String className = token.nextToken();
				try {
					Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
					strategies.add((T) wac.createBean(clazz));
				} catch (Exception e) {
					LOGGER.error("Can't load class " + className + "", e);
				}
			}
		} else {
			strategies = Collections.emptyList();
		}
		return strategies;
	}

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		View view = null;
		if (mv.isReference()) {
			// We need to resolve the view name.
			view = resolveViewName(mv.getViewName(), mv.getModelInternal(), request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName()
						+ "' in servlet with name '" + getServletName() + "'");
			}
		} else {
			// No need to lookup: the ModelAndView object contains the actual
			// View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a "
						+ "View object in servlet with name '" + getServletName() + "'");
			}
		}
		// Delegate to the View object for rendering.
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		view.render(mv.getModelInternal(), request, response);
	}

	protected View resolveViewName(String viewName, Map<String, Object> model, HttpServletRequest request)
			throws Exception {
		for (Iterator<ViewResolver> it = this.viewResolvers.iterator(); it.hasNext();) {
			ViewResolver viewResolver = it.next();
			View view = viewResolver.resolveViewName(viewName);
			if (view != null) {
				return view;
			}
		}
		return null;
	}

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		Iterator<HandlerAdapter> it = this.handlerAdapters.iterator();
		while (it.hasNext()) {
			HandlerAdapter ha = it.next();
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Testing handler adapter [" + ha + "]");
			}
			if (ha.supports(handler)) {
				return ha;
			}
		}
		throw new ServletException("No adapter for handler [" + handler
				+ "]: Does your handler implement a supported interface like Controller?");
	}

	protected Object getHandler(HttpServletRequest request) throws Exception {
		Iterator<HandlerMapping> it = this.handlerMappings.iterator();
		while (it.hasNext()) {
			HandlerMapping hm = it.next();
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName()
						+ "'");
			}
			return hm.getHandler(request);
		}
		return null;
	}

	private String getDefaultViewName(HttpServletRequest request) {
		String url = request.getServletPath();
		url = url.replaceAll("/", "");
		url = url.replaceAll(".html", "");
		url = url.replaceAll(".htm", "");

		url = "WEB-INF/" + url + ".jsp";

		return url;
	}

}

初始化操作.

  1. 检查系统中是否已经定义HandlerMapping。如果没有定义,则使用默认配置。
  2. 检查系统中是否已经定义HandlerAdapter。如果没有定义,则使用默认配置。
  3. 检查系统中是否已经定义ViewResolover。如果没有定义,则使用默认配置。

请求处理.

  1. 根据特定的请求,使用HandlerMapping找到相应的控制器Handler。
  2. 找到支持此种handler的HandlerAdapter,handler处理完响应业务后,HandlerAdapter把它转化为ModelAndView对象。
  3. 利用ViewResolver对ModelAndView进行分析,生成相应的View对象。
  4. 生成响应。
默认配置

com.google.mvc.web.servlet.HandlerMapping=com.google.mvc.web.servlet.handler.URLHandlerMapping
com.google.mvc.web.servlet.HandlerAdapter=com.google.mvc.web.servlet.mvc.HttpRequestHandlerAdapter,/
com.google.mvc.web.servlet.mvc.ControllerHandlerAdapter
com.google.mvc.web.servlet.ViewResolver=com.google.mvc.web.servlet.mvc.DefaultViewResolver


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值