spring callstack¶
这个callstack记录了spring在收到一个request之后是怎样分发给对应的controller的。Spring版本是org.springframework:spring-core:4.2.7。
可参考:https://docs.spring.io/spring/docs/current/javadoc-api/
f0 hello.GreetingController#greeting¶
最终将请求127.0.0.1:8080/greeting分发给这个controller的greeting方法,除此之外没啥好说的。
f1 sun.reflect.NativeMethodAccessorImpl#invoke0¶
private static native Object invoke0(Method var0, Object var1, Object[] var2);
f2 sun.reflect.NativeMethodAccessorImpl#invoke¶
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
// step 0. 增加调用此方法的计数,此处应该是安全检查,与spring无关,不展开讨论,注意可能会抛出异常即可
if(++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}
// step 1. 通过这行调用f1
return invoke0(this.method, var1, var2);
}
f3 sun.reflect.DelegatingMethodAccessorImpl#invoke¶
// 不是spring package的类,不展开讨论,注意一下函数签名即可
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
return this.delegate.invoke(var1, var2);
}
f4 java.lang.reflect.Method#invoke¶
平常使用的Method类,与Spring无关。
// obj的内容是GreetingController, args里面只有一个“World”字符串
public Object invoke(Object obj, Object... args)
{
...
}
可以看出hello.GreetingController#greeting对应了spring中的一个Method对象,通过反射来触发调用greeting函数。
f5 org.springframework.web.method.support.InvocableHandlerMethod#doInvoke¶
该类位于spring-web模块。
protected Method getBridgedMethod() {
return this.bridgedMethod;
}
// args里面只有一个“World”字符串
protected Object doInvoke(Object... args) throws Exception {
// spring支持将greeting方法声明为private
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 此处调用f4
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
...
}
catch (InvocationTargetException ex) {
...
}
异常情况不展开讨论,因为我们只关注spring核心逻辑。因此org.springframework.web.method.support.InvocableHandlerMethod#doInvoke只是java.lang.reflect.Method#invoke的一个简单的wrapper,处理一些反射时出现的异常情况,无他。
f6 org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest¶
该类位于spring-web模块。
// 入参的内容
// ServletWebRequest: uri=/greeting;client=127.0.0.1
// ModelAndViewContainer: View is [null]; default model {}
// 可以发现
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// step 0. 从NativeWebRequest和ModelAndViewContainer 中提取参数,关注主要逻辑,暂不看细节实现
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// step 1. 打开trace log会有日志,protected final Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
// step 2. 此处调用f5
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
invokeForRequest只是根据request等入参来获取greeting方法参数列表中的参数,然后通过反射来调用greeting方法。
f7 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle¶
该类位于spring-webmvc模块。
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// step 0. 此处调用f6来获取此次request的返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// step 1. 设置webRequest对象的响应状态,在这次请求中,由于响应状态是null,实际上webRequest没有设置响应状态。
// todo: 看一下greeting抛出exception时是怎样处理的。
setResponseStatus(webRequest);
// step 2. 处理mavContainer对象的状态
...
mavContainer.setRequestHandled(true);
// step 3. 处理返回值,值得一看,暂时略过,因为f8中会仔细分析
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
...
}
这里step 3的returnValueHandlers使用了组合设计模式,可简单参考org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite,关注主要逻辑,暂时无需关注太多。
f8 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod¶
这部分略抽象,我们仅需知道,我们的greeting使用了@RequestMapping注解,所以会选择RequestMappingHandlerAdapter来调度执行相应的方法。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 可参考http://lgbolgger.iteye.com/blog/2111003
...
// 此处调用f7
invocableMethod.invokeAndHandle(webRequest, mavContainer);
...
}
f9 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal¶
使用handlerMethod来内部处理request,暂时无需关注过多。
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...
}
f10 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle¶
使用handlerMethod来处理request,暂时无需关注过多。
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
f11 org.springframework.web.servlet.DispatcherServlet#doDispatch¶
将请求分发给对应的handler。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
}
思考(to do):
这段代码是怎样分发到对应的handlerMethod的?
f12 org.springframework.web.servlet.DispatcherServlet#doService¶
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
}
f13 org.springframework.web.servlet.FrameworkServlet#processRequest¶
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
}
f14 org.springframework.web.servlet.FrameworkServlet#doGet¶
暴露给容器的Servlet,可以看出这个是springframework的入口servlet
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
f15 javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)¶
注意这个类是HttpServlet即可
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
...
}
可以看出,从f1到f15是分发请求并处理的完整过程,这个过程的入口是HttpServlet的service方法。
f15之后¶
在f15之后的栈帧,除了filter这个过程含有spring的实现类,其它都是发生在org.apache.catalina这个包中的,这里只关注spring相关的内容,spring对于filter的实现,主要参考org.springframework.web.filter.RequestContextFilter#doFilterInternal和org.springframework.web.filter.OncePerRequestFilter#doFilter即可,他们都是javax.servlet.Filter的子类。