包含Spring Data Rest到mappings endpoint中

21 2月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/02/21/include-data-rest-in-mappings-endpoint/

Spring Boot提供了一套方便使用的endpoint,暴露了常用的一些应用信息,比如路由情况,堆栈情况等等,灵活的使用不仅可以加快调试,也可以方便运维。

RequestMappingEndpoint类提供了地址为mappings的endpoint,提供了是当前的路由情况,什么样的路径解析到什么样的执行器中。大概的输出如下

mapping-endpoint-sample

当然,任何你自己定义的Controller等等,都会被自动包含到这个mappings中。但是如果你使用Spring Data Rest,你就会发现它的相关信息并没有被包含到这个里面。

Mappings Endpoint原理

要解决这个问题,就需要先来看看RequestMappingEndpoint是如何工作的。

首先它并没有缓存,这意味着每次访问的时候它都会调用invoke方法来获取信息

public Map<String, Object> invoke() {
     ....
}

而Spring中的路由的映射大致讲只有两种,一种是UrlHandlerMapping,一种是MethodMapping。我们最常用的Controller配合RequestMapping的属于后者。

而处理这两种情况都是从applicationContext中获取所有实例,然后提取信息。唯一的不同是两种映射的对应信息保持方式不同而已。

Map <String,AbstractUrlHandlerMapping > mappings = applicationContext.getBeansOfType(AbstractUrlHandlerMapping.class);
for (Entry < String, AbstractUrlHandlerMapping > mapping: mappings.entrySet()) {
    Map < String, Object > handlers = getHandlerMap(mapping.getValue());
    for (Entry < String, Object > handler: handlers.entrySet()) {
        result.put(handler.getKey(), Collections.singletonMap("bean", mapping.getKey()));
    }
}

那么以这种逻辑来看,Spring Data Rest的映射也必然在这其中才对,为什么没有显示出来?

RepositoryRestHandlerMapping和其初始化

Spring Data Rest的映射是由RepositoryRestHandlerMapping处理的AbstractHandlerMethodMapping。

也就是说在RequestMappingEndpoint从上下文中获取所有MethodMapping的时候就应该获取到它。

那么来看看它的初始化过程,具体代码在RepositoryRestMvcConfiguration中

@Bean
public DelegatingHandlerMapping restHandlerMapping() {

		RepositoryRestHandlerMapping repositoryMapping = new RepositoryRestHandlerMapping(resourceMappings(), config());
		repositoryMapping.setJpaHelper(jpaHelper());
		repositoryMapping.setApplicationContext(applicationContext);
		repositoryMapping.afterPropertiesSet();

		BasePathAwareHandlerMapping basePathMapping = new BasePathAwareHandlerMapping(config());
		basePathMapping.setApplicationContext(applicationContext);
		basePathMapping.afterPropertiesSet();

		List<HandlerMapping> mappings = new ArrayList<HandlerMapping>();
		mappings.add(basePathMapping);
		mappings.add(repositoryMapping);

		return new DelegatingHandlerMapping(mappings);
	}

可以看到对上下文而言,暴露的只有DelegatingHandlerMapping本身,并没有暴露RepositoryRestHandlerMapping,而DelegatingHandlerMapping实现的是HandlerMapping。

也就是说只要暴露RepositoryRestHandlerMapping,那么mappings endpoint就能工作了。

遗憾的是RepositoryRestMvcConfiguration是data-rest-webmvc的一部分,没有修改,所以实在需要这些信息只有自己去获取并暴露出来。

暴露Spring Data Rest路由信息

自定义一个endpoint,对于invoke方法

@Override
	public Map<String, Object> invoke() {
		Map<String, Object> result = new LinkedHashMap<String, Object>();
		addDataRestMethodMappings(this.applicationContext, result);
		return result;
	}
protected void addDataRestMethodMappings(ApplicationContext applicationContext, Map<String, Object> result) {
		if (applicationContext != null) {
			RepositoryResourceMappings resourceMappings = applicationContext.getBean(RepositoryResourceMappings.class);
			RepositoryRestConfiguration config = applicationContext.getBean(RepositoryRestConfiguration.class);
			JpaHelper jpaHelper = applicationContext.getBean(JpaHelper.class);
			RepositoryRestHandlerMapping repositoryMapping = new RepositoryRestHandlerMapping(resourceMappings, config);
			repositoryMapping.setJpaHelper(jpaHelper);
			repositoryMapping.setApplicationContext(applicationContext);
			repositoryMapping.afterPropertiesSet();
			Map<?, HandlerMethod> methods = repositoryMapping.getHandlerMethods();
			for (Map.Entry<?, HandlerMethod> method : methods.entrySet()) {
				Map<String, String> map = new LinkedHashMap<String, String>();
				map.put("bean", "repositoryMapping");
				map.put("method", method.getValue().toString());
				result.put(method.getKey().toString(), map);
			}
		}
	}

当然,这段代码只是一个例子,并没有做任何安全检查和空判断。

最后效果如下:

data-rest-included-in-mappings

参考资料

https://github.com/spring-projects/spring-boot/issues/4541

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/02/21/include-data-rest-in-mappings-endpoint/

发表评论

电子邮件地址不会被公开。