public interface Servlet {
void init(ServletConfig var1) throws ServletException;
}
GenericServlet抽象类,初始化方法空实现(由子类重写实现)
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
}
GenericServlet抽象类的子类HttpServlet没有实现,具体实现在HttpServletBean类
根据代码可知,具体实现依然需要子类根据需求喜好自己实现重写
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
@Override
public final void init() throws ServletException {
//让子类做他们喜欢的任何初始化
initServletBean();
}
protected void initServletBean() throws ServletException {
}
}
FrameworkServlet 抽象类重写初始化方法initServletBean()
‘springMVC’ :项目名称。日志打印初始化servlet名称以及初始化所需时间
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@Override
protected final void initServletBean() throws ServletException {
//日志打印Initializing Spring DispachServlet 'springMVC'
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
//日志打印Initializing Servlet 'springMVC'
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");
}
}
}
初始化webApplicationContext容器
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
//上下文实例在构造时被注入->使用它
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);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
//创建WebApplicationContext
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//创建WebApplicationContext时候会添加监听器,onRefreash,DispatcherServlet初始化九大组件
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
创建WebApplicationContext
XmlWebApplication类的父类实现了ConfigurableWebApplicationContext接口
WebApplicationContext的父容器是ApplicationContext
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
//默认XmlWebApplication
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
//调用无参构造函数创建 ConfigurableWebApplicationContext
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
//设置环境参数
wac.setEnvironment(getEnvironment());
//设置springmvc的WebApplicationContext容器的父容器为spring的ApplicationContext容器
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
//设置‘springmvc.xml’配置文件路径
wac.setConfigLocation(configLocation);
}
//配置刷新容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
配置刷新容器
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
//就是把它的id由org.springframework.web.context.support.XmlWebApplicationContext@c335c0c
//改成了基于Servlet名字的org.springframework.web.context.WebApplicationContext:/dispatcher,
//官方文档说是替换成一个更有意义的ID
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
//配置ServletContext,放进去的是ApplicationContextFacade对象
wac.setServletContext(getServletContext());
//配置ServletConfig,StandardWrapperFacade对象
wac.setServletConfig(getServletConfig());
//配置命名空间,默认是[Servlet的名字]-servlet
wac.setNamespace(getNamespace());
//添加监听器,监听ContextRefreshedEvent事件,该事件会在WebApplicationContext初始化完毕或者主动调用
//refresh()方法时触发,比如Spring容器加载完context配置文件后就会触发,所以会触发多次,触发后调用
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
//补全之前创建的StandardServletEnvironment对象
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
//空方法,也是供子类扩展的,目前还没有使用
postProcessWebApplicationContext(wac);
//主要是为了在调用refresh方法之前做一些准备工作
applyInitializers(wac);
//主动调用refresh方法,触发上面刚添加的监听器
wac.refresh();
}
DispatcherServlet初始化初始化九大组件
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void onRefresh(ApplicationContext context) {
//将初始化策略和onRefresh方法分开,让子类灵活扩展
initStrategies(context);
}
//这也正是SpringMVC最为核心的部分
protected void initStrategies(ApplicationContext context) {
//处理文件上传请求
initMultipartResolver(context);
//国际化处理
initLocaleResolver(context);
//解析主题配置
initThemeResolver(context);
//把request映射到具体的处理器上(负责找handler)
initHandlerMappings(context);
//调用处理器来处理(负责让handler干活)
initHandlerAdapters(context);
//解析过程出了问题就交给我
initHandlerExceptionResolvers(context);
//从request中获取viewName
initRequestToViewNameTranslator(context);
//将我们返回的视图名字符串(如hello.jsp)解析为具体的view对象
initViewResolvers(context);
//管理FlashMap,主要用于redirect
initFlashMapManager(context);
}
}
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
判断不是已 scopedTarget 开头
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
//获取所有的bean名字
protected String[] getCandidateBeanNames() {
return (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
// 获取具体的类型
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// 不是null 并且 类型是存在 @Controller 或者 @RequestMapping 注解
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
核心代码来了
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
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);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
Web容器启动后(发起调用),GenericServlet接收上下文对象,HttpServletBean给属性赋值,FrameworkServlet负责创建并初始化WebApplicationContext容器,最后DispatcherServlet初始化九大组件
http://localhost:8080/springmvc/target
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查处理文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//处理器映射器,根据url找到对应的controller,找不到报错
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//根据controller找到对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
//根据文件的最近修改时间判断是否返回304状态码,默认修改时间返回-1即不支持该缓存方式。
//如果想使用需要另外配置
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//处理前先执行拦截器的preHandle方法,该方法会返回一个boolean值
//如果是true,则交给后面的Interceptor继续处理,返回false则表示自己处理完了,
//包括response也搞定了,后面的不用麻烦了直接做中断处理。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//HandlerAdapter调用Handler处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//判断是否需要viewNameTranslator从request里获取view的名字(针对在handler的返回值里没有给出的情况)
applyDefaultViewName(request, mv);
//处理完后执行拦截器的PostHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//做最后的处理工作,比如页面渲染,调用拦截器的afterCompletion方法等
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
}
finally {
//清理文件上传留下的临时文件
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//通过url匹配controller具体方法
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
核心就是第一行代码
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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);
}
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());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
核心步骤
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//requestMapping地址如 “/target”
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
//通过九大组件中获取的全量的controller匹配得到具体方法并返回
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
public interface HandlerAdapter {
//是否支持该HandlerMethod
boolean supports(Object handler);
//HandlerMthod根据反射调用controller具体方法返回modelAndView
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//最后修改时间
long getLastModified(HttpServletRequest request, Object handler);
}
处理器适配器通过反射执行controller方法核心代码
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//检查是否支持当前request的请求方式和session
checkRequest(request);
// 如果需要,在同步块中执行invokeHandlerMethod
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 {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
//判断是否有@SessionAttribute注解
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
//准备响应工作
prepareResponse(response);
}
}
return mav;
}
调用具体方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
...
}
最难也是最主要的工作获取方法反射需要的参数(及方法请求的参数)
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return this.doInvoke(args);
}
获取request、sesion、自定义对象等等参数值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
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) {
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 var10) {
if (logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
执行最后结果
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);
}
}
// 处理渲染
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);
}
}
具体渲染过程
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 国际化设置
Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 获取视图解析器
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());
}
//将model值渲染到页面上
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
通过自己配置的视图解析器,
view.render(mv.getModelInternal(), request, response);
将model值渲染到页面上