天天看点

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

博学,切问,近思--詹子知 (https://jameszhan.github.io)

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

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

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>

<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();

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) {

} catch (throwable 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;

logger.info("successfully completed request, cost " + processingtime + " ms/n");

protected void dodelete(httpservletrequest request, httpservletresponse response) throws servletexception,

ioexception {

processrequest(request, response);

protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {

protected void dohead(httpservletrequest request, httpservletresponse response) throws servletexception,

protected void dooptions(httpservletrequest request, httpservletresponse response) throws servletexception,

protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception,

protected void doput(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {

protected void dotrace(httpservletrequest request, httpservletresponse response) throws servletexception,

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.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;

public class dispatcherservlet extends frameworkservlet {

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 {

defaultstrategies.load(dispatcherservlet.class.getresourceasstream(default_strategies_path));

throw new illegalstateexception("could not load 'dispatcherservlet.properties': " + ex.getmessage());

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) {

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);

this.handleradapters = new arraylist<handleradapter>(map.values());

if (this.handleradapters == null) {

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);

this.viewresolvers = new arraylist<viewresolver>(map.values());

if (this.viewresolvers == null) {

logger.debug("no viewresolvers found in servlet '" + getservletname() + "': using default");

this.viewresolvers = getdefaultstrategies(wac, viewresolver.class);

protected void doservice(httpservletrequest request, httpservletresponse response) throws exception {

logger.debug("dispatcherservlet with name '" + getservletname() + "' received request for ["

+ request.getrequesturi() + "]");

dodispatch(request, response);

protected void dodispatch(httpservletrequest request, httpservletresponse response) throws exception {

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();

class<?> clazz = this.getclass().getclassloader().loadclass(classname);

strategies.add((t) wac.createbean(clazz));

} catch (exception e) {

logger.error("can't load class " + classname + "", e);

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() + "'");

// no need to lookup: the modelandview object contains the actual

// view object.

view = mv.getview();

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.

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();

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();

handlermapping hm = it.next();

logger.debug("testing handler map [" + hm + "] in dispatcherservlet with name '" + getservletname()

+ "'");

return hm.gethandler(request);

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;

初始化操作.

检查系统中是否已经定义handlermapping。如果没有定义,则使用默认配置。

检查系统中是否已经定义handleradapter。如果没有定义,则使用默认配置。

检查系统中是否已经定义viewresolover。如果没有定义,则使用默认配置。

请求处理.

根据特定的请求,使用handlermapping找到相应的控制器handler。

找到支持此种handler的handleradapter,handler处理完响应业务后,handleradapter把它转化为modelandview对象。

利用viewresolver对modelandview进行分析,生成相应的view对象。

生成响应。

默认配置 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

相关文章:

mvc架构探究及其源码实现(1)-理论基础

mvc架构探究及其源码实现(2)-核心组件定义

mvc架构探究及其源码实现(3)-webapplicationcontext

mvc架构探究及其源码实现(5)-相关组件实现

mvc架构探究及其源码实现(6)-简单示例