编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

SpringMVC自定义注解实现接口调用

wxchong 2024-06-27 01:39:19 开源技术 37 ℃ 0 评论

环境:springboot2.2.10.RELEASE

建议先阅读上一篇文章:SpringMVC请求原理源码分析


开发步骤:

  1. 自定义的注解类
@Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomEndpoint {
}

@CustomEndpoint注解标识自定义的类(Bean)在该注解中添加了@Component注解为了让容器管理我们的类(生成Bean)。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackMapping {
	// 请求URL
	String[] value() default {};
	// 请求的方法
	RequestMethod[] method() default {};
}

该注解就相当于@RequestMapping注解,定义请求接口。

  1. 自定义HandlerMapping

自定义HandlerMapping的作用是让HandlerMapping与我们自定义的@CustomEndpoint类相关联,简单说就是能够处理标有@CustomEndpoint注解的类。

public class CustomPackRequestHandlerMapping extends RequestMappingHandlerMapping {

  // 该方法是必须重写的,使得自定义的HandlerMapping能够处理标有@CustomEndpoint注解的类
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return AnnotatedElementUtils.hasAnnotation(beanType, CustomEndpoint.class);
	}
	
  // 该方法也必须重写不然你的这个自定义HandlerMapping将轮不到就被(SimpleUrlHandlerMapping)处理了。
	@Override
    public void afterPropertiesSet() {
        super.setOrder(0); // 这里很重要使得我们的HandlerMapping能够排到最前面
        super.afterPropertiesSet();
    }
	
  // 该方法必须重写因为你要针对标有自定义@PackMapping注解的方法能够处理你的请求。
	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo requestMappingInfo = createRequestMappingInfo(method) ;
		return requestMappingInfo ;
	}
	
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		PackMapping packMapping = AnnotatedElementUtils.findMergedAnnotation(element, PackMapping.class);
		return (packMapping != null ? builderMapping(packMapping) : null);
	}
	
	private RequestMappingInfo builderMapping(PackMapping packMapping) {
		RequestMappingInfo.Builder builder = RequestMappingInfo
				.paths(packMapping.value())
				.methods(packMapping.method())
				.params(new String[] {})
				.headers(new String[] {})
				.consumes(new String[] {})
				.produces(new String[] {})
				.mappingName("") ;
		return builder.build() ;
	}

}

以上自定义的HandlerMapping重要的方法已经说明了。

  1. 配置HandlerMapping
@Configuration
public class CustomEndpointConfig {
	
	@Bean
	public CustomPackRequestHandlerMapping customPackRequestHandlerMapping() {
		CustomPackRequestHandlerMapping handlerMapping = new CustomPackRequestHandlerMapping() ;
		return handlerMapping ;
	}
	
}
  1. 测试
@CustomEndpoint
@ResponseBody
public class CustomWebController {

	@PackMapping("/custom/index")
	public Object index(String key) {
		return key ;
	}
	
}


到此开发一个自定义的HandlerMapping就完成了。

真正实际的调用(Controller方法)其实是HandlerAdapter。

AbstractHandlerMethodAdapter类中定义了如下方法,是专门为让子类来实现的,我们可以根据自己的需要作相应的重写。

protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

查看 RequestMappingHandlerAdapter类的实现。

@Override
	protected boolean supportsInternal(HandlerMethod handlerMethod) {
		return true;
	}

这里在说下一些核心类之间的关系:

所有的拦截器也是与HandlerMapping关联的:

@Bean
	@SuppressWarnings("deprecation")
	public RequestMappingHandlerMapping requestMappingHandlerMapping(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setContentNegotiationManager(contentNegotiationManager);
		mapping.setCorsConfigurations(getCorsConfigurations());

		...

		return mapping;
	}

mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));

消息转换与HandlerAdapter相关联

@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcValidator") Validator validator) {

		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
		adapter.setContentNegotiationManager(contentNegotiationManager);
		adapter.setMessageConverters(getMessageConverters());
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

		if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}

		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

		return adapter;
	}

adapter.setMessageConverters(getMessageConverters());


好心人给个关注+转发谢谢啊

Spring Cloud Sentinel 熔断降级

Spring Cloud Gateway应用详解1之谓词

SpringBoot开发自己的@Enable功能

springboot中定时任务执行Quartz的使用

Springboot之Actuator详解

SpringMVC请求原理源码分析

2、SpringCloud 注册中心配置

SpringMVC内嵌Tomcat零配置

springboot 中使用JWT保护资源安全

springboot 基于数据库的乐观锁实现

SpringBoot2 整合 OAuth2 资源认证(保护)

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表