好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

完全自定义实现SpringMVC核心组件

概述

通过Spring定义请求接口非常容器,通过几个注解就可以完成,如下:

 @RestController   @RequestMapping ( "/demos" )  public   class   DemoController  {  @GetMapping ( "/index" )  public   Object   index () {  return   "index"  ;
  }
}

通过上面的@RestController, @RequestMapping就完成了一个简单的接口定义。

实际Spring Web底层是做了很多的工作,其核心组件有HandlerMapping, HandlerAdapter, ViewResolver等组件。

HandlerMapping
根据当前请求的URI,查找对应的Handler,如: HandlerExecutionChain ,包装的 HandlerMethod HandlerAdapter
根据上面的确定的HandlerMethod, 找到能够处理该Handler的Adapter,进行调用 ViewResolver
如果返回的 ModelAndView 对象那么会通过相应的 ViewResolver 进行渲染输出

了解了上面的几个核心组件之后,接下来就是自定义实现上面的核心类,来完成接口的请求处理。

自定义Endpoint

自定义注解,标记Controller类及请求参数:

  @Target ( ElementType . TYPE )  @Retention ( RetentionPolicy . RUNTIME )  @Documented   public   @interface   PackEndpoint  {
 }

参数标记,用来对接口参数进行注解。

  @Target ( ElementType . PARAMETER )  @Retention ( RetentionPolicy . RUNTIME )  @Documented   public   @interface   PackParam  {
 }

Endpoint接口参数封装对象

该对象用来保存记录,方法参数由 @PackParam 注解的参数。

 public   class   PackMethodParameter  {  // 用来解析接口参数的名称   private   ParameterNameDiscoverer   parameterNameDiscoverer   =   new   LocalVariableTableParameterNameDiscoverer () ;  private   String   name  ;  private   Executable   executable  ;  private   int   parameterIndex  ;  private   Class      type  ;  public   PackMethodParameter ( String   name ,  int   parameterIndex ,  Executable   executable ) {  this . name   =   name ;  this . parameterIndex   =   parameterIndex  ;  this . executable   =   executable  ;
  }  public   PackMethodParameter ( int   parameterIndex ,  Executable   executable ,  Class      type ) {  this . parameterIndex   =   parameterIndex  ;  this . executable   =   executable  ;  this . type   =   type  ;
  }  public   boolean   hasParameterAnnotation ( Class     extends   Annotation  >   clazz ) {  Method   method   =  ( Method )  this . executable  ;  Parameter []  parameters   =   method . getParameters () ;  return   parameters [ this . parameterIndex ]. isAnnotationPresent ( clazz ) ;
  }  public   String   getParameterName () {  String []  parameterNames   =   parameterNameDiscoverer . getParameterNames (( Method )  this . executable ) ;  return   parameterNames [ this . parameterIndex ] ;
  } 
} 

自定义HandlerMapping

自定义实现了SpringMVC标准的HandlerMapping,这样在DispatcherServlet中才能够识别。

 public   class   PackHandlerMapping   implements   HandlerMapping ,  InitializingBean ,  ApplicationContextAware  {  private   ApplicationContext   context ;  private   Map  <  String ,  PackMethodHandler  >   mapping   =   new   HashMap  <> ();  @Override   public   HandlerExecutionChain   getHandler ( HttpServletRequest   request )  throws   Exception  {  String   requestPath   =   request . getRequestURI ();  Optional  <  PackMethodHandler  >   opt   =   mapping . entrySet (). stream (). filter ( entry   ->   entry . getKey (). equals ( requestPath )). findFirst ()
        . map ( Map . Entry :: getValue );  if  ( opt . isPresent ()) {  HandlerExecutionChain   executionChain   =   new   HandlerExecutionChain ( opt . get ()) ;  return   executionChain  ;
    }  return   null ;
  }  // Bean初始化时,从容器中查找所有符合条件的Bean对象,即Bean对象上有@PackEndpoint注解   @Override   public   void   afterPropertiesSet ()  throws   Exception  {  String []  beanNames   =   context . getBeanNamesForType ( Object . class ) ;  for  ( String   beanName  :  beanNames ) {  Object   bean   =   this . context . getBean ( beanName ) ;  Class      clazz   =   bean . getClass () ;  // 判断当前的Bean上是否有PackEndpoint注解,只对有该注解的类进行处理   if  ( clazz . getAnnotation ( PackEndpoint . class )  !=   null ) {  RequestMapping   clazzMapping   =   clazz . getAnnotation ( RequestMapping . class ) ;  String   rootPath   =   clazzMapping . value ()[ 0 ] ;  if  ( clazzMapping   !=   null ) {  ReflectionUtils . doWithMethods ( clazz ,  method   ->  {  RequestMapping   nestMapping   =   AnnotatedElementUtils . findMergedAnnotation ( method ,  RequestMapping . class ) ;  if  ( nestMapping   !=   null ) {  String   nestPath   =   nestMapping . value ()[ 0 ] ;  String   path   =   rootPath   +   nestPath  ;  PackMethodHandler   handler   =   new   PackMethodHandler ( method ,  bean ) ;  mapping . put ( path ,  handler ) ;
            }
          }) ;
        }
      }
    }
  }  @Override   public   void   setApplicationContext ( ApplicationContext   applicationContext )  throws   BeansException  {  this . context   =   applicationContext ;
  }  // 该类的作用:用来记录接口对应的信息,方法,对应的实例,参数信息   public   static   class   PackMethodHandler  {  private   Method   method ;  private   Object   instance ;  private   PackMethodParameter []  parameters  ;  public   Method   getMethod (){  return   method ;
    }  public   void   setMethod ( Method   method ){  this . method   =   method ;
    }  public   Object   getInstance (){  return   instance ;
    }  public   void   setInstance ( Object   instance ){  this . instance   =   instance ;
    }  public   PackMethodHandler ( Method   method ,  Object   instance ){  super ();  this . method   =   method ;  this . instance   =   instance ;  Parameter []  params   =   method . getParameters () ;  this . parameters   =   new   PackMethodParameter [ params . length ] ;  for  ( int   i   =   0 ;  i   <   params . length ;  i  ++ ) {  this . parameters [ i ]  =   new   PackMethodParameter ( i ,  method ,  params [ i ]. getType ()) ;
      }
    }  public   PackMethodParameter []  getParameter () {  return   this . parameters  ;
    }
  }
}

自定义参数解析器

专门用来解析处理接口方法中的参数信息然后从请求中读取。

 public   interface   PackHandlerMethodArgumentResolver  {  boolean   supportsParameter ( PackMethodParameter   methodParameter );  Object   resolveArgument ( PackMethodParameter   methodParameter ,  HttpServletRequest   request );
}  public   class   PackParamHandlerMethodArgumentResolver   implements   PackHandlerMethodArgumentResolver  {  @Override   public   boolean   supportsParameter ( PackMethodParameter   methodParameter ){  return   methodParameter . hasParameterAnnotation ( PackParam . class ) ;
  }  @Override   public   Object   resolveArgument ( PackMethodParameter   methodParameter ,  HttpServletRequest   request ){  String   name   =   methodParameter . getParameterName () ;  Object   arg   =   null ;  String []  parameterValues   =   request . getParameterValues ( name ) ;  if  ( parameterValues   !=   null ) {  arg   =   parameterValues . length   ==   1   ?   parameterValues [ 0 ] :  parameterValues  ;
    }  return   arg  ;
  }
}

自定义HandlerAdapter

自定义实现了SpringMVC标准的HandlerAdatper,这样在DispatcherServlet中才能够识别。

 public   class   PackHandlerAdapter   implements   HandlerAdapter {  @Resource   private   ConversionService   conversionService  ;  private   PackParamHandlerMethodArgumentResolver   argumentResolver   =   new   PackParamHandlerMethodArgumentResolver () ;  @Override   public   boolean   supports ( Object   handler ){  return   handler   instanceof   PackMethodHandler ;
  }  @Override   public   ModelAndView   handle ( HttpServletRequest   request ,  HttpServletResponse   response ,  Object   handler )  throws   Exception  {  PackMethodHandler   methodHandler   =  ( PackMethodHandler )  handler  ;  PackMethodParameter []  parameters   =   methodHandler . getParameter () ;  Object []  args   =   new   Object [ parameters . length ] ;  for  ( int   i   =   0 ;  i   <   args . length ;  i  ++ ) {  if  ( this . argumentResolver . supportsParameter ( parameters [ i ])) {  // 解析对应的方法参数   args [ i ]  =   this . argumentResolver . resolveArgument ( parameters [ i ],  request ) ;  // 类型转换   args [ i ]  =   this . conversionService . convert ( args [ i ],  parameters [ i ]. getType ()) ;
      }
    }  // 调用目标方法   Object   result   =   methodHandler . getMethod (). invoke ( methodHandler . getInstance (),  args ) ;  // 设置响应header,输出内容   response . setHeader ( "Content-Type" ,  "text/plain;charset=utf8" ) ;  PrintWriter   out   =   response . getWriter () ;  out . write (( String )  result ) ;  out . flush () ;  out . close () ;  return   null  ;
  }  @Override   public   long   getLastModified ( HttpServletRequest   request ,  Object   handler ){  return   -  1  ;
  }

}

通过以上的步骤就完成了一个完全自定义SpringMVC核心组件的实现。

原文地址:https://www.toutiao.com/article/7172758686195220995/

查看更多关于完全自定义实现SpringMVC核心组件的详细内容...

  阅读:21次