本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2016/02/21/include-data-rest-in-mappings-endpoint/
Spring Boot提供了一套方便使用的endpoint,暴露了常用的一些应用信息,比如路由情况,堆栈情况等等,灵活的使用不仅可以加快调试,也可以方便运维。
RequestMappingEndpoint类提供了地址为mappings的endpoint,提供了是当前的路由情况,什么样的路径解析到什么样的执行器中。大概的输出如下
当然,任何你自己定义的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); } } }
当然,这段代码只是一个例子,并没有做任何安全检查和空判断。
最后效果如下:
参考资料
https://github.com/spring-projects/spring-boot/issues/4541
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2016/02/21/include-data-rest-in-mappings-endpoint/