springMVC有两种注册web接口的方式:
一:使用@ResquestMapper
注册
二:继承Controller接口, 使用 @Component注册Bean
不同的注册方式有不同的handle处理!!!
方式一:使用Controller接口:
编写方式:
创建自定义类,继承Controller接口,重写handleRequest方法。使用@Component(”xxx")注入映射路径。
@Component("/test")
public class TestControllerI implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("执行Controller接口自定义实现类TestControllerI了!!!");
return null;
}
}
执行逻辑:
1.首先执行DispatchServlet中的doDispatch方法,
2.getHandler() 获取 handler对象,先匹配到BeanNameHandlerMapping,再调用 getHandler(request),得到手写的集成Controller的api接口类handler对象。
3.getHandlerAdapter() 获取 adapter对象;
4. adapter对象调用 mv = ha.handle(processedRequest,response, mappedHandler.getHandler())
会执行到 SimpleControllerHandlerAdapter类中的handle(),通过强制装换成Controller接口对象,实际上就是我们写的实现Controller接口的对象,调用handleRequest()就调用了自己重写的方法。
核心代码如下:
DispatcherServlet 的doService()方法的核心代码:
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
……
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
如上代码,先通过request信息匹配获取对应的handle处理器(不同注册方式有不同的handle),然后通过handle匹配获取对应的Adapter,最后再通过Adapter对象调用handle方法,完成真实方法的调用。
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
…………
}
此处的核心代码((Controller) handler).handleRequest(request, response),这个强转就是转成我们自定义的实现Controller接口的实现类对象,调用handleRequest方法就进入到我们写的真实方法里了。
方式二:使用@RequestMapping
编写方式:
自定义类打上@Controller注解托管,使用@RequestMapping("xxx")注入映射路径。
@Controller
@RequestMapping("/test/a)
public class TestA {
@GetMapping("/get")
public ModelAndView getMyProcessApplyList() {
System.out.println("注解方式");
return null;
}
}
执行逻辑:
逻辑与方式一获取Handle逻辑一样,只不过先匹配到的mapping对象不是BeanNameHandlerMapping而是RequestMappingHandlerMapping,通过RequestMappingHandlerMapping对象,调用mapping.getHandler(request),得到的Handler对象是HandlerMethod handlerMethod,也就是我们写的方法对象的包装类。
获取的handle不同,执行ha.handle过程就不一样,接口方式进入的是 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
注解 方式进入的是
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
如上,进一步调用handleInternal方法,将执行到
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
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) {
……
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
……
return mav;
}
注意上面的核心代码 invokeHandlerMethod(request, response, handlerMethod),该方法就是调用真实方法的入口。
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
…………
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
注意上面invocableMethod.invokeAndHandle(webRequest, mavContainer) 这一行就是调用真实方法的更深一步入口。
咋们继续再往下看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()) {
disableContentCachingIfNecessary(webRequest);
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;
}
}
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);
}
这里有一行关键的代码,就是doInvoke(args),代码如下:
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
……
}
我们进入getBridgedMethod()方法,会发现获取的正是我们再controller层写的方法对象。
那么拿到了Method方法对象,再调用invoke方法,这不就是我们熟知的反射api吗!所以最终就是通过这里的反射调用了我们的真实方法。
看到这里同学们应该明白了springMVC执行方法的过程,真实方法执行以后,接下来就是视图解析,咋们下期再见!