Spring MVC + Spring Security 源码串讲
概述
本文串联 Spring MVC 和 Spring Security 的源码执行流程,展示一次 HTTP 请求从 FilterChain → DispatcherServlet → Controller → 响应的完整路径。
一、一次请求的完整路径
请求进入
↓
Servlet 容器(Tomcat / Jetty)
↓
FilterChain
├── CharacterEncodingFilter → 编码设置
├── HiddenHttpMethodFilter → PUT/DELETE 方法转换
├── FormContentFilter → 表单解析
└── SecurityFilterChain → Spring Security 过滤器链
├── SecurityContextPersistenceFilter → 从 Session 恢复 SecurityContext
├── LogoutFilter → 登出处理
├── UsernamePasswordAuthenticationFilter → 用户名密码认证
├── DefaultLoginPageGeneratingFilter → 登录页生成
├── BasicAuthenticationFilter → HTTP Basic 认证
├── SecurityContextHolderAwareRequestFilter → 包装 Request
├── RememberMeAuthenticationFilter → 记住我认证
├── AnonymousAuthenticationFilter → 匿名认证
├── SessionManagementFilter → Session 管理
├── ExceptionTranslationFilter → 异常转换
└── FilterSecurityInterceptor → 权限验证(最终拦截器)
↓
DispatcherServlet
├── doDispatch()
│ ├── getHandler() → 获取 HandlerExecutionChain
│ ├── getHandlerAdapter() → 获取 HandlerAdapter
│ ├── applyPreHandle() → 执行前置拦截器
│ ├── handle() → 调用 Controller 方法
│ ├── applyPostHandle() → 执行后置拦截器
│ └── processDispatchResult() → 视图渲染/响应处理
└── 返回响应二、DispatcherServlet 核心流程
2.1 doDispatch() — 请求分发
java
// org.springframework.web.servlet.DispatcherServlet
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1. 检查是否 multipart 请求(文件上传)
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2. 获取 HandlerExecutionChain(核心!)
// HandlerMapping 实现类:RequestMappingHandlerMapping / SimpleUrlHandlerMapping 等
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 没有匹配的 Handler → 404
noHandlerFound(processedRequest, response);
return;
}
// 3. 获取 HandlerAdapter(支持不同类型的处理器)
// RequestMappingHandlerAdapter / HttpRequestHandlerAdapter 等
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 4. 执行前置拦截器(HandlerInterceptor.preHandle())
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
// 拦截器返回 false → 请求结束
return;
}
// 5. 调用 Controller 方法(核心!)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 6. 异步处理检查
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 7. 应用默认视图名称(如果 Controller 未设置)
applyDefaultViewName(processedRequest, mv);
// 8. 执行后置拦截器(HandlerInterceptor.postHandle())
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 9. 处理结果(视图渲染 / 异常处理)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} finally {
// 10. 触发完成拦截器(HandlerInterceptor.afterCompletion())
if (mappedHandler != null && !asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
// 11. 清理 multipart
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}2.2 getHandler() — 获取处理器
java
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 遍历所有 HandlerMapping(有序 List)
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
// RequestMappingHandlerMapping.getHandlerInternal()
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 1. 获取请求路径
String lookupPath = initLookupPath(request);
// 2. 从 mappingRegistry 匹配 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
// mappingRegistry 结构(初始化时扫描所有 @RequestMapping 构建)
// {
// "/api/orders/{id}" → OrderController.getOrder()
// "/api/orders" → OrderController.createOrder()
// "/api/users/{id}" → UserController.getUser()
// }2.3 getHandlerAdapter() — 获取适配器
java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 遍历 HandlerAdapter,找到支持该处理器的
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler");
}2.4 调用 Controller
java
// RequestMappingHandlerAdapter.handleInternal()
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 检查 Session 是否需要
checkRequest(request);
// 是否同步锁执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
return mav;
}
// invokeHandlerMethod() — 核心
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 创建 ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 创建 InvocableHandlerMethod(可调用的处理器方法)
InvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数解析器(@RequestParam / @PathVariable / @RequestBody 等)
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
// 设置返回值处理器(ModelAndView / ResponseEntity / String 等)
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
// 创建 ModelAndViewContainer
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 执行方法!
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 获取返回值 ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}2.5 参数绑定
java
// InvocableHandlerMethod.invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取方法参数值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 处理返回值
setResponseStatus(webRequest);
if (returnValue == null) {
// 方法返回 void 或标记了 @ResponseStatus
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (!hasRequestHandled(returnValue)) {
// 处理返回值(视图解析 / 消息转换)
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
// invokeForRequest() — 参数绑定
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 解析所有方法参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// 调用方法
return doInvoke(args);
}
// 参数解析器链示例:
// @PathVariable → PathVariableMethodArgumentResolver
// @RequestParam → RequestParamMethodArgumentResolver
// @RequestBody → RequestResponseBodyMethodProcessor
// @ModelAttribute → ModelAttributeMethodProcessor
// @RequestHeader → RequestHeaderMethodArgumentResolver
// @CookieValue → ServletCookieValueMethodArgumentResolver
// HttpServletRequest → ServletRequestMethodArgumentResolver
// Principal / UserDetails → AuthenticationPrincipalArgumentResolver三、Spring Security 与 MVC 集成
3.1 DelegatingFilterProxy — 桥接
java
// Spring Security 通过 DelegatingFilterProxy 注册到 Servlet 容器
// FilterChain 中实际是 DelegatingFilterProxy,它委托给 Spring 管理的 Filter
// web.xml 或 Spring Boot 自动注册
// springSecurityFilterChain → SecurityFilterChain
public class DelegatingFilterProxy extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 委托给 Spring 管理的 Filter
Filter delegate = getDelegate();
delegate.doFilter(request, response, filterChain);
}
}3.2 SecurityFilterChain 执行
java
// FilterChainProxy — 安全过滤器链的入口
// 包装多个 SecurityFilterChain
public class FilterChainProxy extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 1. 获取匹配的 SecurityFilterChain
List<Filter> filters = getFilters(request);
if (filters == null || filters.isEmpty()) {
// 没有安全过滤链 → 直接放行
chain.doFilter(request, response);
return;
}
// 2. 创建虚拟过滤器链并执行
VirtualFilterChain vfc = new VirtualFilterChain(chain, filters);
vfc.doFilter(request, response);
}
}3.3 ExceptionTranslationFilter
java
// ExceptionTranslationFilter — 异常转换(AuthenticationException / AccessDeniedException)
public class ExceptionTranslationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
// 1. 获取 SecurityException
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
RuntimeException securityException = null;
// 2. 检查是否认证异常
AuthenticationException authException = findAuthenticationException(causeChain);
if (authException != null) {
securityException = authException;
// 认证失败 → 触发 AuthenticationEntryPoint(重定向到登录页 / 401)
sendStartAuthentication(request, response, chain, authException);
}
// 3. 检查是否权限异常
AccessDeniedException accessDeniedException = findAccessDeniedException(causeChain);
if (accessDeniedException != null) {
securityException = accessDeniedException;
// 权限不足 → 触发 AccessDeniedHandler(403 / 错误页面)
accessDeniedHandler.handle(request, response, accessDeniedException);
}
if (securityException == null) {
// 不是安全异常 → 继续抛出
rethrow(ex);
}
}
}
}3.4 FilterSecurityInterceptor
java
// FilterSecurityInterceptor — 最后的权限校验
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
// 1. 检查是否已认证
Authentication authenticated = SecurityContextHolder.getContext().getAuthentication();
// 2. 权限验证
// 调用 AccessDecisionManager.decide() 或 AuthorizationManager.check()
// 根据配置的规则(.antMatchers("/admin/**").hasRole("ADMIN"))判断
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
// 3. 放行到 Servlet(进入 DispatcherServlet)
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, null);
}
}四、视图解析
4.1 processDispatchResult()
java
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler,
@Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
// 1. 异常处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 调用 HandlerExceptionResolver(@ExceptionHandler 在此处理)
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 2. 渲染视图
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
// 3. 触发完成拦截器
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}4.2 render() — 视图渲染
java
protected void render(ModelAndView mv, HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 1. 解析视图(ViewResolver)
View view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view");
}
// 2. 渲染视图
view.render(mv.getModelInternal(), request, response);
}五、总结
| 阶段 | 关键组件 | 核心方法 |
|---|---|---|
| Filter 链 | DelegatingFilterProxy | doFilter() |
| Security 链 | FilterChainProxy | doFilter() |
| Security 认证 | UsernamePasswordAuthenticationFilter | attemptAuthentication() |
| Security 授权 | FilterSecurityInterceptor | beforeInvocation() |
| Security 异常 | ExceptionTranslationFilter | handleSpringSecurityException() |
| MVC 入口 | DispatcherServlet | doDispatch() |
| Handler 匹配 | RequestMappingHandlerMapping | getHandlerInternal() |
| 参数绑定 | RequestMappingHandlerAdapter | invokeHandlerMethod() |
| 视图解析 | ViewResolver | resolveViewName() |
参考链接: