服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 完全自定义实现SpringMVC核心组件

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

2022-12-07 20:24Spring全家桶实战案例 Java教程

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

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

概述

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

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

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

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

  1. HandlerMapping
    根据当前请求的URI,查找对应的Handler,如:HandlerExecutionChain,包装的HandlerMethod
  2. HandlerAdapter
    根据上面的确定的HandlerMethod, 找到能够处理该Handler的Adapter,进行调用
  3. 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/

延伸 · 阅读

精彩推荐