JavaEE 企业级分布式高级架构师(四)SpringMVC学习笔记(5)

原理篇

图解MVC三大角色和三大组件作用

在这里插入图片描述

结构流程说明

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器根据url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. HandlerAdapter执行处理器(handler,也叫后端控制器)
  6. controller执行完成返回ModelAndView
  7. HandlerAdapterhandler执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServletModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View对象
  10. DispatcherServletView进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户

六大组件说明

  • DispatcherServlet 前端控制器:用户请求到达前端控制器,DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。
  • HandlerMapping 处理器映射器:HandlerMapping负责根据用户请求找到Handler处理器,SpringMVC提供了不同的映射器实现不同的映射方法,如:配置文件方式、实现接口方式、注解方式等。
  • Handler 处理器:Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
  • HandlerAdapter 处理器适配器:通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  • ViewResolver 视图解析器:ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
  • View 视图:SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

说明:在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。需要开发的组件有:处理器、视图

源码篇

知识储备

在这里插入图片描述

Servlet的生命周期

  • 实例化,由web容器实例化servlet实例;
  • 初始化,容器调用 init 方法:Servlet对象创建之后调用;
  • 服务,客户端请求 servlet 时,容器调用 service 方法:Servlet对象被HTTP请求访问时调用;
  • 销毁,结束服务,调用 destroy方法:Servlet对象销毁之前调用;
  • 垃圾回收。

DispatcherServlet继承体系

在这里插入图片描述

InitializingBean接口介绍

  • Spring有两种Bean的初始化(不是实例化)方式:
    • 一种是实现InitializingBean接口;
    • 一种是通过反射调用bean标签中的init-method属性指定的方法。
  • 不同点:接口比配置效率高,但是配置消除了对Spring的依赖。
  • InitializingBean接口为bean提供了初始化方法的方式:它只包括 afterPropertiesSet 方法;凡是实现该接口的类,在初始化bean的时候会执行该方法。

实现InitializingBean接口与在配置文件中指定init-method有什么不同?

  • 系统先调用afterPropertiesSet方法,然后调用init-method中指定的方法。

这种Bean的初始化方式在spring中是怎么实现的?

  • 执行时机:在创建Bean实例及设置完属性之后执行,通过查看spring加载bean的源码类(AbstractAutowireCapableBeanFactory类中的invokeInitMethods)可看出其中奥妙,源码如下:

在这里插入图片描述

DispatcherServlet主流程

初始化流程

  • 初始化入口:GenericServlet#init(config)
// 生命周期方法之初始化方法,servlet被创建时会调用该方法
public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}
public void init() throws ServletException {
}

在这里插入图片描述

  • 接下来准备调用GenericServlet#init()方法,不过该方法它没有实现,而是被HttpServletBean给覆盖了,接下来直接看看HttpServletBean#init()方法

在这里插入图片描述

  • 接下来调用initServletBean(),不过该方法需要去HttpServletBean的子类FrameworkServlet中查看

在这里插入图片描述

  • 方法调用到这里,我们终于知道DispatcherServlet初始化的主要工作是干嘛的了,就是为了创建Spring容器(其实容器内还要初始化一些组件)。接下我们看看FrameworkServlet#initWebApplicationContext()方法
protected WebApplicationContext initWebApplicationContext() {
	// 父容器
	WebApplicationContext rootContext =
			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	// 子容器
	WebApplicationContext wac = null;

	// 省略一些判断、设置...

	if (!this.refreshEventReceived) {
		// Either the context is not a ConfigurableApplicationContext with refresh
		// support or the context injected at construction time had already been
		// refreshed -> trigger initial onRefresh manually here.
		// 刷新容器中的策略
		onRefresh(wac);
	}

	// 省略...

	return wac;
}
  • onRefresh()方法是初始化一些默认组件,比如HandlerMapping组件中的BeanNameURLHandlerMapping,我们进入这个方法看看:

在这里插入图片描述

  • 看到这里,我们已经明白入门程序为什么没有配置三大组件,Spring容器中却依然有这些组件。这个地方初始化了很多默认配置,我们可以随便找个initHandlerMapping来了解一下它们的实现:

在这里插入图片描述

  • 看看是如何加载默认策略的,进入getDefaultStrategies方法:

在这里插入图片描述

  • 那么defaultStrategies集合是如何初始化的呢?
    在这里插入图片描述
    至此,DispatcherServlet初始化工作就完成了。
  • 记笔记:
GenericServlet#init(config):生命周期方法之初始化方法:Servlet被创建时会调用该方法
  |--HttpServletBean#init():子类HttpServletBean覆写父类【GenericServlet】的init()空方法——模板方法模式
	|--FrameworkServlet#initServletBean():子类FrameworkServlet覆写父类【HttpServletBean】的initServletBean()空方法——模板方法模式
	  |--FrameworkServlet#initWebApplicationContext():创建spring容器,父子容器创建
		|--DispatcherServlet#onRefresh(ApplicationContext context):刷新容器【初始化一些默认组件】,子类DispatcherServlet覆写父类【FrameworkServlet】的onRefresh()空方法——模板方法模式
		  |--DispatcherServlet#initStrategies(context):初始化组件策略
			|--DispatcherServlet#initHandlerMappings(context):以初始化处理器映射器组件为例,从spring容器中获取HandlerMapping,如果没有就走默认策略
			  |--DispatcherServlet#getDefaultStrategies(context, HandlerMapping.class):获取默认的组件初始化策略,其中defaultStrategies是在静态代码块中去读取DispatcherServlet.properties的内容
  • 涉及到的类:
* GenericServlet
* HttpServletBean
* FrameworkServlet
* DispatcherServlet

访问处理流程

  • 访问入口:HttpServlet#service(...)方法(该方法的request 和 response参数不是Http开头的)

在这里插入图片描述

  • 继续跟踪到另一个service方法(请求和响应式Http开头的),该方法根据请求的method分别调用相应的处理器
protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    String method = req.getMethod();

    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < lastModified) {
                // If the servlet mod time is later, call doGet()
                // Round down to the nearest second for a proper compare
                // A ifModifiedSince of -1 will always be less
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }
    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
        
    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);
        
    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);
        
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);
        
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);
        
    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);
        
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}
  • 我们主要去看看doGetdoPost方法是如何处理的,由继承体系分析得知,我们应该去FrameworkServlet类查看:
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	processRequest(request, response);
}
  • 到此为止,我们还没有进入DispatcherServlet类,所以继续去processRequest方法看一下:

在这里插入图片描述

  • 通过doService方法才正式进入到 DispatcherServlet类中去执行:
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	// 省略...

	try {
		// 最核心的一个方法,处理请求分发(做调度)
		doDispatch(request, response);
	}
	// 省略...
}
  • 至此,我们终于找到了DispatcherServlet中最核心的一个方法:doDispatch,进到方法里查看:

在这里插入图片描述

  • 源码阅读到这里,最起码从主流程中我们可以得知DispatcherServlet是如何处理一个请求的。但是我们看到现在,还没有看出DispatcherServlet是如何与三大组件进行联系的。所以我们要分别找到三大组件与DispatcherServlet交互的地方。
  • 处理器映射器与DispatcherServlet交互的地方:getHandler方法:

在这里插入图片描述

  • 处理器适配器与DispatcherServlet交互的地方:getHandlerAdapter方法:

在这里插入图片描述

  • 视图解析器与DispatcherServlet交互的代码需要多深入几层去了解,先进入processDispatchResult方法:

在这里插入图片描述

  • 再进入render方法:

在这里插入图片描述

  • 这个resolveViewName方法就是视图解析器和DispatcherServlet交互的方法:

在这里插入图片描述

  • 到此,DispatcherServlet的主流程以及三大组件和它的联系,我们都已经搞清楚了。至于,三大组件的具体实现,这里暂不分析。
  • 记笔记:
HttpServlet#service(req, res)
  |--HttpServlet#service(req, res)
	|--FrameworkServlet#doGet(req, res)
      |--FrameworkServlet#processRequest(req, res)
		|--FrameworkServlet#processRequest(req, res):处理请求,但是还没有真正干活
		  |--DispatcherServlet#doService(req, res):真正干活【很关键的一步】
			|--DispatcherServlet#doDispatch(req, res):最核心的一个方法
			  |--DispatcherServlet#checkMultipart(req):处理含文件上传的请求
			  |--DispatcherServlet#getHandler(processedRequest):通过处理器映射器解析请求URL,获取对应的处理器对象
			  |--DispatcherServlet#getHandlerAdapter(mappedHandler.getHandler()):根据查找到的处理器对象,找到它的处理器适配器对象
			  |--DispatcherServlet#processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException):处理执行结果,即对ModelAndView进行处理【视图解析、视图渲染】
				|--DispatcherServlet#processHandlerException(request, response, handler, exception):处理异常
				|--DispatcherServlet#render(mv, request, response):视图渲染
				  |--DispatcherServlet#resolveViewName(viewName, mv.getModelInternal(), locale, request):根据视图名称,调用视图解析器,解析出来视图对象
  • 涉及到的类:
* HttpServlet
* FrameworkServlet
* DispatcherServlet

拦截器处理流程

  • 分析源码入口:DispatcherServlet#doDispatch方法:
    在这里插入图片描述
  • preHandle流程分析(HandlerExecutionChain类)
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
	// 获取当前HandlerMapping返回的拦截器集合
	HandlerInterceptor[] interceptors = getInterceptors();
	if (!ObjectUtils.isEmpty(interceptors)) {
		for (int i = 0; i < interceptors.length; i++) {
			HandlerInterceptor interceptor = interceptors[i];
			// 执行拦截器preHandle方法
			if (!interceptor.preHandle(request, response, this.handler)) {
				triggerAfterCompletion(request, response, null);
				return false;
			}
			// 记录最后成功执行的处理器拦截器在拦截器集合中的下标,影响postHandle和afterCompletion方法的执行顺序
			this.interceptorIndex = i;
		}
	}
	return true;
}
  • postHandle流程分析(HandlerExecutionChain类)
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
	HandlerInterceptor[] interceptors = getInterceptors();
	if (!ObjectUtils.isEmpty(interceptors)) {
		for (int i = interceptors.length - 1; i >= 0; i--) {// 倒序
			HandlerInterceptor interceptor = interceptors[i];
			// 执行postHandle方法
			interceptor.postHandle(request, response, this.handler, mv);
		}
	}
}
  • afterCompletion流程分析(HandlerExecutionChain类)
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
	HandlerInterceptor[] interceptors = getInterceptors();
	if (!ObjectUtils.isEmpty(interceptors)) {
		// 边界是preHandle方法赋值的interceptorIndex,倒序执行afterCompletion方法
		for (int i = this.interceptorIndex; i >= 0; i--) {
			HandlerInterceptor interceptor = interceptors[i];
			try {
				interceptor.afterCompletion(request, response, this.handler, ex);
			}
			catch (Throwable ex2) {
				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
			}
		}
	}
}
  • 记笔记:
DispatcherServlet#doDispatch()
  |--DispatcherServlet#applyPreHandle(..):执行处理器的preHandler方法
	|--HandlerExecutionChain#applyPreHandle(..)
  |--DispatcherServlet#applyPostHandle(..):执行处理器的postHandler方法
	|--HandlerExecutionChain#applyPostHandle(..)
  |--DispatcherServlet#processDispatchResult(..):执行处理器的afterCompletion方法
  |--DispatcherServlet#triggerAfterCompletion(..):执行处理器的afterCompletion方法
	|--HandlerExecutionChain#triggerAfterCompletion(..)
  • 涉及到的类:
* DispatcherServlet
* HandlerExecutionChain

处理器映射器

  • 主要分析注解方式的处理器映射器RequestMappingHandlerMapping:根据@ResquestMapping注解查找处理器(HandlerMethod)。

RequestMappingHandlerMapping继承体系

在这里插入图片描述

注册流程

  • 分析入口:RequestMappingHandlerMapping#afterPropertiesSet方法:
@Override
public void afterPropertiesSet() {
	this.config = new RequestMappingInfo.BuilderConfiguration();
	this.config.setUrlPathHelper(getUrlPathHelper());
	this.config.setPathMatcher(getPathMatcher());
	this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
	this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
	this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
	this.config.setContentNegotiationManager(getContentNegotiationManager());

	super.afterPropertiesSet();
}
  • 继续进入父类AbstractHandlerMethodMapping#afterPropertiesSet方法,其中调用了initHandlerMethods方法(定义了映射器处理器的主流程)
@Override
public void afterPropertiesSet() {
	initHandlerMethods();
}

在这里插入图片描述

  • 我们继续去看看detectHandlerMethods方法(核心处理方法)

在这里插入图片描述

  • 上面的方法处理逻辑主要分为两大步骤:
    • 映射Method和RequestMappingInfo的关系
    • 映射关系:RequestMappingInfo与URL和HandlerMethod的关系
  • 我们先看第一大步骤,也就是调用MethodIntrospector#selectMethods方法

在这里插入图片描述

  • 我们去看一下MetadataLookup的匿名内部类实现中调用的getMappingForMethod方法是如何实现的?需要去RequestMappingHandlerMapping类中去查看方法:

在这里插入图片描述
在这里插入图片描述

  • 至此,第一大步骤我们阅读完了,接下来去看看第二大步骤,我们看看AbstractHandlerMethodMapping#registerHandlerMethod方法:
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}
  • 接下来,我们去看看register方法:

在这里插入图片描述
在这里插入图片描述

  • 至此处理器映射器的初始化流程就完成了。
  • 记笔记:以RequestMappingHandlerMapping为例
RequestMappingHandlerMapping#afterPropertiesSet()
  |--AbstractHandlerMethodMapping#afterPropertiesSet()
	|--AbstractHandlerMethodMapping#initHandlerMethods()
  	  |--AbstractHandlerMethodMapping#detectHandlerMethods(beanName):【核心的处理方法】
		|--MethodIntrospector#selectMethods(userType, (MethodIntrospector.MetadataLookup<T>)method):将处理器中的方法进行过滤,映射Method和RequestMappingInfo
		  |--RequestMappingHandlerMapping#getMappingForMethod(Method method, Class<?> handlerType):将RequestMapping注解封装成RequestMappingInfo对象返回
			|--RequestMappingHandlerMapping#createRequestMappingInfo(method):获取方法上的RequestMapping注解信息
			|--RequestMappingHandlerMapping#createRequestMappingInfo(handlerType):获取类上的RequestMapping注解信息
			  |--RequestMappingHandlerMapping#createRequestMappingInfo:封装RequestMappingInfo对象信息
     	  |--MethodIntrospector.MetadataLookup#inspect(Method method):返回RequestMappingInfo对象
    	|--AbstractHandlerMethodMapping#registerHandlerMethod(handler, invocableMethod, mapping):将handler和method封装成HandlerMethod对象,进行映射注册
     	  |--AbstractHandlerMethodMapping#register(mapping,handler, method)
      		|--Map<T, HandlerMethod> mappingLookup:将HandlerMethod和HandlerMappingInfo进行映射
      		|--MultiValueMap<String, T> urlLookup:将URL和HandlerMappingInfo进行映射
     |--handlerMethodsInitialized(getHandlerMethods()):还未实现
  • 涉及到的类:
* RequestMappingHandlerMapping
* AbstractHandlerMethodMapping
* MethodIntrospector
* MethodIntrospector.MetadataLookup

处理流程

  • 分析入口:DispatcherServlet#getHandler方法:

在这里插入图片描述

  • 接下来我们需要进入到具体的AbstractHandlerMapping#getHandler方法:

在这里插入图片描述

  • 接下来我们重点看看AbstractHandlerMethodMapping#getHandlerInternal方法:

在这里插入图片描述

  • 接下来我们重点去看看lookupHandlerMethod方法(核心方法):
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List<Match> matches = new ArrayList<>();
	// 根据查找路径(URL)去urlLookup集合中获取匹配到的RequestMappingInfo集合
	List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	if (directPathMatches != null) {
		// 将RequestMappingInfo对象和HandlerMethod对象进行匹配,将匹配到的信息封装到Match对象,再将Match对象放入matches集合
		addMatchingMappings(directPathMatches, matches, request);
	}
	if (matches.isEmpty()) {
		// No choice but to go through all mappings...
		addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
	}

	if (!matches.isEmpty()) {
		Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
		// 使用指定的比较器,将匹配到的Match对象进行排序
		matches.sort(comparator);
		if (logger.isTraceEnabled()) {
			logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
		}
		// 找到最优匹配项
		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			if (CorsUtils.isPreFlightRequest(request)) {
				return PREFLIGHT_AMBIGUOUS_MATCH;
			}
			// 获取次优匹配项
			Match secondBestMatch = matches.get(1);
			// 如果最优匹配项和次优匹配项是相同的,则报错
			if (comparator.compare(bestMatch, secondBestMatch) == 0) {
				Method m1 = bestMatch.handlerMethod.getMethod();
				Method m2 = secondBestMatch.handlerMethod.getMethod();
				throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
						request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
			}
		}
		request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
		handleMatch(bestMatch.mapping, lookupPath, request);
		// 返回最匹配的HandlerMethod对象
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
	}
}
  • 其中,我们继续去看看addMatchingMappings方法:
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
	for (T mapping : mappings) {
		// 获取待匹配的RequestMappingInfo对象,封装RequestMapping注解信息
		T match = getMatchingMapping(mapping, request);
		if (match != null) {
			// 将待匹配的RequestMappingInfo和HandlerMethod对象封装到Match对象中,并添加到集合
			matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		}
	}
}
  • 接着去RequestMappingInfoHandlerMapping#getMatchingMapping方法:
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
	return info.getMatchingCondition(request);
}
  • 最后去RequestMappingInfo#getMatchingCondition方法:
@Override
@Nullable
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
	RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
	ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
	HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
	ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
	ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

	if (methods == null || params == null || headers == null || consumes == null || produces == null) {
		return null;
	}
	// 获取到RequestMapping注解中value属性的值
	PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
	if (patterns == null) {
		return null;
	}

	RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
	if (custom == null) {
		return null;
	}

	return new RequestMappingInfo(this.name, patterns,
			methods, params, headers, consumes, produces, custom.getCondition());
}
  • 记笔记:
DispatcherServlet#getHandler(HttpServletRequest request)
  |--AbstractHandlerMapping#getHandler(request):返回HandlerExecutionChain
	|--AbstractHandlerMethodMapping#getHandlerInternal(request):交给具体子类【比如AbstractHandlerMethodMapping】实现,返回HandlerMethed对象
	  |--AbstractHandlerMethodMapping#lookupHandlerMethod:根据请求URL,获取HandlerMethod对象【核心方法】
		|--AbstractHandlerMethodMapping#addMatchingMappings:将RequestMappingInfo对象和请求中的信息进行匹配,将匹配信息封装到Match对象存储到集合中
		  |--RequestMappingInfoHandlerMapping#getMatchingMapping:获取匹配到的RequestMappingInfo对象
			|--RequestMappingInfo#getMatchingCondition
	|--getHandlerExecutionChain(handler, request):将Handler和HandlerInterceptor封装成一个执行链对象
  • 涉及到的类:
* DispatcherServlet
* AbstractHandlerMapping
* AbstractHandlerMethodMapping
* RequestMappingInfoHandlerMapping
* RequestMappingInfo
开课吧-javaEE企业级分布式高级架构师是一门专注于培养企业级应用开发的高级技术课程。该课程旨在帮助学员全面掌握Java EE企业级开发的技能和知识,培养他们成为具备分布式应用系统设计和架构能力的高级架构师。 在这门课程中,学员将学习Java EE的核心概念和技术,包括Servlet、JSP、JDBC、EJB、JNDI等。同时,学员还将深入学习分布式应用开发的相关技术,如Web服务、消息队列、分布式缓存、负载均衡等。除此之外,课程还将涉及如何使用流行的Java EE开发框架(如Spring、Hibernate等)进行企业应用开发,并介绍分布式系统的设计原则和最佳实践。 通过学习这门课程,学员将能够了解分布式应用架构的基本原理,并具备设计和构建分布式应用系统的能力。他们将熟练掌握Java EE平台的各种技术和工具,能够灵活运用它们开发高性能、可扩展性强的企业级应用系统。此外,通过课程中的实战项目,学员还将锻炼解决实际问题和项目管理的能力。 作为一门高级架构师的课程,它将帮助学员进一步提升自己的职业发展。毕业后,学员可以在企业中担任分布式应用的架构师、系统设计师、技术经理等角色,负责企业级应用系统的设计和开发。此外,他们还可以选择独立开发,提供技术咨询和解决方案。 总之,开课吧-javaEE企业级分布式高级架构师是一门非常有价值的课程,它将帮助学员掌握Java EE企业级开发的核心技术和分布式应用架构的设计原理,培养他们成为具备高级架构师能力的软件开发专业人士。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

讲文明的喜羊羊拒绝pua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值