# 概述
Spring框架提供的构建WEB应用程序的全功能MVC模块.
# MVC框架
- 一种软件编程模式,M代表业务模型,V指用户界面,C则是控制器。
- MVC框架的目的是将M和V的实现代码分离,控制器则负责确保M和V的同步,一旦M改变,V同步更新;
# 源码
# 架构设计
- HandlerMapping
/*xxx: springMvc的九大组件之一*/
/*xxx: 用于查找 Handler的,springMVC会处理很多请求,具体的某一个请求才以哦那个哪个 Handler处理,需要使用该类来处理*/
public interface HandlerMapping {
@Nullable
/*xxx: 只有提供了一个抽象方法*/
/*xxx: 获取处理器,但是实际返回的是 处理器执行链*/
/*xxx: 能否返回处理器执行链,取决于当前所采用的策略*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
- Handler(逻辑存在)
/*xxx: 处理器过滤链*/
public class HandlerExecutionChain {
/*xxx: handler是一个对象,只要能够实际处理请求的 ,就是handler,可以是类,也可以是方法,也可以是其它*/
private final Object handler;
/*xxx: 处理器拦截器*/
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
}
- HandlerAdapter
/*xxx: springMVC的 九大组件之一*/
/*xxx: 用它的原因是因为: springMVC中,并没有对Handler做任何限制*/
public interface HandlerAdapter {
/*xxx: 执行具体的Handler方法*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
- ModelAndView
/*xxx: 业务逻辑与视图映射关系*/
public class ModelAndView {
/*xxx: 与处理器类似,没有对 view 做限制 */
private Object view;
private ModelMap model;
}
- ViewResolver
/*xxx: springMVC九大组件之一*/
/*xxx: 用来将 String类型的视图名 和 Locale 解析为 View类型的视图*/
public interface ViewResolver {
/*xxx: 将String类型的视图名,解析为实际的视图*/
/*xxx: 它主要处理两个问题: 1.使用什么模板 2.采用什么技术填入参数*/
View resolveViewName(String viewName, Locale locale) throws Exception;
}
- View
/*xxx: 抽象视图*/
public interface View {
/*xxx: 渲染,实际上是将相应的解析结果,输出到response中*/
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
# 流程设计
# 装载基础设施
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
/*xxx: 在服务器容器启动后,将会自动初始化 (init-param 设置为非负数,或者没设 在context完成后,会自动执行初始化)*/
/*xxx: 装载servlet时,会初始化上下文*/
public final void init() throws ServletException {
/*xxx: 模板方法,子类初始化的入口方法*/
initServletBean();
}
protected void initServletBean() throws ServletException {
}
}
/*xxx: 该方法重写了 除了 doHead外的所有方法,所以 本质上 是侵入了Servlet规范的*/
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected final void initServletBean() throws ServletException {
/*xxx: 初始化 WebApplicationContext*/
/*xxx: 初始化上下文时,分为两类,一类是springboot,通过外部设置进来,一类是spring,通过实例化上下文进行初始化*/
this.webApplicationContext = initWebApplicationContext();
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext wac = null;
/*xxx: 如果已经通过构造方法设置了 webApplicationContext*/
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
}
if (wac == null) {
/*xxx: 当 webAppicationContext 已经存在 ServletContext中时,通过配置在 Servlet中的 contextAttribute参数获取*/
wac = findWebApplicationContext();
}
if (wac == null) {
/*xxx: 如果 webApplicationContext还没有创建,则创建一个*/
/*xxx: 正常情况下,就是走这个分支*/
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
/*xxx: 当ContextRefreshedEvent事件没有触发时,调用此方法,为模板方法*/
onRefresh(wac);
}
}
}
/*xxx: 表示已经调用过 refresh方法*/
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
synchronized (this.onRefreshMonitor) {
onRefresh(event.getApplicationContext());
}
}
protected void onRefresh(ApplicationContext context) {
}
}
public class DispatcherServlet extends FrameworkServlet {
@Override
/*xxx: 该方法 是 DispatcherServlet 的入口方法*/
protected void onRefresh(ApplicationContext context) {
/*xxx: 初始化9个组件*/
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
/*xxx: 4.handlerMapping组件*/
initHandlerMappings(context);
/*xxx: 5.handlerAdapter组件*/
initHandlerAdapters(context);
/*xxx: 8.viewResolver组件*/
initViewResolvers(context);
}
/*xxx: 初始化组件策略*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
/*xxx: 从上下文中获取 handlerMapping,分为按类型获取多个,以及按名称获取单个*/
/*xxx: 代码,略*/
/*xxx: 上下文中,没有相应实现,则采用默认策略*/
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}
}
# 正常运行逻辑
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*xxx: 处理请求的处理器链(包含处理器 和对应的 Interceptor)*/
HandlerExecutionChain mappedHandler = null;
try {
/*xxx: 封装 Model 和 View 的容器*/
ModelAndView mv = null;
/*xxx: 根据 request 找到 handler*/
mappedHandler = getHandler(processedRequest);
/*xxx: 根据handler找到 handlerAdapter*/
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
/*xxx: 执行 相应 Interceptor 的 preHandle*/
/*xxx: 前置拦截 */
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/*xxx: 用 handlerAdapter 处理 handler*/
/*xxx: controller 便是在此处执行的*/
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
/*xxx: 执行 相应 Interceptor 的 postHandle*/
/*xxx: 后置拦截*/
mappedHandler.applyPostHandle(processedRequest, response, mv);
/*xxx: 处理上面处理之后的结果 (包括 处理异常,渲染页面,发出完成通知触发 Interceptor 的 afterCompletion)*/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}catch (Exception e){
}
}
/*xxx: 需要注意,HandlerMapping 具有优先级关系*/
/*xxx: 在前的优先*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
/*xxx: handlerAdapter也具有优先级关系*/
/*xxx: 在前的优先 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
/*xxx: 处理分发结果 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
/*xxx: 渲染页面,具体在 render方法中执行*/
render(mv, request, response);
/*xxx: 发出请求处理完成的通知,触发 Interceptor 的 afterCompletion*/
mappedHandler.triggerAfterCompletion(request, response, null);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
/*xxx: viewResolvers 也具有优先级关系*/
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
/*xxx: 使用 viewResolver进行渲染*/
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
}
# 无视图返回逻辑
public class DispatcherServlet extends FrameworkServlet {
/*xxx: 处理分发结果 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
/*xxx: 渲染页面*/
/*xxx: 当采用 @RestController,或者 @ResponseBody时,无视图返回,不进行渲染逻辑*/
if (mv != null && !mv.wasCleared()) {
/*xxx: 渲染页面,具体在 render方法中执行*/
render(mv, request, response);
}
/*xxx: 发出请求处理完成的通知,触发 Interceptor 的 afterCompletion*/
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
# 视图返回逻辑
public class DispatcherServlet extends FrameworkServlet {
/*xxx: 处理分发结果 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
/*xxx: 渲染页面*/
if (mv != null && !mv.wasCleared()) {
/*xxx: 渲染页面,具体在 render方法中执行*/
render(mv, request, response);
}
/*xxx: 发出请求处理完成的通知,触发 Interceptor 的 afterCompletion*/
mappedHandler.triggerAfterCompletion(request, response, null);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
if (viewName != null) {
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
}
}
/*xxx: viewResolvers 也具有优先级关系*/
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
/*xxx: 使用 viewResolver进行渲染*/
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
}
# 视图重定向逻辑
/*xxx: 可用于解析 jsp视图*/
public class InternalResourceViewResolver extends UrlBasedViewResolver {
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
return view;
}
}
public class InternalResourceView extends AbstractUrlBasedView {
@Override
/*xxx: 将逻辑视图的数据进行融合为实际的视图*/
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
/*xxx: 获取分发视图的路径*/
String dispatcherPath = prepareForRendering(request, response);
/*xxx: 构造视图请求分发器*/
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
rd.forward(request, response);
}
}
final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher {
public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
this.doForward(request, response);
}
private void doForward(ServletRequest request, ServletResponse response) throws ServletException, IOException {
this.processRequest(request, response, state);
}
private void processRequest(ServletRequest request, ServletResponse response, ApplicationDispatcher.State state) throws IOException, ServletException {
this.invoke(state.outerRequest, response, state);
}
private void invoke(ServletRequest request, ServletResponse response, ApplicationDispatcher.State state) throws IOException, ServletException {
Servlet servlet = null;
servlet = this.wrapper.allocate();
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, this.wrapper, servlet);
filterChain.doFilter(request, response);
}
}
# 实践
# 在spring环境中的应用
- 通过xml方式加载Servlet组件
<xml>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</xml>
# 在springBoot环境中的应用
public class DispatcherServletAutoConfiguration {
protected static class DispatcherServletRegistrationConfiguration {
@Bean(
name = {"dispatcherServletRegistration"}
)
@ConditionalOnBean(
value = {DispatcherServlet.class},
name = {"dispatcherServlet"}
)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
registration.setName("dispatcherServlet");
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}
protected static class DispatcherServletConfiguration {
@Bean(
name = {"dispatcherServlet"}
)
public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
return dispatcherServlet;
}
}
}
# 三个初始化器
/*xxx: 由spring-web提供,与 ServletContainerInitializer 搭配使用*/
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
/*xxx: 由springWeb提供的容器初始化器*/
/*xxx: 在springWebmvc模块的 services,将该类进行了注册,由tomcat容器的 SPI机制进行生效 */
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new ArrayList<>(webAppInitializerClasses.size());
for (Class<?> waiClass : webAppInitializerClasses) {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
List<WebApplicationInitializer> initializers = Collections.emptyList();
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
/*xxx: spi机制生效节选*/
public class ContextConfig implements LifecycleListener {
protected void processServletContainerInitializers() {
List<ServletContainerInitializer> detectedScis;
WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
detectedScis = loader.load(ServletContainerInitializer.class);
/*xxx: 省略其它抽象...*/
}
}
public class WebappServiceLoader<T> {
private static final String CLASSES = "/WEB-INF/classes/";
private static final String LIB = "/WEB-INF/lib/";
private static final String SERVICES = "META-INF/services/";
public List<T> load(Class<T> serviceType) throws IOException {
String configFile = SERVICES + serviceType.getName();
ClassLoader loader = context.getParentClassLoader();
Enumeration<URL> containerResources;
if (loader == null) {
containerResources = ClassLoader.getSystemResources(configFile);
} else {
containerResources = loader.getResources(configFile);
}
/*xxx: 省略其它抽象...*/
}
}
/*xxx: 由springBoot提供,与 ServletContainerInitializer 搭配使用*/
public interface ServletContextInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
/*xxx: 由springBoot提供的,内置tomcat的唯一容器类型初始化器*/
final class TomcatStarter implements ServletContainerInitializer {
private final ServletContextInitializer[] initializers;
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
for (ServletContextInitializer initializer : this.initializers) {
initializer.onStartup(servletContext);
}
}
}
/*xxx: servlet容器初始化器,由servlet规范提供*/
public interface ServletContainerInitializer {
/*xxx: @HandlesTypes,由servelt规范提供*/
void onStartup(Set<Class<?>> annotatedByHandlesTypes, ServletContext servletContext) throws ServletException;
}
需要注册原生servlet上下文原生组件时,需要采用此方法,通过ServletWebServerApplication完成装载
更多内容详见: tomcat学习笔记-内置tomcat如何装载Servlet,Filter和Listener
# springMvc的详细流程
# HandlerMapping结构
/*xxx: springMvc的九大组件之一*/
/*xxx: 用于查找 Handler的,springMVC会处理很多请求,具体的某一个请求才以哦那个哪个 Handler处理,需要使用该类来处理*/
public interface HandlerMapping {
/*xxx: 获取处理器,但是实际返回的是 处理器执行链*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
/*xxx: 用于配置 springMVC的拦截器*/
private final List<Object> interceptors = new ArrayList<>();
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
/*xxx: 模板方法,留给子类实现,也是子类主要做的事*/
Object handler = getHandlerInternal(request);
if (handler == null) {
/*xxx: 没有获取到,则使用默认的 Handler*/
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
/*xxx: 如果找到的是 String 类型,则去 MVC的容器里面查找对应的Bean */
handler = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
//xxx: 如果是cors的检查请求,则会进行处理
CorsConfiguration config = getCorsConfiguration(handler, request);
//xxx: 省略其它抽象...
//xxx: 跨域检查请求与常规的请求,是相互独立的控制器
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//xxx: 将匹配的拦截器与控制器进行组装,略...
}
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
//xxx: 将cors的拦截器 CorsInterceptor加入列表,略...
}
/*xxx: 获取处理器*/
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
}
/*xxx: 该 系列,将Method 作为Handler来使用*/
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
//xxx: 映射存储器
private final MappingRegistry mappingRegistry = new MappingRegistry();
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
/*xxx: 根据获取路径*/
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
/*xxx: 通过路径和请求 找到HandlerMethod*/
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
/*xxx: 如果找到了Handler,则使用 createWithResolvedBean 创建新的 HandlerMethod并返回*/
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
//xxx:根据匹配规则,获取到控制器,略...
//xxx: 否则返空
}
}
/*xxx: 基于控制器的具体实现*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
implements MatchableHandlerMapping, EmbeddedValueResolverAware {
}
# 映射器的存储
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
@Override
public void afterPropertiesSet() {
/*xxx: 调用 initHandlerMethods,从spring容器中获取符合条件的bean,进行装配*/
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
/*xxx: 处理 controller类*/
processCandidateBean(beanName);
}
}
/*xxx: 将@Controller 或 @RequestMapping的注解给提出来进行注册*/
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = obtainApplicationContext().getType(beanName);
if (beanType != null && isHandler(beanType)) {
/*xxx: 从controller中,将方法提出来*/
detectHandlerMethods(beanName);
}
}
/*xxx: 判断某个类是否是控制器*/
protected abstract boolean isHandler(Class<?> beanType);
/*xxx: 根据方法的映射,返回泛型控制器*/
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
protected void detectHandlerMethods(Object handler) {
/*xxx: 获取Handler的类型*/
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
/*xxx: 获取当前bean里面,所有符合Handler要求的Method*/
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
/*xxx: 符合要求的method注册起来*/
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
/*xxx: 将映射路径存储到注册表中*/
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
}
# 映射器注册表
class MappingRegistry {
//xxx: 注册表
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
//xxx: 路径查找表
private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
//xxx: 名称查找表
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
//xxx: cors查找表
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
//xxx: 注册控制器信息
public void register(T mapping, Object handler, Method method) {
/*xxx:根据处理器, 创建 HandlerMethod*/
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
/*xxx: 同时验证 HandlerMethod的合法性,如果重复,则会抛出错误*/
validateMethodMapping(handlerMethod, mapping);
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
//xxx: 更新查找表
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
//xxx: 更新名称表
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
/*xxx: 注册新的 HandlerMethod*/
addMappingName(name, handlerMethod);
}
//xxx: 更新映射信息
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name));
}
}
# HandlerMethod的结构
/*xxx: 用于封装Handler 和其中 具体处理请求的 Method,分别对应其中的bean 和 method属性*/
public class HandlerMethod {
/*xxx: 实际的handler,为一个bean*/
private final Object bean;
/*xxx: 需要执行的方法*/
private final Method method;
//xxx: 省略其它抽象...
}
public class InvocableHandlerMethod extends HandlerMethod {
@Nullable
/*xxx: 可以创建WebDataBinder,用于参数解析器 ArgumentResolver中*/
private WebDataBinderFactory dataBinderFactory;
/*xxx: 用于解析参数*/
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
/*xxx: 用来获取参数名, 用于 MethodParameter中*/
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*xxx: 准备方法所需要的参数*/
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
/*xxx: 具体调用Method,我们写的方法都是通过该方法来执行的*/
return doInvoke(args);
}
@Nullable
protected Object doInvoke(Object... args) throws Exception {
/*xxx: 通过反射,调用bean的对应方法*/
return getBridgedMethod().invoke(getBean(), args);
}
/*xxx: 参数绑定的方法*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*xxx: 获取方法的参数,在HandlerMethod中*/
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
/*xxx: 用于保存解析出参数的值*/
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
/*xxx: 给parameter设置参数名解析器*/
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
/*xxx: 如果相应类型的参数 已经在proivdedArgs中提供了,则直接设置到 parameter*/
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
/*xxx: 使用 argumentResolvers解析参数*/
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
//xxx: 抛错,略...
}
}
return args;
}
}
/*xxx: 一种Handler,增加了 方法执行,参数解析,返回值处理等功能*/
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*xxx: 首先调用父类,执行请求*/
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
/*xxx: 接着 处理 @ResponseStatus 注释,设置http状态码*/
setResponseStatus(webRequest);
/*xxx: 最后处理返回值*/
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
/*xxx: 如果 request的notModified为真, @ResponseStatus存在,或者 mavContainer的requestandled为true,
则设置为请求已经处理,并返回*/
//xxx: 将不再进行视图的渲染等操作
mavContainer.setRequestHandled(true);
return;
}
}
/*xxx: 使用returnValueHandlers 处理返回值*/
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
# HandlerAdapter的结构
/*xxx: springMVC的 九大组件之一*/
/*xxx: 用它的原因是因为: springMVC中,并没有对Handler做任何限制*/
public interface HandlerAdapter {
/*xxx: 判断是否支持处理某个 Handler*/
boolean supports(Object handler);
/*xxx: 执行具体的Handler方法*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
public final boolean supports(Object handler) {
/*xxx: 在handler必须是 HandlerMethod的子类 */
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//xxx: 子类处理
return handleInternal(request, response, (HandlerMethod) handler);
}
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
}
/*xxx: springMVC中,最复杂的组件*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//xxx: 基于控制器的方法执行时,不论返回值是多少,都会被处理成 ModelAndView
//xxx: springMvc的返回值,与方法的返回值,不是同一个概念
ModelAndView mav;
/*xxx: 如果当前的session需要同步,则加锁*/
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
/*xxx: 加锁同步执行*/
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
/*xxx: 没有session,则直接运行*/
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
/*xxx: 没有同步要求,也是直接运行*/
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
/*xxx: 具体执行请求的处理*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//xxx: 实际的处理方法,springMvc控制器执行的核心,见下文
}
}
# 适配器的初始化
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
public void afterPropertiesSet() {
/*xxx: 初始化 注释了 @ControllerAdvice的类的相关属性*/
initControllerAdviceCache();
/*xxx: 用于给处理器方法 和 注释了 @ModelAttribute的方法设置参数*/
if (this.argumentResolvers == null) {
/*xxx: 获取默认的 参数解析器*/
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
/*xxx: 用于 给 注释了 @initBinder的方法设置参数*/
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
/*xxx: 用于 将 处理器的返回值 处理成 ModelAndView的类型*/
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
//xxx: 省略其它抽象...
/*xxx: 缓存 @ControllerAdvice注释的类里面 注释了 @ModelAttribute 的方法*/
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
/*xxx: 缓存 @ControllerAdvice注释的类里面 注释了 @InitBinder 的方法*/
this.initBinderAdviceCache.put(adviceBean, binderMethods);
/*xxx: 表明@RequestAdvice注解的类,具有最高优先级*/
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
/*xxx:添加基于注解解析参数的 解析器*/
/*xxx: @RequestParam 注解*/
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
/*xxx: 多个@RequestParam 注解*/
resolvers.add(new RequestParamMapMethodArgumentResolver());
/*xxx: @PathVariable 注解*/
resolvers.add(new PathVariableMethodArgumentResolver());
/*xxx: 多个 @PathVariable 注解*/
resolvers.add(new PathVariableMapMethodArgumentResolver());
/*xxx: @MatrixVariable 注解*/
resolvers.add(new MatrixVariableMethodArgumentResolver());
/*xxx: 多个 @MatrixVariable 注解*/
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
/*xxx: @ModelAttribute注解*/
resolvers.add(new ServletModelAttributeMethodProcessor(false));
/*xxx: @RequestBody @ResponseBody 注解处理*/
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
/*xxx: @RequestPart 注解*/
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
/*xxx: @RequestHeader注解*/
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
/*xxx: 多个 @RequestHeader 注解*/
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
/*xxx: @CookieValue 注解*/
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
/*xxx: @Value注解,它是spring工厂的注解*/
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
/*xxx: @SessionAttribute注解处理*/
resolvers.add(new SessionAttributeMethodArgumentResolver());
/*xxx: @RequestAttribute注解*/
resolvers.add(new RequestAttributeMethodArgumentResolver());
/*xxx: 基于 类型解析参数的解析器*/
/*xxx: 请求时 处理这些原生类型:
WebRequest,
ServletRequest,
MultipartRequest,
HttpSession,
Principle,
InputStream,
Reader,
HttpMethod.
Locale,
TimeZone,
ZoneId
*/
resolvers.add(new ServletRequestMethodArgumentResolver());
/*xxx: 响应时,处理这些原生类型:
* ServletResponse,
* OutputStream,
* Writer
* */
resolvers.add(new ServletResponseMethodArgumentResolver());
/*xxx: 处理 HttpEntity,RequestEntity*/
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
/*xxx: 处理 RedirectAttributes 类型*/
resolvers.add(new RedirectAttributesMethodArgumentResolver());
/*xxx: 处理 Model类型*/
resolvers.add(new ModelMethodProcessor());
/*xxx: 处理 Map类型,并且没有注解*/
resolvers.add(new MapMethodProcessor());
/*xxx: 处理 Errors类型(spring-context 的 validation包下的)*/
resolvers.add(new ErrorsMethodArgumentResolver());
/*xxx: 处理 SessionStatus类型*/
resolvers.add(new SessionStatusMethodArgumentResolver());
/*xxx: 处理 UriComponentsBuilder 和 ServletUriComponentBuilder类型*/
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
/*xxx: 添加自定义参数解析器,用于解析自定义类型*/
/*xxx: 自定义解析器,是在 基于注解 和类型 参数解析器都无法解析的时候,才会用到*/
/*xxx: 该顺序是固定的,无法改变*/
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
/*xxx: 这两个解析器,可以解析所有类型的参数*/
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
/*xxx: @InitBinder使用的参数解析器*/
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
/*xxx: 返回值参数处理器*/
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
/*xxx: 方法返回值为ModelAndView的处理 */
handlers.add(new ModelAndViewMethodReturnValueHandler());
/*xxx: 方法返回值为 Model 处理 */
handlers.add(new ModelMethodProcessor());
/*xxx: 方法返回值为 View 的处理 */
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
/*xxx: 方法返回值为 StreamingResponseBody 的处理 */
handlers.add(new StreamingResponseBodyReturnValueHandler());
/*xxx: 方法返回值为 httpEntity的处理*/
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
/*xxx: 方法返回值 为 HttpHeader 的处理*/
handlers.add(new HttpHeadersReturnValueHandler());
/*xxx: 方法返回值 为 Callable 的处理 */
handlers.add(new CallableMethodReturnValueHandler());
/*xxx: 方法返回值为 DeferredResult 的处理 */
handlers.add(new DeferredResultMethodReturnValueHandler());
/*xxx: 方法返回值为 WebAsyncTask 的处理*/
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
handlers.add(new ServletModelAttributeMethodProcessor(false));
/*xxx: 注释了@Response返回值处理*/
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
/*xxx: 返回值为 void 或者 String时的处理*/
handlers.add(new ViewNameMethodReturnValueHandler());
/*xxx: 返回值为 Map的处理, 同时也可处理 Map类型 的参数*/
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
/*xxx: 全局返回值处理,其它处理器都没处理时,进行处理*/
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ServletModelAttributeMethodProcessor(true));
}
return handlers;
}
}
# 适配器的执行流程
/*xxx: springMVC中,最复杂的组件*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
/*xxx: 具体执行请求的处理*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
/*xxx: 使用 request 和 response 创建了 ServletWebRRequest类型的 webRequest*/
ServletWebRequest webRequest = new ServletWebRequest(request, response);
/*xxx: 用于参数绑定,主要功能就是 实现参数 跟 String 之间的类型转换*/
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
/*xxx: 用来处理Model, 1.用于在处理器具体处理之前,对Model进行初始化 2.处理完请求后,对Model参数进行更新*/
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
/*xxx: 该类型非常重要, 继承自 HandlerMethod,并且可以直接执行*/
/*xxx: 实际请求的处理 就是通过它来执行的*/
/*xxx: 参数绑定,处理请求 以及 返回值处理,都在这里完成*/
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
/*xxx: 设置参数解析器*/
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
/*xxx: 设置返回值处理器*/
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
/*xxx: 设置参数绑定工厂*/
invocableMethod.setDataBinderFactory(binderFactory);
/*xxx: 设置parameterNameDiscoverer*/
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
/*xxx: 新建ModelAndViewContainer,用于保存 Model 和 View,它贯穿整个处理过程*/
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
/*xxx: 将FlashMap中的数据,设置到Model*/
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
/*xxx: 使用modelFactory 将 sessionAttributes 和 注释了 @ModelAttribute的方法的参数设置到Model*/
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
/*xxx: 根据配置,对 ignoreDefaultModelOnRedirect进行设置*/
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
/*xxx: 绑定参数的数据来源:
* request中参数(url,post请求体,请求头), cookie,session -> 通过request管理
* FlashMap中的参数(主要用于redirect的参数传递),sessionAttributes传递的参数,@ModelAttribute设置的参数 -> Model管理
* 其中,前三类 直接在request获取,不用过多准备工作
* 第四类: FlashMap 直接在 RequestMappingHandlerAdapter处理,请求前 设置到Model中,请求后则视情况将值设置到 FlashMap
* sessionAttributes,ModelAttribute 使用ModelFactory管理
* */
//xxx: 省略其它抽象...
/*xxx: 执行请求*/
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
}
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
/*xxx: 更新Model,包括设置 SessionAttributes 和 给Model 设置 BindingResult*/
modelFactory.updateModel(webRequest, mavContainer);
/*xxx: 根据mavContainer创建 ModelAndView */
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
/*xxx: 如果 mavContainer里的Model是 RedirectAttributes类型,则将其设置到 FlashMap*/
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
}
# 控制器关键流程
# 参数解析
public class InvocableHandlerMethod extends HandlerMethod {
/*xxx: 用于解析参数*/
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
/*xxx: 参数绑定的方法*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*xxx: 获取方法的参数信息,在HandlerMethod中*/
MethodParameter[] parameters = getMethodParameters();
/*xxx: 用于保存解析出参数的值*/
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
/*xxx: 给parameter设置参数名解析器*/
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
/*xxx: 如果相应类型的参数 已经在proivdedArgs中提供了,则直接设置到 parameter*/
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
/*xxx: 使用 argumentResolvers解析参数*/
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
throw ex;
}
}
return args;
}
}
public interface HandlerMethodArgumentResolver {
/*xxx: 用于判断是否支持传入参数的解析*/
boolean supportsParameter(MethodParameter parameter);
/*xxx: 用于实际解析参数*/
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
/*xxx: 参数解析器*/
private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
/*xxx:解析参数 */
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
/*xxx: 使用 HttpMessageConverter解析 request body 类型参数的基类*/
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {
//xxx: 消息转换器
protected final List<HttpMessageConverter<?>> messageConverters;
/*xxx: 读取消息*/
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
/*xxx: 消息类型*/
MediaType contentType;
/*xxx: 如果没有获取到消息类型,则默认使用 octet_stream作为消息类型*/
contentType = MediaType.APPLICATION_OCTET_STREAM;
/*xxx: 遍历消息转换器进行处理*/
for (HttpMessageConverter<?> converter : this.messageConverters) {
/*xxx: 通过指定类型,确定消息转换器是否能读取*/
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
/*xxx: 消息体读取前置操作*/
HttpInputMessage msgToUse =getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
/*xxx: 消息体读取后置操作*/
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
}
return body;
}
}
/*xxx: 解析注释了 @RequestBody 和 @ResponseBody的参数*/
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
/*xxx: 通过消息转换器读取参数 */
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
/*xxx: 从request中读取参数 */
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
/*xxx: 如果参数是必填项,则抛错*/
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}
/*xxx: 解析参数*/
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
/*xxx: 读取到参数的结果*/
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
return arg;
}
}
/*xxx: http消息转换器*/
public interface HttpMessageConverter<T> {
/*xxx: 是否可读取*/
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
//xxx: 是否可写入
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
/*xxx: 读取*/
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/*xxx: 写入*/
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T> {
boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType);
T read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType);
void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
/*xxx: 消息转换器抽象类 */
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
implements GenericHttpMessageConverter<T> {
/*xxx: 写入消息*/
public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,
HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
/*xxx: 设置响应头信息*/
final HttpHeaders headers = outputMessage.getHeaders();
addDefaultHeaders(headers, t, contentType);
//xxx: 写入消息,并刷新缓存
writeInternal(t, type, outputMessage);
outputMessage.getBody().flush();
}
/*xxx: 写入*/
protected abstract void writeInternal(T t, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
/*xxx: 基于jackson的实现*/
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
/*xxx: jackson的转换器*/
protected ObjectMapper objectMapper;
@Override
/*xxx: 读取参数 */
public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}
/*xxx: 读取为java类*/
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
}
/*xxx: 写入json信息*/
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
//xxx: 省略其它抽象...
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
ObjectWriter objectWriter = (serializationView != null ?
this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
//xxx: 写入json信息
objectWriter.writeValue(generator, value);
}
}
public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
private String jsonPrefix;
protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
if (this.jsonPrefix != null) {
generator.writeRaw(this.jsonPrefix);
}
}
}
# @RequestBody参数切面
/*xxx: 参数切面*/
/*xxx: 作用域 使用了 @ControllerAdvice 并且 实现了 @RequestBodyAdvice 的类*/
public interface RequestBodyAdvice {
/*xxx: 是否支持当前参数*/
boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType);
/*xxx: 读取参数前处理*/
HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;
/*xxx: 读取参数后处理*/
Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
/*xxx: 空实体处理*/
Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
}
# 返回值处理
public interface HandlerMethodReturnValueHandler {
/*xxx: 是否支持返回值解析*/
boolean supportsReturnType(MethodParameter returnType);
/*xxx: 处理返回值*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
/*xxx: 处理返回值为void ,或者为 String的参数*/
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
/*xxx: 如果返回值为String,则将其设置到 mavContainer的view中*/
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
//xxx: void返回值,实际上什么也没处理
}
/*xxx: 是否是重定向视图*/
protected boolean isRedirectViewName(String viewName) {
return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName) || viewName.startsWith("redirect:"));
}
}
- 写出消息的两类实现
/*xxx: 返回资源信息*/
public class ResourceHttpRequestHandler extends WebContentGenerator
implements HttpRequestHandler, EmbeddedValueResolverAware, InitializingBean, CorsConfigurationSource {
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//xxx: 省略抽象...
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
}
}
/*xxx: 解析注释了 @RequestBody 和 @ResponseBody的参数*/
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
/*xxx: 设置该参数后,将不再进行 viewResolver的步骤*/
mavContainer.setRequestHandled(true);
/*xxx: responseBodyAdvice 可以介入处理*/
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//xxx: 省略其它抽象...
for (HttpMessageConverter<?> converter : this.messageConverters) {
//xxx: 类型可写入时,进行处理
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
/*xxx: 写入前处理, responseBodyAdvice*/
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
//xxx: 写入消息
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
}
}
}
# 返回值写出操作委派
/*xxx: 解析注释了 @RequestBody 和 @ResponseBody的参数*/
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
/*xxx: responseBodyAdvice 可以介入处理*/
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
/*xxx: 定义相关工具,不直接解析参数*/
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {
//xxx: 消息转换器
protected final List<HttpMessageConverter<?>> messageConverters;
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
@Nullable List<Object> requestResponseBodyAdvice) {
this.messageConverters = converters;
this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);
}
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
//xxx: 根据解析到的返回值类型 进行处理
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
//xxx: 遍历消息转换器进行处理
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
//xxx: 类型可写入时,进行处理
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
/*xxx: 写入前处理, responseBodyAdvice*/
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
//xxx: 写入消息
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
return;
}
}
}
}
}
/*xxx: springMVC中,最复杂的组件*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
private List<HttpMessageConverter<?>> messageConverters;
}
/*xxx: http消息转换器*/
public interface HttpMessageConverter<T> {
/*xxx: 是否可读取*/
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
//xxx: 是否可写入
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
/*xxx: 读取*/
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/*xxx: 写入*/
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
# @ResponseBody返回值切面
/*xxx: 返回值切面*/
/*xxx: 作用于 注解了 @ControllerAdvice 且 实现了 ResponseBodyAdvice接口的类*/
public interface ResponseBodyAdvice<T> {
/*xxx: 是否支持该参数处理*/
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
/*xxx: 参数写入前的处理*/
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
}
# 控制器增强器
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
}
@Component
public @interface ControllerAdvice {
}
- 作用于所有注解了**@RequestMapping**的方法
- 该类的方法可以使用**@ExceptionHandler**,@InitBinder,@ModelAttribute实现全局功能
@ControllerAdvice
public class GlobalController{
//(1)全局数据绑定
//应用到所有@RequestMapping注解方法
//此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对
@ModelAttribute
public void addUser(Model model) {
model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
}
//(2)全局数据预处理
//应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
//用来设置WebDataBinder
@InitBinder("user")
public void initBinder(WebDataBinder binder) {
}
// (3)全局异常处理
//应用到所有@RequestMapping注解的方法,在其抛出Exception异常时执行
//定义全局异常处理,value属性可以过滤拦截指定异常,此处拦截所有的Exception
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return "error";
}
}
# ModelAndView构建
- 根据返回值,将view的名称设置到
ModelAndViewContainer
中 - 某些返回值处理器,会设置
mavContainer.setRequestHandled(true)
,将阻断后续的流程
# FlushMap参数传递
- RedirectAttributes可传递redirect参数
# Model参数传递
- 使用**@ModelAttribute**
- 作用于方法上,该方法将会在controller每个方法执行前执行;
- 作用于参数定义上,则作为参数的默认初始值,参考 (opens new window)
- 使用**@SessionAttribute**,会将参数暂存在Session中,下次请其时恢复到model中
# 异常处理
# 结构设计
/*xxx: 异常处理器*/
public interface HandlerExceptionResolver {
/*xxx: 从异常中,解析出 ModelAndView*/
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
/*xxx: 允许异常处理的handler*/
private Set<?> mappedHandlers;
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
/*xxx: 判断短期的ExceptionResolver 是否可以解析所传入的处理器抛出的异常,不可以则返回nul,交给其它ExceptionResolver解析*/
if (shouldApplyTo(request, handler)) {
/*xxx: 根据 preventResponseCaching 标识判断 是否给response 设置禁用缓存的属性*/
prepareResponse(ex, response);
/*xxx: 模板方法,留给子类实现*/
ModelAndView result = doResolveException(request, response, handler, ex);
return result;
}
else {
return null;
}
}
/*xxx: 解析异常*/
protected abstract ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}
public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
protected final ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
//xxx: 处理 HandlerMethod的异常
HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null);
return doResolveHandlerMethodException(request, response, handlerMethod, ex);
}
protected abstract ModelAndView doResolveHandlerMethodException(
HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);
}
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
/*xxx: 找到处理异常的方法*/
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
/*xxx: 设置 argumentResolvers 和returnValueHandlers*/
if (this.argumentResolvers != null) {
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
/*xxx: 执行exceptionHandler方法解析异常*/
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
/*xxx: 异常处理,可以看成执行了另外一个 handlerMethod,也会通过返回值处理器继续处理*/
if (mavContainer.isRequestHandled()) {
return new ModelAndView();
}
else {
/*xxx: 保存异常处理的参数信息*/
ModelMap model = mavContainer.getModel();
HttpStatus status = mavContainer.getStatus();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
mav.setViewName(mavContainer.getViewName());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
}
}
# 流程设计
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//xxx: 省略其它抽象... 为该方法的最后一个步骤
/*xxx: 处理上面处理之后的结果 (包括 处理异常,渲染页面,发出完成通知触发 Interceptor 的 afterCompletion)*/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
/*xxx: 处理分发结果 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
/*xxx: 如果请求处理的过程中,有异常抛出,则处理异常*/
//xxx: 为该方法的第一个步骤
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//xxx: 统一异常处理,并未阻断流程
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
//xxx: 省略其它抽象...
}
/*xxx: 处理异常 */
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
/*xxx: 异常处理器进行异常处理 */
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
/*xxx: 链上处理之后,将不再处理*/
if (exMv != null) {
break;
}
}
}
//xxx: 省略其它抽象...
}
}
# 资源处理
# SimpleHandlerMapping结构
/*xxx:采用模板模式,设计了HandlerMapping 实现的整体结构*/
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
@Override
protected void initApplicationContext() throws BeansException {
/*xxx: 模板方法,用于给子类提供一个 添加(或修改) Interceptors的入口*/
extendInterceptors(this.interceptors);
/*xxx: 用于将 springMVC容器 及 父容器中的所有 MappedInterceptor类型的Bean 添加到 mappedInterceptors属性*/
detectMappedInterceptors(this.adaptedInterceptors);
/*xxx: 初始化 Interceptor */
initInterceptors();
}
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
/*xxx: 模板方法,留给子类实现,也是子类主要做的事*/
Object handler = getHandlerInternal(request);
if (handler == null) {
/*xxx: 没有获取到,则使用默认的 Handler*/
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
/*xxx: 如果找到的是 String 类型,则去 MVC的容器里面查找对应的Bean */
handler = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
//xxx: 如果是cors的检查请求,则会进行处理
CorsConfiguration config = getCorsConfiguration(handler, request);
//xxx: 省略其它抽象...
//xxx: 跨域检查请求与常规的请求,是相互独立的控制器
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
/*xxx: 获取处理器*/
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
}
/*xxx: 通过url进行匹配*/
/*xxx: 此系列的原理是 将 url 与对应的 Handler保存在 一个Map中,使用时,则根据url来取Handler*/
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {
/*XXX: 交给了具体的子孙类 去完成*/
private final Map<String, Object> handlerMap = new LinkedHashMap<>();
//xxx: 省略其它抽象...
}
/*xxx: 根据url进行映射 */
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
/*xxx: 定义了一个内部的map*/
private final Map<String, Object> urlMap = new LinkedHashMap<>();
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
/*xxx: 初始化时,将子类的map注册到父类当中*/
registerHandlers(this.urlMap);
}
/*xxx: 初始化时,需要显示指定 url->handler的映射关系*/
public SimpleUrlHandlerMapping(Map<String, ?> urlMap) {
setUrlMap(urlMap);
}
}
# HttpRequestHandlerAdapter结构
/*xxx: 根据 RequestHandler 进行处理的 适配器*/
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/*xxx: 根据请求直接执行*/
((HttpRequestHandler) handler).handleRequest(request, response);
/*xxx: 返回空*/
return null;
}
}
# ResourceHttpRequestHandler结构
/*xxx: 请求直接处理*/
public interface HttpRequestHandler {
/*xxx: 根据请求、响应直接处理*/
void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
/*xxx: web内容生成器*/
public abstract class WebContentGenerator extends WebApplicationObjectSupport {
/*xxx: 检测请求合法性*/
protected final void checkRequest(HttpServletRequest request) throws ServletException {
String method = request.getMethod();
/*xxx: 探测是否支持当前的method类型(get,post,put,delete)*/
/*xxx: supportedMethods 默认为空*/
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
}
/*xxx: 如果需要session,则先检测session是否合法(默认不检测)*/
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
/*xxx: 设置资源缓存特性*/
protected final void prepareResponse(HttpServletResponse response) {
if (this.cacheControl != null) {
/*xxx: 给 response设置缓存过期时间*/
applyCacheControl(response, this.cacheControl);
}
else {
applyCacheSeconds(response, this.cacheSeconds);
}
/*xxx: 将请求的vary请求头,原样返回*/
if (this.varyByRequestHeaders != null) {
for (String value : getVaryRequestHeadersToAdd(response, this.varyByRequestHeaders)) {
response.addHeader("Vary", value);
}
}
}
}
/*xxx: 处理资源请求的处理器 */
public class ResourceHttpRequestHandler extends WebContentGenerator
implements HttpRequestHandler, EmbeddedValueResolverAware, InitializingBean, CorsConfigurationSource {
/*xxx: 抽象资源定位符*/
private final List<Resource> locations = new ArrayList<>(4);
/*xxx: 实际处理请求的方法*/
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*xxx: 获取资源定位符,如果获取失败,则报404*/
Resource resource = getResource(request);
if (resource == null) {
logger.debug("Resource not found");
/*xxx: 获取不到,则抛错*/
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
//xxx: 省略其它抽象...
/*xxx: 检测方法与session是否满足条件*/
checkRequest(request);
/*xxx: 检测资源是否更改过,没更改过则不处理*/
if (isUseLastModified() && new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
logger.trace("Resource not modified");
return;
}
/*xxx: 设置缓存*/
prepareResponse(response);
/*xxx: 设置资源类型*/
MediaType mediaType = getMediaType(request, resource);
//xxx: 省略其它抽象...
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
/*xxx: 通过消息转换器写入资源内容 */
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
//xxx: 写资源的时候,分为分段写入,以及全量写入,状态码分别为: 206 以及
}
@Nullable
protected Resource getResource(HttpServletRequest request) throws IOException {
/*xxx: 该值在父流程中,已经设置好*/
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
//xxx: 省略其它抽象...
/*xxx: 通过资源解析器链解析资源*/
Resource resource = this.resolverChain.resolveResource(request, path, getLocations());
if (resource != null) {
resource = this.transformerChain.transform(request, resource);
}
return resource;
}
}
# ResourceHttpMessageConverter资源转换器结构
/*xxx: http消息转换器*/
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {
/*xxx: 支持的媒体类型列表*/
private List<MediaType> supportedMediaTypes = Collections.emptyList();
@Override
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return readInternal(clazz, inputMessage);
}
protected abstract T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
//xxx: 添加默认头部信息
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
//xxx: 流消息
streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
@Override
public OutputStream getBody() {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}));
}
else {
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
}
}
protected void addDefaultHeaders(HttpHeaders headers, T t, @Nullable MediaType contentType) throws IOException {
//xxx: 设置响应类型,略
//xxx: 设置内容长度
if (headers.getContentLength() < 0 && !headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
Long contentLength = getContentLength(t, headers.getContentType());
if (contentLength != null) {
headers.setContentLength(contentLength);
}
}
}
protected abstract void writeInternal(T t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
/*xxx: 资源消息转换器*/
public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<Resource> {
@Override
protected Resource readInternal(Class<? extends Resource> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
/*xxx: 流工具操作,流没法直接操作,理论上,它由底层硬件控制*/
if (this.supportsReadStreaming && InputStreamResource.class == clazz) {
return new InputStreamResource(inputMessage.getBody()) {
@Override
public String getFilename() {
return inputMessage.getHeaders().getContentDisposition().getFilename();
}
@Override
public long contentLength() throws IOException {
long length = inputMessage.getHeaders().getContentLength();
return (length != -1 ? length : super.contentLength());
}
};
}
else if (Resource.class == clazz || ByteArrayResource.class.isAssignableFrom(clazz)) {
byte[] body = StreamUtils.copyToByteArray(inputMessage.getBody());
return new ByteArrayResource(body) {
@Override
@Nullable
public String getFilename() {
return inputMessage.getHeaders().getContentDisposition().getFilename();
}
};
}
else {
throw new HttpMessageNotReadableException("Unsupported resource class: " + clazz, inputMessage);
}
}
@Override
/*xxx: 写入资源*/
protected void writeInternal(Resource resource, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
writeContent(resource, outputMessage);
}
protected void writeContent(Resource resource, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
try {
InputStream in = resource.getInputStream();
try {
/*xxx: 流拷贝*/
StreamUtils.copy(in, outputMessage.getBody());
}
catch (NullPointerException ex) {
// ignore, see SPR-13620
}
finally {
try {
in.close();
}
catch (Throwable ex) {
// ignore, see SPR-12999
}
}
}
catch (FileNotFoundException ex) {
// ignore, see SPR-12999
}
}
}
# springMvc前端静态资源原理
# springBoot-Mvc自动装配
- 官方的优先级低于用户优先级
- 官方判断条件为
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
# 自动配置的细节
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration {
@Import(EnableWebMvcConfiguration.class)
/*xxx: webMvc的自动配置, configurer配置器,相当于插件化配置 */
//xxx: 主要用于装配相应的属性
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
//略
}
//xxx: webMvc的实际配置项 该类主要配置了 基于 RequestMapping的mvc套件: HandlerMapping,HandlerAdapter
//xxx: 其父类会配置 springMvc的其它机制的套件
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
//xxx: 略
}
}
/*xxx: 为springMvc提供插件化配置的功能*/
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
//略
}
/*xxx: springMvc官方提供的标准配置项*/
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
@SuppressWarnings("deprecation")
/*xxx: 标准配置里面提供该配置,但在springBoot的环境下,会被替换*/
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
//略...
return null;
}
@Bean
/*xxx: 标准配置里面提供该配置,但在springBoot的环境下,会被替换*/
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
//略...
return null;
}
@Bean
@Nullable
/*xxx: 处理资源的 HandlerMapping,本质上为 SimpleUrlHandlerMapping */
public HandlerMapping resourceHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
addResourceHandlers(registry);
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
return handlerMapping;
}
@Bean
/*xxx: 处理资源的 适配器套件 */
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
}
# 生效的HandlerMapping
- SimpleUrlHandlerMapping实现细节,见上文资源处理
# HandlerMapping的默认位置
- 更多内容详见tomcat部分-最佳实践springMVC的结合章节
public class DispatcherServlet extends FrameworkServlet {
/*xxx: 初始化组件策略*/
private void initHandlerMappings(ApplicationContext context) {
/*xxx: 从上下文中获取 handlerMapping,分为按类型获取多个,以及按名称获取单个*/
/*xxx: 该属性默认为开启状态, 即默认情况下,通过类型的方式从容器中获取 handlerMapping*/
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
//xxx: 根据order配置对handlerMapping进行排序, 所有的HandlerMapping都实现了Ordered接口
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
/*xxx: 上下文中,没有相应实现,则采用默认策略*/
//xxx: 默认策略不改动的情况下为: BeanNameUrl,RequestMapping,RouterFunction
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
//xxx: 略...
}
}
}
public class WebMvcConfigurationSupport{
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
//xxx: 略...
return null;
}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping(){
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2);
//略...
return null;
}
@Bean
public RouterFunctionMapping routerFunctionMapping(){
RouterFunctionMapping mapping = new RouterFunctionMapping();
mapping.setOrder(3);
//略
return null;
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(){
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping();
setOrder(2);
//xxx: 略
return null;
}
}
public class WebMvcEndpointManagementContextConfiguration {
void ControllerEndpointHandlerMapping(){
setOrder(-100);
//略
}
}
public class ResourceHandlerRegistry {
//xxx: 该值作为资源处理 处理器 的默认顺序
private int order = Ordered.LOWEST_PRECEDENCE - 1;
}
- RequestMapping的默认位置为0,Resource的默认位置为Ordered.LOWEST_PRECEDENCE-1,这意味着资源请求的处理总是在requestMapping之后完成
- 常见的HandlerMapping都有固定的顺序。RequestMapping顺序默认为0
# springBoot-Mvc的自动配置参数
public class WebMvcAutoConfiguration {
//xxx: webMvc的实际配置项 该类主要配置了 基于 RequestMapping的mvc套件
//xxx: 其父类会配置 springMvc的其它机制的套件
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//xxx: 默认情况下, 识别为资源的路径有:
//xxx: /webjars/**、/** (不配置的情况下)
//xxx: 默认寻找的路径再不配置的情况下有:
//xxx: classpath:/META-INF/resources/webjars/,
// "classpath:/META-INF/resources/",
// "classpath:/resources/",
// "classpath:/static/",
// "classpath:/public/"
ServletContext servletContext = getServletContext();
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
}
}
}
# 配置资源形式
spring.mvc.static-path-pattern=/**
- 默认为
/**
- 配置项为单个参数,即只能满足指定一个统配的要求,如指定
/static/video/**
为视频请求,/template/myword/**
为自定义资源请求,无法做到精细化配置; - 当前默认情况下
/**
可以处理所有的静态资源(在前面没有RequestMapping以及自定义的HandlerMapping的情况下)
# 配置资源地址
spring.resources.staticLocations=aaa,bbb,ccc
- 默认识别地址包括:
classpath:/META-INF/resources/
,classpath:/resources/
,classpath:/static/
,classpath:/public
# 非SpringBoot环境注意事项
# MVC基础设置装配
装配方式,可以粗糙的理解为两种:
- 使用了标准springMVC配置的方式:
WebMvcConfigurationSupport
- 没有使用标准springMVC配置的方式
- 使用了标准springMVC配置的方式:
二者的springMVC装配行为存在着较大差距
# 静态资源处理
springMvc在没有使用标准springMVC配置的情况下,不存在静态资源处理功能
使用了标准配置,仍然需要进行配置才可使用静态资源功能
# springMvc静态资源与动态网页
- 动态网页与静态资源不是一个概念,但静态资源可以充当网页,代码层面上来说,它们也不再一个层次,静态资源在动态网页的更上层;
- 动态网页基于RequestMapping,静态资源基于SimpleUrl
- 动态网页的核心在于视图解析器,静态资源的核心在于静态资源地址
# springboot项目放置静态资源
# 方式一
- 1.配置 spring.mvc.static-path-pattern: /template/*
- 2.将html文档放在 templates放在默认的资源目录下,通过template访问(所有的静态资源,均需要template前缀才能够访问),不配置的情况下,所有路径都能够访问静态资源
- 默认资源目录:
classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/,classpath:/public/
,不用考虑是 springboot项目,还是tomcat项目,直接把html文档也当成静态资源;
# 方式二
spring:
web:
resources:
static-locations: classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/,classpath:/public/,classpath:/templates/
classpath:/templates/
就是需要新增的资源路径默认情况下,
templates
用于存放Thymeleaf、FreeMarker等模板引擎的模板文件将templates目录设置为静态资源可能会导致安全风险,因为这会使原本仅限于服务器端渲染的模板文件暴露给客户端。请确保这样做不会泄露敏感信息。
如果你的项目同时使用了模板引擎(如Thymeleaf),将templates目录设为静态资源可能会影响模板的正常工作,因为这些文件不再经过模板引擎的解析。
注意事项:
spring:
mvc:
view:
prefix: /template/
suffix: .html
- 该配置是为了用于寻找模板引擎的模板文件,必须结合模板引擎的视图解析器使用;它与静态资源有所区别(服务端的角度而言);
# 方式三
- 通过自定义静态资源处理器,实现自定义静态资源路径
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/template/**")
.addResourceLocations("classpath:/templates/");
}
}
- 这个配置告诉Spring Boot当请求以
/template/
开头时,从类路径的/templates/
目录中查找资源。