概述
通过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核心组件的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did189886