程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> SpringMVC源碼解析- HandlerAdapter初始化,handleradapter作用

SpringMVC源碼解析- HandlerAdapter初始化,handleradapter作用

編輯:JAVA綜合教程

SpringMVC源碼解析- HandlerAdapter初始化,handleradapter作用


HandlerAdapter初始化時,主要是進行注解解析器初始化注冊;返回值處理類初始化;全局注解@ControllerAdvice內容讀取並緩存.

目錄:

  注解解析器初始化注冊:@ModelAttribute(往model中添加屬性)

  注解解析器初始化注冊:@InitBinder(用於注冊校驗器,參數編輯器等)  

  返回值處理returnValueHandlers初始化

  全局的@ControllerAdvice注解使用類的@ModelAttribute 和 @InitBinder信息讀取並緩存 

 

注:具體解析器的分析還是看後續文章吧,要不文章跟裹腳布似的.

 

注解@ModelAttritue解析器初始化並注冊

 我們先看下@ModelAttribute注解的使用吧:

  1. 在注解中定義屬性名,方法返回值

  2. 通過model直接設置

  3.  暫時沒搞定

 1     // 在注解中定義屬性名,方法返回值
 2     @ModelAttribute("clazzName")
 3     public String setModel() {
 4         return this.getClass().getName();
 5     }
 6     // 通過model直接設置
 7     @ModelAttribute
 8     public void setModel1(Model model){
 9         model.addAttribute("movie", "who");
10     }
11     // 暫時沒搞定
12     @ModelAttribute()
13     public String setModel2(){
14         return "actor";
15     }

新建解析器時的邏輯:

  1 如果沒有配置,直接讀取默認實現

    這邊默認實現多達24種+自定義實現,主要分為4類解析器:基於注解,基於類型,自定義,號稱解析全部

  2 通過Composite封裝,並注冊

    解析策略實在太多,這邊封裝一個HandlerMethodArgumentResolverComposite,迭代解析器委托處理(有點責任鏈的味道)

先看初始化解析器,並注冊的代碼:

 1 package org.springframework.web.servlet.mvc.method.annotation;
 2 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
 3         InitializingBean {
 4     public void afterPropertiesSet() {
 5         if (this.argumentResolvers == null) {
 6             List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
 7             this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
 8         }
 9         // ...
10     }
11     private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
12         List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
13 
14         // Annotation-based argument resolution 基於注解的解析器
15         resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
16         resolvers.add(new RequestParamMapMethodArgumentResolver());
17         resolvers.add(new PathVariableMethodArgumentResolver());
18         resolvers.add(new PathVariableMapMethodArgumentResolver());
19         resolvers.add(new MatrixVariableMethodArgumentResolver());
20         resolvers.add(new MatrixVariableMapMethodArgumentResolver());
21         resolvers.add(new ServletModelAttributeMethodProcessor(false));
22         resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
23         resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
24         resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
25         resolvers.add(new RequestHeaderMapMethodArgumentResolver());
26         resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
27         resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
28 
29         // Type-based argument resolution 基於類型的解析器
30         resolvers.add(new ServletRequestMethodArgumentResolver());
31         resolvers.add(new ServletResponseMethodArgumentResolver());
32         resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
33         resolvers.add(new RedirectAttributesMethodArgumentResolver());
34         resolvers.add(new ModelMethodProcessor());
35         resolvers.add(new MapMethodProcessor());
36         resolvers.add(new ErrorsMethodArgumentResolver());
37         resolvers.add(new SessionStatusMethodArgumentResolver());
38         resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
39 
40         // Custom arguments 自定義解析器
41         if (getCustomArgumentResolvers() != null) {
42             resolvers.addAll(getCustomArgumentResolvers());
43         }
44 
45         // Catch-all 全能的解析器
46         resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
47         resolvers.add(new ServletModelAttributeMethodProcessor(true));
48 
49         return resolvers;
50     }
51 }

 

然後是HandlerMethodArgumentResolverComposite迭代具體解析器委托處理的代碼:

GOF對責任鏈意圖的定義是:

  使多個對象都有機會iu處理請求,從而避免請求的發送者和接受者直接的耦合關系.將這些對象連成一條鏈,並沿這條鏈傳遞該請求,直到有一個對象處理它為止.

  從百度百科盜了個類圖,來類比下:

上面是標准的責任鏈,下面是HandlerMethodReturnValueHandler部分類圖

 1 package org.springframework.web.method.support;
 2 public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
 3     public Object resolveArgument(
 4             MethodParameter parameter, ModelAndViewContainer mavContainer,
 5             NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
 6             throws Exception {
 7 
 8         HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
 9         return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
10     }
11     public boolean supportsParameter(MethodParameter parameter) {
12         return getArgumentResolver(parameter) != null;
13     }
14     private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
15         HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
16         if (result == null) {
17             for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
18                 if (methodArgumentResolver.supportsParameter(parameter)) {
19                     result = methodArgumentResolver;
20                     this.argumentResolverCache.put(parameter, result);
21                     break;
22                 }
23             }
24         }
25         return result;
26     }
27     // ...
28 }

  

 

注解@InitBinder解析器初始化

 先看@InitBinder注解的使用吧:

 1     /**
 2      * 使用WebDataBinder實現日期校驗
 3      * @param dataBinder
 4      */
 5     @InitBinder
 6     public void dateFormat(WebDataBinder dataBinder){
 7         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
 8         dateFormat.setLenient(false);
 9         dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false));
10     }

這邊的代碼邏輯其實跟@ModelAttribute解析器初始化的邏輯是一樣的,就不具體分析,只是這邊初始化使用的解析器是不一樣的.至於差異的原因,暫時還不知道,哪位有興趣可以幫忙科普科普.

 1 package org.springframework.web.servlet.mvc.method.annotation;
 2 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
 3         InitializingBean {
 4     private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
 5         List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
 6 
 7         // Annotation-based argument resolution 基於注解的解析器
 8         resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
 9         resolvers.add(new RequestParamMapMethodArgumentResolver());
10         resolvers.add(new PathVariableMethodArgumentResolver());
11         resolvers.add(new PathVariableMapMethodArgumentResolver());
12         resolvers.add(new MatrixVariableMethodArgumentResolver());
13         resolvers.add(new MatrixVariableMapMethodArgumentResolver());
14         resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
15 
16         // Type-based argument resolution 基於類型的解析器
17         resolvers.add(new ServletRequestMethodArgumentResolver());
18         resolvers.add(new ServletResponseMethodArgumentResolver());
19 
20         // Custom arguments 自定義解析器
21         if (getCustomArgumentResolvers() != null) {
22             resolvers.addAll(getCustomArgumentResolvers());
23         }
24 
25         // Catch-all 全能的解析器
26         resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
27 
28         return resolvers;
29     }
30     // ...
31 }

 

 

返回值處理returnValueHandlers初始化

用於將handler處理器的返回值封裝成ModelAndView.

這邊的處理邏輯跟@ModelAttribute注解解析器的初始化高度雷同,我們還是看看使用的HandlerMethodReturnValueHandler接口

 接口的定義方式也是高度雷同,一個api問是否支持,一個api進行具體處理.

1 package org.springframework.web.method.support;
2 public interface HandlerMethodReturnValueHandler {
3     boolean supportsReturnType(MethodParameter returnType);
4     void handleReturnValue(Object returnValue,
5                            MethodParameter returnType,
6                            ModelAndViewContainer mavContainer,
7                            NativeWebRequest webRequest) throws Exception;
8 
9 }

分類貌似也有一定的相似.

 1 package org.springframework.web.servlet.mvc.method.annotation;
 2 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
 3         InitializingBean {
 4     private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
 5         List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
 6 
 7         // Single-purpose return value types 單一目的
 8         handlers.add(new ModelAndViewMethodReturnValueHandler());
 9         handlers.add(new ModelMethodProcessor());
10         handlers.add(new ViewMethodReturnValueHandler());
11         handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
12         handlers.add(new CallableMethodReturnValueHandler());
13         handlers.add(new DeferredResultMethodReturnValueHandler());
14         handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
15 
16         // Annotation-based return value types 基於注解
17         handlers.add(new ModelAttributeMethodProcessor(false));
18         handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
19 
20         // Multi-purpose return value types 多目的
21         handlers.add(new ViewNameMethodReturnValueHandler());
22         handlers.add(new MapMethodProcessor());
23 
24         // Custom return value types 自定義
25         if (getCustomReturnValueHandlers() != null) {
26             handlers.addAll(getCustomReturnValueHandlers());
27         }
28 
29         // Catch-all    又是全能
30         if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
31             handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
32         }
33         else {
34             handlers.add(new ModelAttributeMethodProcessor(true));
35         }
36 
37         return handlers;
38     }
39 }

 

 

 

全局的@ControllerAdvice注解使用類的@ModelAttribute 和 @InitBinder信息讀取並緩存 

@ControllerAdvice注解主要是為了解決以下的場景問題:

  如果@ModelAttribute或@InitBinder注解如果需要在很多地方使用,怎麼辦?

  使用集成的話,由於java的單繼承會限制父類,不夠靈活.

 

使用時只需要如下添加注解就可以

1 @ControllerAdvice()
2 public class AdviceController {
3     // ...
4 }

 

源碼解析時,是通過InitializingBean的afterPropertiesSet調用initControllerAdviceCache初始化的解析器.

查找使用注解@ControllerAdivce的類時,通過spring迭代容器過濾容器中全部的類,找到使用ControllerAdvice.class的類並注冊.

 1 package org.springframework.web.servlet.mvc.method.annotation;
 2 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
 3         InitializingBean {
 4     public void afterPropertiesSet() {
 5         // ...
 6         initControllerAdviceCache();
 7     }
 8     private void initControllerAdviceCache() {
 9         // ...
10         // 掃描方式找到使用@ControllerAdvice的類
11         List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
12         Collections.sort(beans, new OrderComparator());
13 
14         for (ControllerAdviceBean bean : beans) {
15             Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
16             if (!attrMethods.isEmpty()) {
17                 this.modelAttributeAdviceCache.put(bean, attrMethods);
18             }
19             Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
20             if (!binderMethods.isEmpty()) {
21                 this.initBinderAdviceCache.put(bean, binderMethods);
22             }
23         }
24     }
25 }

 

這邊掃描獲取類的方式跟之前的有所不同,我們可以細看下.

 1 package org.springframework.web.method;
 2 public class ControllerAdviceBean implements Ordered {
 3     /**
 4      * Find the names of beans annotated with
 5      * {@linkplain ControllerAdvice @ControllerAdvice} in the given
 6      * ApplicationContext and wrap them as {@code ControllerAdviceBean} instances.
 7      */
 8     public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext applicationContext) {
 9         List<ControllerAdviceBean> beans = new ArrayList<ControllerAdviceBean>();
10         for (String name : applicationContext.getBeanDefinitionNames()) {
11             if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) {
12                 beans.add(new ControllerAdviceBean(name, applicationContext));
13             }
14         }
15         return beans;
16     }
17 }

看下兩個api在接口中定義:

  1. getBeanDefinitionNames 返回容器中定義的全部bean 的 name

  2. findAnnotationOnBean 查找類上定義的注解,包括父類與接口

 1 package org.springframework.beans.factory;
 2 public interface ListableBeanFactory extends BeanFactory {
 3     // ... 
 4     /**
 5      * Return the names of all beans defined in this factory.
 6      * <p>Does not consider any hierarchy this factory may participate in,
 7      * and ignores any singleton beans that have been registered by
 8      * other means than bean definitions.
 9      * @return the names of all beans defined in this factory,
10      * or an empty array if none defined
11      */
12     String[] getBeanDefinitionNames();
13     /**
14      * Find a {@link Annotation} of {@code annotationType} on the specified
15      * bean, traversing its interfaces and super classes if no annotation can be
16      * found on the given class itself.
17      * @param beanName the name of the bean to look for annotations on
18      * @param annotationType the annotation class to look for
19      * @return the annotation of the given type found, or {@code null}
20      */
21     <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType);
22 
23 }

順便關心下@ControllerAdvice信息是如何保存的,就是對應的pojo ControllerAdviceBean:

這邊只是記錄bean,還沒有添加添加根據類,包進行過濾匹配類的功能.

這邊值得說的有3個:

  1. 根據類是否實現Ordered接口,設置排序順序

  2. 掃描應用下使用ControllerAdvice注解的類就是上面說的api

  3. 實現getBeanType獲取類的類型 和resolveBean獲取類實例 ,這個算是advice的行為吧.作為容器的行為吧.

 1 package org.springframework.web.method;
 2 
 3 public class ControllerAdviceBean implements Ordered {
 4     // 使用注解的類
 5     private final Object bean;
 6     private final int order;
 7     private final BeanFactory beanFactory;
 8 
 9     public ControllerAdviceBean(String beanName, BeanFactory beanFactory) {
10         // ...
11     }
12 
13     public ControllerAdviceBean(Object bean) {
14         // ...
15     }
16 
17     // 如果類實現Ordered,根據order的值設置排序
18     private static int initOrderFromBeanType(Class<?> beanType) {
19         Order annot = AnnotationUtils.findAnnotation(beanType, Order.class);
20         return (annot != null) ? annot.value() : Ordered.LOWEST_PRECEDENCE;
21     }
22 
23     private static int initOrderFromBean(Object bean) {
24         return (bean instanceof Ordered) ? ((Ordered) bean).getOrder() : initOrderFromBeanType(bean.getClass());
25     }
26 
27     /**
28      * 掃描應用下使用ControllerAdvice注解的類
29      */
30     public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext applicationContext) {
31         List<ControllerAdviceBean> beans = new ArrayList<ControllerAdviceBean>();
32         for (String name : applicationContext.getBeanDefinitionNames()) {
33             if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) {
34                 beans.add(new ControllerAdviceBean(name, applicationContext));
35             }
36         }
37         return beans;
38     }
39 
40     public Class<?> getBeanType() {
41         Class<?> clazz = (this.bean instanceof String)
42                 ? this.beanFactory.getType((String) this.bean) : this.bean.getClass();
43 
44         return ClassUtils.getUserClass(clazz);
45     }
46 
47     public Object resolveBean() {
48         return (this.bean instanceof String) ? this.beanFactory.getBean((String) this.bean) : this.bean;
49     }
50     // ...
51 }

 

  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved