3

springboot 获取 web 应用中所有的接口 url

 9 months ago
source link: https://nicksxs.me/2023/08/06/springboot-%E8%8E%B7%E5%8F%96-web-%E5%BA%94%E7%94%A8%E4%B8%AD%E6%89%80%E6%9C%89%E7%9A%84%E6%8E%A5%E5%8F%A3-url/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

springboot 获取 web 应用中所有的接口 url

最近有个小需求,要把我们一个 springboot 应用的 request mapping 给导出来,这么说已经是转化过了的,应该是要整理这个应用所有的接口路径,比如我有一个 api.baidu1.com 作为接口域名,然后这个域名下有很多个接口提供服务,这些接口都是写在一个 springboot 应用里,如果本身有网关管理这些接口转发的其实可以通过网关的数据输出,这里就介绍下通过代码来获取

RequestMappingHandlerMapping 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,
这里面具体执行了

public 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 具体的代码

public Map<T, HandlerMethod> getMappings() {
	return this.mappingLookup;
}

而这个 mappingLookup 再来看下

class 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

public 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就是我们要的路径

public class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {

	private final static Set<String> EMPTY_PATH_PATTERN = Collections.singleton("");


	private final Set<String> patterns;

写到这下一篇是不是可以介绍下 mapping 的具体注册逻辑


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK