概述

Front Controller Pattern(前端控制器模式)来自 Martin Fowler 的《企业应用架构模式》(Patterns of Enterprise Application Architecture,2002),属于 Web 层架构模式,不是 GoF 23 种设计模式的一部分。

详见 企业应用架构模式。

解决的问题

在原始 Servlet 时代,每个 URL 对应一个独立的 Servlet 类,这是 Page Controller 模式:

/users    → UsersServlet
/orders   → OrdersServlet
/products → ProductsServlet

每个 Servlet 都要自己处理身份验证、日志记录、权限检查,代码大量重复。随着 URL 增多,web.xml 里的注册条目也膨胀。

Front Controller 的解法是单一入口:

所有请求 → FrontController(统一处理横切关注点)→ Dispatcher → 具体处理器

三个角色

  • Front Controller:所有请求的唯一入口,集中处理身份验证、权限验证、日志追踪等横切关注点
  • Dispatcher:将请求路由到对应的具体处理器(View/Handler)
  • View / Handler:真正处理业务逻辑的模块

Spring MVC 中的实现

Spring MVC 的 DispatcherServlet 是 Front Controller 模式的标准实现:

HTTP 请求
  → DispatcherServlet(Front Controller,映射到 /)
  → HandlerMapping(查找 URL 对应的 Controller 方法)
  → Controller 方法(业务逻辑)
  → 返回响应

你写的每一个 @GetMapping、@PostMapping 注解,本质上是在向 DispatcherServlet 的路由表注册一条规则。

传统方式需要在 web.xml 中手动注册:

<servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

Spring Boot 的自动配置(DispatcherServletAutoConfiguration)在启动时替你完成这个注册,无需任何 XML。

简单代码示例

HomeView、StudentView 提供真正的业务处理逻辑,Dispatcher 路由到对应 View,FrontController 作为统一入口处理横切关注点。

public class HomeView {
    public void show() {
        System.out.println("show Home view");
    }
}

public class StudentView {
    public void show() {
        System.out.println("show student view");
    }
}

public class Dispatcher {
    private StudentView studentView = new StudentView();
    private HomeView homeView = new HomeView();

    public void dispatch(String viewName) {
        if ("homeView".equals(viewName)) {
            homeView.show();
        } else {
            studentView.show();
        }
    }
}

public class FrontController {
    private Dispatcher dispatcher = new Dispatcher();

    public boolean isAuthenticUser() {
        System.out.println("Authenticate user");
        return true;
    }

    public void trackRequest(String viewName) {
        System.out.println("track request: " + viewName);
    }

    public void dispatchRequest(String viewName) {
        trackRequest(viewName);
        if (isAuthenticUser()) {
            dispatcher.dispatch(viewName);
        }
    }
}

public class FrontControllerPatternDemo {
    public static void main(String[] args) {
        FrontController frontController = new FrontController();
        frontController.dispatchRequest("homeView");
        frontController.dispatchRequest("studentView");
    }
}