下面是当没有注册HandlerAdapter时,spring提供的默认HandlerAdapter的实现类
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
上一节看完了DefaultAnnoationHandlerMapping类,HandlerMapping对request的处理就差不多了解完了,接下来再看HandlerAdapter的概念,该接口有两个重要方法(方法所做的事情就不解释了,注释已经很清楚了):
- /**
- * Given a handler instance, return whether or not this HandlerAdapter can
- * support it. Typical HandlerAdapters will base the decision on the handler
- * type. HandlerAdapters will usually only support one handler type each.
- * <p>A typical implementation:
- * <p><code>
- * return (handler instanceof MyHandler);
- * </code>
- * @param handler handler object to check
- * @return whether or not this object can use the given handler
- */
- boolean supports(Object handler);
- /**
- * Use the given handler to handle this request.
- * The workflow that is required may vary widely.
- * @param request current HTTP request
- * @param response current HTTP response
- * @param handler handler to use. This object must have previously been passed
- * to the <code>supports</code> method of this interface, which must have
- * returned <code>true</code>.
- * @throws Exception in case of errors
- * @return ModelAndView object with the name of the view and the required
- * model data, or <code>null</code> if the request has been handled directly
- */
- ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
先来看SimpleControllerHandlerAdapter对这两个方法的实现,一句话的事情,因为太简单了:
- public boolean supports(Object handler) {
- return (handler instanceof Controller);
- }
- public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- ((Controller) handler).handleRequest(request, response);
- return null;
- }
Controller接口只是定义了handleRequest方法,所以这里的handle处理,就交给了我们实现了Controller的接口的处理类了。到这里,思路就理的很清楚了,但是我忽然有问题,这里适配支持了Controller的实现类,处理调用的是handleRequest,那method对request的处理是怎么回事呢,我们知道在detectHandler时,所有的@Request的value都被对准了一个类。先把我自己的疑惑带着吧,后面我看怎么破解我自己的疑惑。
下面就来看看AnnotationMethodHandlerAdapter类吧,这个类可比SimpleControllerHandlerAdapter复杂多了,先来看看supports方法:
- public boolean supports(Object handler) {
- return getMethodResolver(handler).hasHandlerMethods();
- }
接着去看getMethodResolver方法吧:
- /**
- * Build a HandlerMethodResolver for the given handler type.
- */
- private ServletHandlerMethodResolver getMethodResolver(Object handler) {
- Class handlerClass = ClassUtils.getUserClass(handler);
- ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);
- if (resolver == null) {
- resolver = new ServletHandlerMethodResolver(handlerClass);
- this.methodResolverCache.put(handlerClass, resolver);
- }
- return resolver;
- }
首先我查看了ClassUtils的源码,为了查找getUserClass的涵义:
- /**
- * Return the user-defined class for the given instance: usually simply
- * the class of the given instance, but the original class in case of a
- * CGLIB-generated subclass.
- * @param instance the instance to check
- * @return the user-defined class
- */
- public static Class<?> getUserClass(Object instance) {
- Assert.notNull(instance, "Instance must not be null");
- return getUserClass(instance.getClass());
- }
- /**
- * Return the user-defined class for the given class: usually simply the given
- * class, but the original class in case of a CGLIB-generated subclass.
- * @param clazz the class to check
- * @return the user-defined class
- */
- public static Class<?> getUserClass(Class<?> clazz) {
- return (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR) ?
- clazz.getSuperclass() : clazz);
- }
这里得到的结果无非是handler的父类或者自身,再回到getMethodResolver方法,下面是从缓存中取出handlerClass对应的ServletHandlerMethodResolver对象,如果缓存中没有,那么就重新构造。从看了后面的代码,我头大了,真心的,你们是不知道后面有多麻烦,先来说明ServletHandlerMethodResolver它的意思,可以理解为解析能作为serlvet使用的方法,这个内部类有点儿大,慢慢来看,先来看它的构造函数。
- private ServletHandlerMethodResolver(Class<?> handlerType) {
- init(handlerType);
- }
这里的init是它的父类HandlerMethodResovler的初始化方法:
- /**
- * Initialize a new HandlerMethodResolver for the specified handler type.
- * @param handlerType the handler class to introspect
- */
- public void init(Class<?> handlerType) {
- Class<?>[] handlerTypes =
- Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class<?>[] {handlerType};
- for (final Class<?> currentHandlerType : handlerTypes) {
- ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
- public void doWith(Method method) {
- Method specificMethod = ClassUtils.getMostSpecificMethod(method, currentHandlerType);
- if (isHandlerMethod(method)) {
- handlerMethods.add(specificMethod);
- }
- else if (method.isAnnotationPresent(InitBinder.class)) {
- initBinderMethods.add(specificMethod);
- }
- else if (method.isAnnotationPresent(ModelAttribute.class)) {
- modelAttributeMethods.add(specificMethod);
- }
- }
- }, ReflectionUtils.NON_BRIDGED_METHODS);
- }
- this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
- SessionAttributes sessionAttributes = handlerType.getAnnotation(SessionAttributes.class);
- this.sessionAttributesFound = (sessionAttributes != null);
- if (this.sessionAttributesFound) {
- this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.value()));
- this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
- }
- }
这里又出现了RelectionUtils的doWithMethods方法,我在学习札记(五)里,已经详细介绍了这个方法,在回调处理函数中,我得一层层的来剥if判断,首先是isHandlerMethod
- protected boolean isHandlerMethod(Method method) {
- return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
- }
这个很好理解了,就是查找该方法的注解,看看有没有@RequestMapping如果有,那证明它就是请求处理方法。将它加入handlerMethods集合中,下面的判断是Method类的方法,isAnnotationPresent是其父类AccessibleObject的方法,内部实现则是getAnnotation方法,这一方法在AccessibleObject中是没有具体实现的,但并非抽象,方法内部很有意思。
- public boolean isAnnotationPresent(
- Class<? extends Annotation> annotationClass) {
- return getAnnotation(annotationClass) != null;
- }
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
- throw new AssertionError("All subclasses should override this method");
- }
Method类中:
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
- if (annotationClass == null)
- throw new NullPointerException();
- return (T) declaredAnnotations().get(annotationClass);
- }
- private transient Map<Class, Annotation> declaredAnnotations;
- private synchronized Map<Class, Annotation> declaredAnnotations() {
- if (declaredAnnotations == null) {
- declaredAnnotations = AnnotationParser.parseAnnotations(
- annotations, sun.misc.SharedSecrets.getJavaLangAccess().
- getConstantPool(getDeclaringClass()),
- getDeclaringClass());
- }
- return declaredAnnotations;
- }
注意刚才的doWithMethods方法,它是有3个参数的,最有一个参数是一个过滤器:
- /**
- * Pre-built MethodFilter that matches all non-bridge methods.
- */
- public static MethodFilter NON_BRIDGED_METHODS = new MethodFilter() {
- public boolean matches(Method method) {
- return !method.isBridge();
- }
- };
什么是bridge方法,参见http://freish.iteye.com/blog/1158008 ,
再回到AnnotationMethodHandlerAdapter类的support方法中,我们可以看到hasHandlerMethods方法,该方法是HandlerMethodResolver类中方法:
- public final boolean hasHandlerMethods() {
- return !this.handlerMethods.isEmpty();
- }
只要这个handler中有@RequestMapping注解的方法,那么这个handler必然不为空。
下面我们再进入AnnotationMethodHandlerAdapter类的handle方法,看的好累 不过总算收获不小:
- public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) {
- // Always prevent caching in case of session attribute management.
- checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
- // Prepare cached set of session attributes names.
- }
- else {
- // Uses configured default cacheSeconds setting.
- checkAndPrepare(request, response, true);
- }
- // 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) {
- return invokeHandlerMethod(request, response, handler);
- }
- }
- }
- return invokeHandlerMethod(request, response, handler);
- }
首先判断该handler是否有@SessionAttributes的注解,如果有调用WebContentGenerator的checkAndPrepare。重点不在这里,重点在于invokeHandlerMethod方法:
- protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
- Method handlerMethod = methodResolver.resolveHandlerMethod(request);
- ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
- ServletWebRequest webRequest = new ServletWebRequest(request, response);
- ExtendedModelMap implicitModel = new BindingAwareModelMap();
- Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
- ModelAndView mav =
- methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
- methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
- return mav;
- }
getMethodResolver方法,我们已经看过了,因为已经创建了一次ServletHandlerMethodResolver对象为该handler,所以这次执行直接从缓存Map中读取了,下面就是为request找到适合的Method,使用resolveHandlerMethod方法,这个代码太长了,我贴上来你们别嫌烦。
- public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
- Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);
- Map<RequestMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestMappingInfo, Method>();
- Set<String> allowedMethods = new LinkedHashSet<String>(7);
- String resolvedMethodName = null;
- for (Method handlerMethod : getHandlerMethods()) {
- RequestMappingInfo mappingInfo = new RequestMappingInfo();
- RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class);
- mappingInfo.paths = mapping.value();
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {
- mappingInfo.methods = mapping.method();
- }
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {
- mappingInfo.params = mapping.params();
- }
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) {
- mappingInfo.headers = mapping.headers();
- }
- boolean match = false;
- if (mappingInfo.paths.length > 0) {
- List<String> matchedPaths = new ArrayList<String>(mappingInfo.paths.length);
- for (String methodLevelPattern : mappingInfo.paths) {
- String matchedPattern = getMatchedPattern(methodLevelPattern, lookupPath, request);
- if (matchedPattern != null) {
- if (mappingInfo.matches(request)) {
- match = true;
- matchedPaths.add(matchedPattern);
- }
- else {
- for (RequestMethod requestMethod : mappingInfo.methods) {
- allowedMethods.add(requestMethod.toString());
- }
- break;
- }
- }
- }
- Collections.sort(matchedPaths, pathComparator);
- mappingInfo.matchedPaths = matchedPaths;
- }
- else {
- // No paths specified: parameter match sufficient.
- match = mappingInfo.matches(request);
- if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 &&
- resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) {
- match = false;
- }
- else {
- for (RequestMethod requestMethod : mappingInfo.methods) {
- allowedMethods.add(requestMethod.toString());
- }
- }
- }
- if (match) {
- Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod);
- if (oldMappedMethod != null && oldMappedMethod != handlerMethod) {
- if (methodNameResolver != null && mappingInfo.paths.length == 0) {
- if (!oldMappedMethod.getName().equals(handlerMethod.getName())) {
- if (resolvedMethodName == null) {
- resolvedMethodName = methodNameResolver.getHandlerMethodName(request);
- }
- if (!resolvedMethodName.equals(oldMappedMethod.getName())) {
- oldMappedMethod = null;
- }
- if (!resolvedMethodName.equals(handlerMethod.getName())) {
- if (oldMappedMethod != null) {
- targetHandlerMethods.put(mappingInfo, oldMappedMethod);
- oldMappedMethod = null;
- }
- else {
- targetHandlerMethods.remove(mappingInfo);
- }
- }
- }
- }
- if (oldMappedMethod != null) {
- throw new IllegalStateException(
- "Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" +
- oldMappedMethod + ", " + handlerMethod +
- "}. If you intend to handle the same path in multiple methods, then factor " +
- "them out into a dedicated handler class with that path mapped at the type level!");
- }
- }
- }
- }
- if (!targetHandlerMethods.isEmpty()) {
- List<RequestMappingInfo> matches = new ArrayList<RequestMappingInfo>(targetHandlerMethods.keySet());
- RequestMappingInfoComparator requestMappingInfoComparator =
- new RequestMappingInfoComparator(pathComparator);
- Collections.sort(matches, requestMappingInfoComparator);
- RequestMappingInfo bestMappingMatch = matches.get(0);
- String bestMatchedPath = bestMappingMatch.bestMatchedPath();
- if (bestMatchedPath != null) {
- extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request);
- }
- return targetHandlerMethods.get(bestMappingMatch);
- }
- else {
- if (!allowedMethods.isEmpty()) {
- throw new HttpRequestMethodNotSupportedException(request.getMethod(),
- StringUtils.toStringArray(allowedMethods));
- }
- else {
- throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(),
- request.getParameterMap());
- }
- }
- }