Spring源码学习(5)- springmvc解析
介绍
SpringMvc是基于servlet规范来完成的一个请求详情模块,也是spring中比较大的一个模块。springmvc使用有两种方式,一种是配置文件的形式;另一个就是注解的形式,这种方法采用的是约定大于配置的方式。完成这个过程,springmvc要解决两个问题。
1.取代web.xml配置
springmvc借助servlet中的一个规范,来完成这个事情
当servlet容器启动的时候,会根据spi规范,在家META-INF/services文件夹里面的javax.servlet.ServletContainerInitializer文件,这个文件会实现javax.servlet.ServletContainerInitializer接口。
这个类在启动时,被servlet容器实例化,然后调用 onStartup 方法,并且servlet容器会收集实现了类上 @HandlesTypes 注解里面的接口的类,并作为入参(Set)传入到onStartup方法中,就可以拿到对应的class进行操作了,接下来看到方法中的 onStartup 方法
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
onStartup ():AbstractDispatcherServletInitializer这个类中的
代码分为两部分,一部分是调用父类的onStartup方法,另一部分就是registerDispatcherServlet
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
//注册DispatcherServlet
registerDispatcherServlet(servletContext);
}
super.onStartup()方法
这个方法作用是创建spring容器的上下文对象,存入到ContextLoaderListener对象中,最后存入servletContext中
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
/**
* Register a {@link ContextLoaderListener} against the given servlet context. The
* {@code ContextLoaderListener} is initialized with the application context returned
* from the {@link #createRootApplicationContext()} template method.
* @param servletContext the servlet context to register the listener against
*/
protected void registerContextLoaderListener(ServletContext servletContext) {
// 创建spring上下文,注册了SpringContainer
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
// 创建监听器
/*
形如这种配置
* <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
<!--<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>-->
</listener>
*
* */
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
createRootApplicationContext():
创建spring上下文,上下文就是收集各种bean的信息的容器,有两种收集方式
一种是配置文件收集
另一种则是注解方式收集,注解方式需要需要配置扫描器(@ComponentScan)去扫描项目中需要扫描入容器的bean。
在这个方法中,有个getRoowConfigClasses(),这就需要我们自己写一个类,继承AbstractAnnotationConfigDispatcherServletInitializer类,重写这个方法,将扫描器提供给上下文对象
@Override
@Nullable
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
else {
return null;
}
}
然后将上下文对象设置到ContextLoaderListener监听器对象中,最后把监听器对象设置到servletContext中
if (rootAppContext != null) {
// 创建监听器
/*
形如这种配置
* <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
<!--<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>-->
</listener>
*
* */
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
registerDispatcherServlet()方法
这个方法,作用是实例化DispatcherServlet对象
主要就是两个createXXX方法来创建springmvc上下文跟servlet对象
创建springmvc上下文方法,跟创建spring上下文基本一致,都需要自己定义一个扫描器来扫描生成上下文。
然后根据上下文创建servlet对象
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
// 创建springmvc的上下文,注册了MvcContainer类
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
// 创建DispatcherServlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
"Check if there is another servlet registered under the same name.");
}
/*
* 如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,
值越小,servlet的优先级越高,就越先被加载
* */
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
到此为止一共有spring跟springmvc上下文,分别存放在ContextLoaderListener对象跟DispatcherServlet中
启动spring容器
监听器 ContextLoaderListener 的启动
ContextLoaderListener类的 contextInitialized 方法
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
DispatcherServlet的启动
servlet要完成spring容器的启动,只能在init方法里面完成,所以需要找到此方法
在 DispatcherServlet 的父类 HttpServletBean 中找到init()方法,主要看方法里面的 initServletBean 方法
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();
}
initServletBean()
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (logger.isInfoEnabled()) {
logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
initWebApplicationContext()
1.获取spring上下文对象
protected WebApplicationContext initWebApplicationContext() {
// 这里会从servletContext中获取到父容器,就是通过监听器加载的容器 (spring上下文)
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 代码有省略......
return wac;
}
2.设置springmvc上下文的父上下文(spring上下文)对象
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
// 容器加载
configureAndRefreshWebApplicationContext(cwac);
}
}
}
3.容器加载,进行refresh()
到此,springmvc就使用了servlet规范,来完成取代web.xml的工作,并启动容器
2.取代springmvc.xml配置
使用**@EnableWebMvc** 即可
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
该注解会导入类DelegatingWebMvcConfiguration,其父类为WebMvcConfigurationSupport
WebMvcConfigurationSupport这个类会完成很多组件的实例化,HandlerMapping,HandlerAdapter等,都是通过@Bean方式
请求之间建立映射关系
在Hanldermapping类实例化的时候,就会完成url和method的映射关系,要根据一个请求能够唯一找到一个类和一个方法
主要逻辑都在createRequestMappingHandlerMapping()方法中
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null) {
mapping.setPathPrefixes(pathPrefixes);
}
return mapping;
}
createRequestMappingHandlerMapping
创建RequestMappingHandlerMapping类,其父类的父类的父类AbstractHandlerMethodMapping,实现了InitailizingBean接口,所以在RequestMappingHandlerMapping实例化后,会调用afterPropertiesSet()方法
1.afterPropertiesSet()
public void afterPropertiesSet() {
initHandlerMethods();
}
2.initHandlerMethods()
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
3.processCandidateBean()
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 如果类上面有@Controller注解或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
// 建立uri和method的映射关系
detectHandlerMethods(beanName);
}
}
4.detectHandlerMethods()
能进来这个方法的类,都是有@Controller或者@RequestMapping注解的
这个方法可分为两个部分
- 获取方法和对象上的@RequestMapping注解属性封装对象的映射关系(上半部分)
// 获取方法对象和方法上面的@RequestMapping注解属性封装对象的映射关系
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
selectMethods()
循环判断类上的所有方法,调用方法的匿名内部类中的getMappingForMethod()方法,然后将方法与RequestMappingInfo对象,存到一个map中,并返回
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
// 循环currentHandlerType类的所有方法
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// 判断方法上面是否有@RequestMapping注解,如果有封装对象返回
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
// 建立方法对象和注解封装对象的映射关系
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
getMappingForMethod()
- 先判断方法是否有@RequestMapping注解,如果没有,遍历下一个方法,如果有,解析注解上的各种值,并用构建成RequestMapping对象(建造者模式)。
- 在用相同的办法,来解析类上面的注解信息,封装成RequestMapping对象。
- 然后将类上的RequestMapping与方法上的RequestMapping合并成一个
- 判断是否有前缀,来决定是否需要在合并后的RequestMapping中,加入该前缀
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 寻找有@RequestMapping注解的方法,然后注解里面的内容封装成对象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 类上面的@RequestMapping注解也封装成对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 把方法上面的注解属性结合到类上面的RequestMappingInfo对象中
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
- 建立uri和方法的各种映射关系 (下半部分)
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 建立uri和方法的各种映射关系,反正一条,根据uri要能够找到method对象
registerHandlerMethod(handler, invocableMethod, mapping);
});
registerHandlerMethod()
private final MappingRegistry mappingRegistry = new MappingRegistry();
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
register()
- 创建HandlerMethod对象,对象中存放的是beanName/bean实例(在调用的时候会实例化),跟对应的method
- 建立RequestMappingInfo跟handlerMethod映射关系
- 建立url和RequestMappingInfo的映射关系
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
// 创建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 检验是否唯一
assertUniqueMethodMapping(handlerMethod, mapping);
// 建立uri对象和handlerMethod的映射关系
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 建立url和RequestMappingInfo映射关系
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// 判断method上是否有CrossOrigin注解,把注解里面的属性封装成CorsConfiguration,这个是做跨域访问控制的
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
// 建立映射关系
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
到此,就能根据请求的url,找到一个唯一的HandlerMethod对象,但是方法反射调用,需要的是
对象实例,方法跟参数,前两个已经有了,现在只缺参数了
dispatcherServlet处理请求
当请求过来,会先手调用DispatcherServlet的doService()方法,会调用到doDispatch()方法,
其中重点的几个方法
getHandler()
获取对应的HandlerExecutionChain 对象
HandlerExecutionChain mappedHandler = null;
// 。。。。。。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// ---------- DispatcherServlet 类 --------------
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// handlerMappering实例
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 获取HandlerMethod和过滤器链的包装类
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
// ---------- AbstractHandlerMapping 类 ---------------
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求的uri拿到对应的HandlerMethod对象
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 获取HandlerMethod和过滤器链的包装类
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 是否是跨域请求,就是查看request请求头中是否有Origin属性
if (CorsUtils.isCorsRequest(request)) {
// 自定义的钩子方法获取跨域配置
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
// 注解获取跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
// 这里设置了跨域的过滤器CorsInterceptor
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
// -------------getHandlerInternal() 方法,获取HandlerMethod,并把HandlerMethod中的beanName实例化成bean
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 从request对象中获取uri,/common/query2
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 根据uri从映射关系中找到对应的HandlerMethod对象
/*
1.根据uri,从urlLookup中,获取RquestMappingInfo 对象
2.根据RequestMappingInfo对象,从mappingLookup中,获取HandlerMethod对象
3.把ReqestMapingInfo,HandlerMethod对象。封装成Match对象
4.判断是否有多个匹配的HandlerMethod对象,如果有,判断最佳匹配的。如果没有,直接返回
5.如果匹配到有两个相同的,直接报错
6.返回HandlerMethod对象
*/
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 把Controller类实例化
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
// ---------------getHandlerExecutionChain() 方法,获取HandlerExecutionChain 对象,并判断是否有拦截器,如果有的话。添加进拦截器链中返回
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 把HandlerMethod对象包装到HandlerExecutionChain对象中,这个对象中有过滤器对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 获取uri
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 是否有过滤器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
getHandlerAdapter
获取对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// -----------------------
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
mappedHandler.applyPreHandle
前置处理,调用跟改uri匹配的拦截器的preHandle方法,如果其中一个返回false,则该方法结束调用
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
ha.handle
执行controller具体方法,关键点在参数的解析
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
中间代码很多,主要流程
handle()
方法调用
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
–>AbstractHandlerMethodAdapter.handleInternal()
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// Controller里面具体方法调用
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
–>RequestMappingHandlerAdapter.invokeHandlerMethod()
各种解析
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取数据绑定工厂 @InitBinder注解支持
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// Model工厂,收集了@ModelAttribute注解的方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 可调用的方法对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 设置返回值解析器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 设置参数绑定工厂
invocableMethod.setDataBinderFactory(binderFactory);
// 设置参数名称解析类
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法
// 把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 异步处理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// Controller方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
–>RequestMappingHandlerAdapter.invokeAndHandle()
方法调用跟处理返回值
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 具体调用逻辑
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
–>ServletInvocableHandlerMethod.invokeForRequest()
解析参数跟方法调用
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取参数数组
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
–>InvocableHandlerMethod.getMethodArgumentValues()
解析参数
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
if (ObjectUtils.isEmpty(getMethodParameters())) {
return EMPTY_ARGS;
}
// 入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 设置参数名称解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 典型的策略模式,根据parameter能否找到对应参数的处理类,能找到就返回true
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) {
// Leave stack trace for later, exception may actually be resolved and handled..
if (logger.isDebugEnabled()) {
String error = ex.getMessage();
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, error));
}
}
throw ex;
}
}
return args;
}
// ----------------InvocableHandlerMethod -----------------
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 根据参数获取对应参数的解析类
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException(
"Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +
" supportsParameter should be called first.");
}
// 策略模式去调用具体参数解析类
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
–> InvocableHandlerMethod.doInvoke()
方法调用
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
处理返回值
在ServletInvocableHandlerMethod类的invokeAndHandle()中
返回值可能是数据,也可能是跳转的界面
- 根据返回值,返回值类型,找到一个处理的handler
- 使用策略模式进行解析
try {
//返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
--------------------------------
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
mappedHandler.applyPostHandle
中置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult
视图解析
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
------------------------------
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果异常不为空
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
// 视图渲染,响应视图
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 后置过滤器
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
render()
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 核心逻辑
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
view.render
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
// 这里进行各种响应
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
来源:CSDN
作者:Zzzzz_xh
链接:https://blog.csdn.net/Zzzzz_xh/article/details/104474839