springboot 获取 web 应用中所有的接口 url
最近有个小需求,要把我们一个 springboot 应用的 request mapping 给导出来,这么说已经是转化过了的,应该是要整理这个应用所有的接口路径,比如我有一个 api.baidu1.com 作为接口域名,然后这个域名下有很多个接口提供服务,这些接口都是写在一个 springboot 应用里,如果本身有网关管理这些接口转发的其实可以通过网关的数据输出,这里就介绍下通过代码来获取1
2
3
4
5
6
7
8RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
Set<String> urlSet = entry.getKey().getPatternsCondition().getPatterns();
for (String url : urlSet) {
System.out.println(url);
}
}
第一行
逐行来解析下,第一行就是从上下文中获取 RequestMappingHandlerMapping
这个 bean,
第二行
然后调用了 getHandlerMethods
,
这里面具体执行了1
2
3
4
5
6
7
8
9public Map<T, HandlerMethod> getHandlerMethods() {
this.mappingRegistry.acquireReadLock();
try {
return Collections.unmodifiableMap(this.mappingRegistry.getMappings());
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
前后加了锁,重要的就是从 mappingRegistry
中获取 mappings
, 这里获取的就是org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getMappings
具体的代码1
2
3public Map<T, HandlerMethod> getMappings() {
return this.mappingLookup;
}
而这个 mappingLookup 再来看下1
2
3
4
5class MappingRegistry {
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
可以看到就是在 MappingRegistry 中的一个变量,至于这个变量是怎么来的,简单的考虑下 springboot 处理请求的流程,就是从 Mapping 去找到对应的 Handler,所以就需要提前将这个对应关系存到这个变量里,
具体可以看这 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register
1
2
3
4
5
6
7
8
9
10
11
12
13public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
Class<?>[] parameterTypes = method.getParameterTypes();
if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
}
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
validateMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
就是在这里会把 mapping 和 handleMethod 对应关系存进去
第三行
这里拿的是上面的 map
里的 key
,也就是 RequestMappingInfo
也就是 org.springframework.web.servlet.mvc.method.RequestMappingInfo
而真的 url 就存在 org.springframework.web.servlet.mvc.condition.PatternsRequestCondition
最终这里面的patterns就是我们要的路径1
2
3
4
5
6public class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
private final static Set<String> EMPTY_PATH_PATTERN = Collections.singleton("");
private final Set<String> patterns;
写到这下一篇是不是可以介绍下 mapping 的具体注册逻辑