SpringMVC的源码深度解析

ServletContainerInitializer接口

在web容器启动时提供给第三方做一些初始化的工作的接口,例如servlet或者filtes等,每个框架要使用ServletContainerInitializer就必须在对应的jar包创建META-INF/service目录,并且建javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类。

@HandlesTypes(value = MyHandlesType.class)注解

在ServletContainerInitializer实现类中加上该注解,就能够拿到对应的类的所有子类的class文件信息

SpringMVC 没有web.xml方式基于注解方式实现启动

package com.mayikt.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**
 * @Description:
 * @Author: ChenYi
 * @Date: 2020/07/09 23:24
 **/
@Configuration
@ComponentScan("com.mayikt.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
package com.mayikt.config;

import org.springframework.web.SpringServletContainerInitializer;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

/**
 * @Description:
 * @Author: ChenYi
 * @Date: 2020/07/09 23:35
 **/

public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();
        webApplicationContext.register(SpringMvcConfig.class);
        ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(webApplicationContext));
        dynamic.addMapping("/");
        dynamic.setLoadOnStartup(1);
    }
}

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;


@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);
		}
	}

}

  • Spring-Web依赖Jar包,SpringServletContainerInitializer实现初始化.
  • @HandlesTypes(WebApplicationInitializer.class)
  • MyWebApplicationInitializer继承WebApplicationInitializer类
  • Serlvet容器在初始化的时候会加载到这个SpringServletContainerInitializer,然后会找WebApplicationInitializer子类,然后回调onStartup方法进行初始化

拦截器和过滤器的区别

相同点:

  • 拦截器和过滤器都是基于aop技术,对方法实现增强,都可以拦截请求方

法。
不同点:

  1. 过滤器属于Servlet研发的,而拦截器属于SpringMVC研发的
  2. 过滤器属于拦截Web请求,而拦截器不仅可以拦截请求,还可以拦截普通方法
  3. 过滤器会比拦截器先执行,拦截器封装的方法比过滤器拦截使用起来更加简单

自定义拦截器

实现HandlerInterceptor接口
package com.mayikt.interceptor;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description:
 * @Author: ChenYi
 * @Date: 2020/07/13 08:17
 **/

public class TokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(">>>>>preHandle<<<<");
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)) {
            response.setStatus(500);
            response.getWriter().println("token 无效");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println(">>>>>postHandle<<<<");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println(">>>>>afterCompletion<<<<");

    }
}

  1. preHandle在业务处理器处理请求之前被调用;
  2. postHandle在业务处理器处理请求执行完成后,生成视图之前执行;
  3. afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等 。

DispatchServlet

DispatchServlet与Servlet的关系

类图
在这里插入图片描述
DispatcherServlet继承FrameworkServlet继承HttpServlet

流程:

  1. 先走HttpServlet的service方法,判断是get请求还是post请求,然后执行doGet和doPost方法
  2. 执行FrameworkServlet中的doGet或者doPost方法,执行processRequest方法
  3. 执行DispatcherServlet中的doService方法
  4. 执行DispatcherServlet中的doDispatch方法
  5. 先检查是否是文件上传的格式
  6. 执行getHandler获取HandlerExecutionChain对象,里面有handler对象和拦截器Interceptors,handler里面存的有controller的类和请求目标的方法 ,也就是 请求url映射路径对应的控制层具体的方法
  7. getHandlerAdapter获取处理适配器 RequestMappingHandlerAdapter
    10.执行applyPreHandle →preHandle() ,执行拦截器的前置方法如果返回为true的话。
    handle()执行实际的目标方法, 返回modeAndView对象
    执行applyPostHandle→postHandle() 方法,执行拦截器的后置方法
    执行processDispatchResult中的render()方法渲染视图层内容
    执行triggerAfterCompletion→执行拦截器中的afterCompletion方法,释放资源
控制层容器初始化
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context); //初始化上传文件解析器(或者是多部分请求解析器)
		initLocaleResolver(context);//初始化本地化解析器
		initThemeResolver(context);//初始化主题解析器
		initHandlerMappings(context);//初始化处理器映射器
		initHandlerAdapters(context);//初始化处理器适配器
		initHandlerExceptionResolvers(context);//初始化处理器异常解析器
		initRequestToViewNameTranslator(context);//初始化请求到视图名翻译器
		initViewResolvers(context);//初始化视图解析器
		initFlashMapManager(context);//初始化重定向数据管理器

	}

SpringMVC的适配器

  1. 继承Controller方式所使用的适配器:SimpleControllerHandlerAdapter
  2. HTTP请求处理器适配器:HttpRequestHandlerAdapter
  3. 注解方式(@Controller)的处理器适配器:RequestMappingHandlerAdapter

参考:蚂蚁课堂

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值