当前位置: 首页 > 科技观察

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

时间:2023-03-21 19:10:37 科技观察

概述通过Spring定义请求接口是非常容器化的,可以通过几个注解来完成,如下:@RestController@RequestMapping("/demos")publicclassDemoController{@GetMapping("/index")publicObjectindex(){return"index";}}通过上面的@RestController,@RequestMapping完成了一个简单的接口定义。其实SpringWeb的底层做了很多工作,其核心组件包括HandlerMapping、HandlerAdapter、ViewResolver等组件。HandlerMapping根据当前请求的URI找到对应的Handler,如:HandlerExecutionChain,封装后的HandlerMethodHandlerAdapter根据上面确定的HandlerMethod找到可以处理Handler的Adapter,调用ViewResolver。如果返回的ModelAndView对象是通过对应的ViewResolverOutput渲染的了解了以上核心组件后,接下来就是自定义以上核心类的实现,完成接口的请求处理。CustomizeEndpoint自定义注解来标记Controller类和请求参数:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfacePackEndpoint{}参数标记,用于注解接口参数。@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfacePackParam{}Endpoint接口参数封装对象该对象用于保存记录,方法参数为@PackParam注解的参数。publicclassPackMethodParameter{//用于解析接口参数的名称privateParameterNameDiscovererparameterNameDiscoverer=newLocalVariableTableParameterNameDiscoverer();私有字符串名称;私有可执行文件可执行文件;私有int参数索引;私有类类型;publicPackMethodParameter(Stringname,intparameterIndex,Executableexecutable){this.name=name;this.parameterIndex=parameterIndex;this.executable=executable;}publicPackMethodParameter(intparameterIndex,Executableexecutable,Classtype){this.parameterIndex=parameterIndex;this.executable=executable;this.type=类型;}publicbooleanhasParameterAnnotation(Classclazz){Methodmethod=(Method)this.executable;参数[]参数=方法.getParameters();返回参数[this.parameterIndex].isAnnotationPresent(clazz);}publicStringgetParameterName(){String[]parameterNames=parameterNameDiscoverer.getParameterNames((Method)this.executable);返回参数名[this.parameterIndex];}}CustomHandlerMapping自定义实现SpringMVC标准的HandlerMapping,使其在DispatcherServlet中能够被识别公共类PackHandlerMapping实现HandlerMapping、InitializingBean、ApplicationContextAware{privateApplicationContext上下文;privateMapmapping=newHashMap<>();@OverridepublicHandlerExecutionChaingetHandler(HttpServletRequestrequest)抛出异常{StringrequestPath=request.getRequestURI();可选opt=mapping.entrySet().stream().filter(entry->entry.getKey().equals(requestPath)).findFirst().map(Map.Entry::getValue);if(opt.isPresent()){HandlerExecutionChainexecutionChain=newHandlerExecutionChain(opt.get());返回执行链;}返回空值;}//Bean初始化时,从容器中查找所有符合条件的Bean对象,即Bean对象上有@PackEndpoint注解@OverridepublicvoidafterPropertiesSet()throwsException{String[]beanNames=context.getBeanNamesForType(Object.class);for(StringbeanName:beanNames){对象bean=this.context.getBean(豆名);类clazz=bean.getClass();//判断当前Bean上是否有PackEndpoint注解,只处理有这个注解的类if(clazz.getAnnotation(PackEndpoint.class)!=null){StringrootPath=clazzMapping.value()[0];if(clazzMapping!=null){ReflectionUtils.doWithMethods(clazz,method->{RequestMappingnestMapping=AnnotatedElementUtils.findMergedAnnotation(method,RequestMapping.class);if(nestMapping!=null){StringnestPath=nestMapping.value()[0];Stringpath=rootPath+nestPath;PackMethodHandlerhandler=newPackMethodHandler(method,bean);mapping.put(path,handler);}});}}}}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.context=应用上下文;}//该类的作用:用来记录接口对应的信息,方法,对应的实例,参数信息publicstaticclassPackMethodHandler{privateMethodmethod;私有对象实例;私有PackMethodParameter[]参数;publicMethodgetMethod(){返回方法;}publicvoidsetMethod(Methodmethod){this.method=method;}publicObjectgetInstance(){返回实例;}publicvoidsetInstance(Objectinstance){this.instance=instance;}publicPackMethodHandler(方法方法,对象实例){super();this.method=方法;this.instance=实例;参数[]params=method.getParameters();this.parameters=newPackMethodParameter[params.length];for(inti=0;i

最新推荐
猜你喜欢