This is an automated email from the ASF dual-hosted git repository.
earthchen pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.3 by this push:
new 947c061a7a gRPC support context path (#14509)
947c061a7a is described below
commit 947c061a7a3857a404869d398561e24900c9deac
Author: Sean Yang <[email protected]>
AuthorDate: Mon Aug 12 10:29:39 2024 +0800
gRPC support context path (#14509)
---
.../rpc/protocol/tri/servlet/TripleFilter.java | 45 +++-------
.../java/org/apache/dubbo/rpc/PathResolver.java | 8 +-
.../dubbo/rpc/protocol/tri/RequestMetadata.java | 2 +-
.../apache/dubbo/rpc/protocol/tri/RequestPath.java | 75 +++++++++++++++++
.../dubbo/rpc/protocol/tri/TriplePathResolver.java | 97 +++++++++++++++++++---
.../dubbo/rpc/protocol/tri/TripleProtocol.java | 91 ++++++++------------
.../tri/h12/grpc/GrpcRequestHandlerMapping.java | 39 ++++-----
.../mapping/DefaultRequestMappingRegistry.java | 3 +
.../transport/TripleIsolationExecutorSupport.java | 37 +++++----
.../rpc/protocol/tri/TriplePathResolverTest.java | 42 ++++++++--
.../tri/service/TriBuiltinServiceTest.java | 2 +-
11 files changed, 296 insertions(+), 145 deletions(-)
diff --git
a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
index 4b5ffdf145..c95f177b57 100644
---
a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
+++
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
@@ -16,21 +16,18 @@
*/
package org.apache.dubbo.rpc.protocol.tri.servlet;
-import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.io.StreamUtils;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;
import org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory;
import org.apache.dubbo.remoting.http12.h2.Http2TransportListener;
-import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.PathResolver;
import org.apache.dubbo.rpc.TriRpcStatus.Code;
import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.protocol.tri.RequestPath;
import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;
-import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHeaderNames;
import
org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHttp2ServerTransportListener;
import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils;
@@ -73,31 +70,31 @@ public class TripleFilter implements Filter {
}
@Override
- public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
+ public void doFilter(ServletRequest servletRequest, ServletResponse
servletResponse, FilterChain chain)
throws ServletException, IOException {
- HttpServletRequest hRequest = (HttpServletRequest) request;
- HttpServletResponse hResponse = (HttpServletResponse) response;
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
- if (!hasServiceMapping(hRequest) &&
!mappingRegistry.exists(hRequest.getRequestURI(), hRequest.getMethod())) {
+ if (!hasGrpcMapping(request) &&
!mappingRegistry.exists(request.getRequestURI(), request.getMethod())) {
chain.doFilter(request, response);
return;
}
AsyncContext context = request.startAsync(request, response);
- ServletStreamChannel channel = new ServletStreamChannel(hRequest,
hResponse, context);
+ ServletStreamChannel channel = new ServletStreamChannel(request,
response, context);
try {
Http2TransportListener listener =
determineHttp2ServerTransportListenerFactory(request.getContentType())
.newInstance(channel, ServletExchanger.getUrl(),
FrameworkModel.defaultModel());
boolean isGrpc = listener instanceof
GrpcHttp2ServerTransportListener;
channel.setGrpc(isGrpc);
- context.setTimeout(resolveTimeout(hRequest, isGrpc));
+ context.setTimeout(resolveTimeout(request, isGrpc));
context.addListener(new TripleAsyncListener(channel));
ServletInputStream is = request.getInputStream();
is.setReadListener(new TripleReadListener(listener, channel, is));
response.getOutputStream().setWriteListener(new
TripleWriteListener(channel));
- listener.onMetadata(new HttpMetadataAdapter(hRequest));
+ listener.onMetadata(new HttpMetadataAdapter(request));
} catch (Throwable t) {
LOGGER.info("Failed to process request", t);
channel.writeError(Code.UNKNOWN.code, t);
@@ -107,30 +104,14 @@ public class TripleFilter implements Filter {
@Override
public void destroy() {}
- private boolean hasServiceMapping(HttpServletRequest request) {
- String uri = request.getRequestURI();
-
- int index = uri.indexOf('/', 1);
- if (index == -1) {
- return false;
- }
- if (uri.indexOf('/', index + 1) != -1) {
+ private boolean hasGrpcMapping(HttpServletRequest request) {
+ RequestPath path = RequestPath.parse(request.getRequestURI());
+ if (path == null) {
return false;
}
-
- String serviceName = uri.substring(1, index);
- String version =
request.getHeader(TripleHeaderEnum.SERVICE_VERSION.getHeader());
String group =
request.getHeader(TripleHeaderEnum.SERVICE_GROUP.getHeader());
- String key = URL.buildKey(serviceName, group, version);
- Invoker<?> invoker = pathResolver.resolve(key);
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(URL.buildKey(serviceName, group,
TripleConstant.DEFAULT_VERSION));
- if (invoker == null) {
- return pathResolver.resolve(serviceName) != null;
- }
- }
-
- return true;
+ String version =
request.getHeader(TripleHeaderEnum.SERVICE_VERSION.getHeader());
+ return pathResolver.resolve(path.getPath(), group, version) != null;
}
private Http2ServerTransportListenerFactory
determineHttp2ServerTransportListenerFactory(String contentType) {
diff --git
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PathResolver.java
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PathResolver.java
index ba8d17cdcc..815229c4b4 100644
---
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PathResolver.java
+++
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PathResolver.java
@@ -21,16 +21,20 @@ import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;
/**
- * PathResolver maintains a mapping between request path and Invoker for
multiple protocols.
+ * PathResolver maintains a mapping between request paths and invokers for
multiple protocols.
*/
@SPI(value = CommonConstants.TRIPLE, scope = ExtensionScope.FRAMEWORK)
public interface PathResolver {
+ void register(Invoker<?> invoker);
+
+ void unregister(Invoker<?> invoker);
+
Invoker<?> add(String path, Invoker<?> invoker);
Invoker<?> addIfAbsent(String path, Invoker<?> invoker);
- Invoker<?> resolve(String path);
+ Invoker<?> resolve(String path, String group, String version);
boolean hasNativeStub(String path);
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
index 63e1339625..52794f146e 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestMetadata.java
@@ -55,7 +55,7 @@ public class RequestMetadata {
header.scheme(scheme)
.authority(address)
.method(HttpMethod.POST.asciiName())
- .path("/" + service + "/" + method.getMethodName())
+ .path(RequestPath.toFullPath(service, method.getMethodName()))
.set(TripleHeaderEnum.CONTENT_TYPE_KEY.getHeader(),
MediaType.APPLICATION_GRPC_PROTO.getName())
.set(HttpHeaderNames.TE, HttpHeaderValues.TRAILERS);
setIfNotNull(header, TripleHeaderEnum.TIMEOUT.getHeader(), timeout);
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestPath.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestPath.java
new file mode 100644
index 0000000000..22e79ca102
--- /dev/null
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/RequestPath.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.protocol.tri;
+
+public final class RequestPath {
+
+ private final String path;
+ private final String stubPath;
+ private final String serviceInterface;
+ private final String methodName;
+
+ private RequestPath(String path, String stubPath, String serviceInterface,
String methodName) {
+ this.path = path;
+ this.stubPath = stubPath;
+ this.serviceInterface = serviceInterface;
+ this.methodName = methodName;
+ }
+
+ // Request path patten:
+ // '{interfaceName}/{methodName}' or
'{contextPath}/{interfaceName}/{methodName}'
+ // └─── path ────┘ └─ method ─┘ └────────── path ───────────┘ └─
method ─┘
+ public static RequestPath parse(String fullPath) {
+ int i = fullPath.lastIndexOf('/');
+ if (i < 1) {
+ return null;
+ }
+
+ String path = fullPath.substring(1, i);
+ int j = path.lastIndexOf('/');
+ if (j == -1) {
+ return new RequestPath(path, fullPath, path, fullPath.substring(i
+ 1));
+ } else {
+ return new RequestPath(path, fullPath.substring(j),
path.substring(j + 1), fullPath.substring(i + 1));
+ }
+ }
+
+ public static String toFullPath(String path, String methodName) {
+ return '/' + path + '/' + methodName;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getStubPath() {
+ return stubPath;
+ }
+
+ public String getServiceInterface() {
+ return serviceInterface;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ @Override
+ public String toString() {
+ return path + '/' + methodName;
+ }
+}
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolver.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolver.java
index be291bd865..49192076bb 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolver.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolver.java
@@ -16,48 +16,121 @@
*/
package org.apache.dubbo.rpc.protocol.tri;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.PathResolver;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
public class TriplePathResolver implements PathResolver {
- private final ConcurrentHashMap<String, Invoker<?>> path2Invoker = new
ConcurrentHashMap<>();
- private final ConcurrentHashMap<String, Object> nativeStub = new
ConcurrentHashMap<>();
+ private static final Logger LOGGER =
LoggerFactory.getLogger(TripleProtocol.class);
+
+ private final Map<String, Invoker<?>> mapping =
CollectionUtils.newConcurrentHashMap();
+ private final Map<String, Boolean> nativeStubs =
CollectionUtils.newConcurrentHashMap();
+
+ @Override
+ public void register(Invoker<?> invoker) {
+ URL url = invoker.getUrl();
+ String serviceKey = url.getServiceKey();
+ String serviceInterface =
url.getServiceModel().getServiceModel().getInterfaceName();
+
+ register0(serviceKey, serviceInterface, invoker, url);
+
+ // Path patten: '{interfaceName}' or '{contextPath}/{interfaceName}'
+ String path = url.getPath();
+ int index = path.lastIndexOf('/');
+ if (index == -1) {
+ return;
+ }
+ String fallbackPath = path.substring(0, index + 1) + serviceInterface;
+ register0(URL.buildKey(path, url.getGroup(), url.getVersion()),
fallbackPath, invoker, url);
+ }
+
+ private void register0(String path, String fallbackPath, Invoker<?>
invoker, URL url) {
+ // register default mapping
+ Invoker<?> previous = mapping.put(path, invoker);
+ if (previous != null) {
+ if (path.equals(fallbackPath)) {
+ LOGGER.info(
+ "Already exists an invoker[{}] on path[{}], dubbo will
override with invoker[{}]",
+ previous.getUrl(),
+ path,
+ url);
+ } else {
+ throw new IllegalStateException(String.format(
+ "Already exists an invoker[%s] on path[%s], failed to
add invoker[%s], please use a unique path.",
+ previous.getUrl(), path, url));
+ }
+ } else {
+ LOGGER.debug("Register triple grpc mapping: '{}' -> invoker{}",
path, url);
+ }
+
+ // register fallback mapping
+ if (TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT &&
!path.equals(fallbackPath)) {
+ previous = mapping.putIfAbsent(fallbackPath, invoker);
+ if (previous != null) {
+ LOGGER.info(
+ "Already exists an invoker[{}] on path[{}], dubbo will
skip override with invoker[{}]",
+ previous.getUrl(),
+ fallbackPath,
+ url);
+ } else {
+ LOGGER.info("Register fallback triple grpc mapping: '{}' ->
invoker{}", fallbackPath, url);
+ }
+ }
+ }
+
+ @Override
+ public void unregister(Invoker<?> invoker) {
+ URL url = invoker.getUrl();
+ mapping.remove(url.getServiceKey());
+ if (TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
+
mapping.remove(url.getServiceModel().getServiceModel().getInterfaceName());
+ }
+ }
@Override
public Invoker<?> add(String path, Invoker<?> invoker) {
- return path2Invoker.put(path, invoker);
+ return mapping.put(path, invoker);
}
@Override
public Invoker<?> addIfAbsent(String path, Invoker<?> invoker) {
- return path2Invoker.putIfAbsent(path, invoker);
+ return mapping.putIfAbsent(path, invoker);
}
@Override
- public Invoker<?> resolve(String path) {
- return path2Invoker.get(path);
+ public Invoker<?> resolve(String path, String group, String version) {
+ Invoker<?> invoker = mapping.get(URL.buildKey(path, group, version));
+ if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
+ invoker = mapping.get(URL.buildKey(path, group,
TripleConstant.DEFAULT_VERSION));
+ if (invoker == null) {
+ invoker = mapping.get(path);
+ }
+ }
+ return invoker;
}
- @Override
public boolean hasNativeStub(String path) {
- return nativeStub.containsKey(path);
+ return nativeStubs.containsKey(path);
}
@Override
public void addNativeStub(String path) {
- nativeStub.put(path, 0);
+ nativeStubs.put(path, Boolean.TRUE);
}
@Override
public void remove(String path) {
- path2Invoker.remove(path);
+ mapping.remove(path);
}
@Override
public void destroy() {
- path2Invoker.clear();
+ mapping.clear();
}
}
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
index 7c04bf914f..a7f37a0be5 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
@@ -19,8 +19,6 @@ package org.apache.dubbo.rpc.protocol.tri;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.config.ConfigurationUtils;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.ExecutorUtil;
import org.apache.dubbo.common.utils.NetUtils;
@@ -45,7 +43,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
-import io.grpc.health.v1.HealthCheckResponse;
import io.grpc.health.v1.HealthCheckResponse.ServingStatus;
import static
org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLIENT_THREADPOOL;
@@ -65,8 +62,6 @@ import static org.apache.dubbo.rpc.Constants.HTTP3_KEY;
public class TripleProtocol extends AbstractProtocol {
- private static final Logger logger =
LoggerFactory.getLogger(TripleProtocol.class);
-
private final PathResolver pathResolver;
private final RequestMappingRegistry mappingRegistry;
private final TriBuiltinService triBuiltinService;
@@ -110,72 +105,60 @@ public class TripleProtocol extends AbstractProtocol {
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
String key = serviceKey(url);
+
+ // create exporter
AbstractExporter<T> exporter = new AbstractExporter<T>(invoker) {
@Override
public void afterUnExport() {
- pathResolver.remove(url.getServiceKey());
-
pathResolver.remove(url.getServiceModel().getServiceModel().getInterfaceName());
+ // unregister grpc request mapping
+ pathResolver.unregister(invoker);
+
// unregister rest request mapping
mappingRegistry.unregister(invoker);
- // set service status
- if (triBuiltinService.enable()) {
- triBuiltinService
- .getHealthStatusManager()
- .setStatus(url.getServiceKey(),
ServingStatus.NOT_SERVING);
- triBuiltinService
- .getHealthStatusManager()
- .setStatus(url.getServiceInterface(),
ServingStatus.NOT_SERVING);
- }
+
+ // set service status to NOT_SERVING
+ setServiceStatus(url, ServingStatus.NOT_SERVING);
+
exporterMap.remove(key);
}
};
-
exporterMap.put(key, exporter);
+ // add invoker
invokers.add(invoker);
- Invoker<?> previous = pathResolver.add(url.getServiceKey(), invoker);
- if (previous != null) {
- if (url.getServiceKey()
-
.equals(url.getServiceModel().getServiceModel().getInterfaceName())) {
- logger.info("Already exists an invoker[" + previous.getUrl() +
"] on path[" + url.getServiceKey()
- + "], dubbo will override with invoker[" + url + "]");
- } else {
- throw new IllegalStateException(
- "Already exists an invoker[" + previous.getUrl() + "]
on path[" + url.getServiceKey()
- + "], failed to add invoker[" + url + "] ,
please use unique serviceKey.");
- }
- }
- if (RESOLVE_FALLBACK_TO_DEFAULT) {
- previous = pathResolver.addIfAbsent(
-
url.getServiceModel().getServiceModel().getInterfaceName(), invoker);
- if (previous != null) {
- logger.info("Already exists an invoker[" + previous.getUrl() +
"] on path["
- +
url.getServiceModel().getServiceModel().getInterfaceName()
- + "], dubbo will skip override with invoker[" + url +
"]");
- } else {
- logger.info("Add fallback triple invoker[" + url + "] to path["
- +
url.getServiceModel().getServiceModel().getInterfaceName() + "] with invoker["
+ url + "]");
- }
- }
+ // register grpc path mapping
+ pathResolver.register(invoker);
// register rest request mapping
mappingRegistry.register(invoker);
- // set service status
- if (triBuiltinService.enable()) {
- triBuiltinService
- .getHealthStatusManager()
- .setStatus(url.getServiceKey(),
HealthCheckResponse.ServingStatus.SERVING);
- triBuiltinService
- .getHealthStatusManager()
- .setStatus(url.getServiceInterface(),
HealthCheckResponse.ServingStatus.SERVING);
- }
- // init
+ // set service status to SERVING
+ setServiceStatus(url, ServingStatus.SERVING);
+
+ // init server executor
ExecutorRepository.getInstance(url.getOrDefaultApplicationModel())
.createExecutorIfAbsent(ExecutorUtil.setThreadName(url,
SERVER_THREAD_POOL_NAME));
+ // bind server port
+ bindServerPort(url);
+
+ // optimize serialization
+ optimizeSerialization(url);
+
+ return exporter;
+ }
+
+ private void setServiceStatus(URL url, ServingStatus status) {
+ if (triBuiltinService.enable()) {
+
triBuiltinService.getHealthStatusManager().setStatus(url.getServiceKey(),
status);
+
triBuiltinService.getHealthStatusManager().setStatus(url.getServiceInterface(),
status);
+ }
+ }
+
+ private void bindServerPort(URL url) {
boolean bindPort = true;
+
if (SERVLET_ENABLED) {
int port = url.getParameter(BIND_PORT_KEY, url.getPort());
Integer serverPort = ServletExchanger.getServerPort();
@@ -188,6 +171,7 @@ public class TripleProtocol extends AbstractProtocol {
}
ServletExchanger.bind(url);
}
+
if (bindPort) {
PortUnificationExchanger.bind(url, new DefaultPuHandler());
}
@@ -196,9 +180,6 @@ public class TripleProtocol extends AbstractProtocol {
Http3Exchanger.bind(url);
http3Bound = true;
}
-
- optimizeSerialization(url);
- return exporter;
}
@Override
@@ -231,7 +212,7 @@ public class TripleProtocol extends AbstractProtocol {
@Override
public void destroy() {
if (logger.isInfoEnabled()) {
- logger.info("Destroying protocol [" + getClass().getSimpleName() +
"] ...");
+ logger.info("Destroying protocol [{}] ...",
getClass().getSimpleName());
}
PortUnificationExchanger.close();
if (http3Bound) {
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcRequestHandlerMapping.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcRequestHandlerMapping.java
index c2e8d9d3ae..b5467f2d50 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcRequestHandlerMapping.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcRequestHandlerMapping.java
@@ -20,15 +20,17 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.remoting.http12.HttpRequest;
import org.apache.dubbo.remoting.http12.HttpResponse;
+import org.apache.dubbo.remoting.http12.HttpStatus;
+import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
import org.apache.dubbo.remoting.http12.message.MediaType;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.PathResolver;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils;
+import org.apache.dubbo.rpc.protocol.tri.RequestPath;
import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
-import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
import org.apache.dubbo.rpc.protocol.tri.route.RequestHandler;
import org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping;
@@ -52,33 +54,22 @@ public final class GrpcRequestHandlerMapping implements
RequestHandlerMapping {
return null;
}
- String uri = request.uri();
- int index = uri.indexOf('/', 1);
- if (index == -1) {
- return null;
- }
- if (uri.indexOf('/', index + 1) != -1) {
- return null;
+ RequestPath path = RequestPath.parse(request.uri());
+ if (path == null) {
+ throw notFound();
}
- String serviceName = uri.substring(1, index);
- String version =
request.header(TripleHeaderEnum.SERVICE_VERSION.getHeader());
String group =
request.header(TripleHeaderEnum.SERVICE_GROUP.getHeader());
- String key = URL.buildKey(serviceName, group, version);
- Invoker<?> invoker = pathResolver.resolve(key);
- if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
- invoker = pathResolver.resolve(URL.buildKey(serviceName, group,
TripleConstant.DEFAULT_VERSION));
- if (invoker == null) {
- invoker = pathResolver.resolve(serviceName);
- if (invoker == null) {
- return null;
- }
- }
+ String version =
request.header(TripleHeaderEnum.SERVICE_VERSION.getHeader());
+ Invoker<?> invoker = pathResolver.resolve(path.getPath(), group,
version);
+ if (invoker == null) {
+ throw notFound();
}
RequestHandler handler = new RequestHandler(invoker);
- handler.setHasStub(pathResolver.hasNativeStub(uri));
- handler.setMethodName(uri.substring(index + 1));
+ handler.setHasStub(pathResolver.hasNativeStub(path.getStubPath()));
+ handler.setMethodName(path.getMethodName());
+ String serviceName = path.getServiceInterface();
handler.setServiceDescriptor(DescriptorUtils.findServiceDescriptor(invoker,
serviceName, handler.isHasStub()));
HttpMessageCodec codec = CODEC_FACTORY.createCodec(url,
frameworkModel, request.contentType());
handler.setHttpMessageDecoder(codec);
@@ -86,6 +77,10 @@ public final class GrpcRequestHandlerMapping implements
RequestHandlerMapping {
return handler;
}
+ private static HttpStatusException notFound() {
+ return new HttpStatusException(HttpStatus.NOT_FOUND.getCode(),
"Invoker for gRPC not found");
+ }
+
@Override
public String getType() {
return TripleConstant.TRIPLE_HANDLER_TYPE_GRPC;
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
index 159b1e7179..3168e23c5a 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
@@ -184,6 +184,9 @@ public final class DefaultRequestMappingRegistry implements
RequestMappingRegist
@Override
public void unregister(Invoker<?> invoker) {
+ if (tree == null) {
+ return;
+ }
lock.writeLock().lock();
try {
tree.remove(mapping -> mapping.meta.getInvoker() == invoker);
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleIsolationExecutorSupport.java
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleIsolationExecutorSupport.java
index cd70a2a3b5..81ec798f35 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleIsolationExecutorSupport.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/transport/TripleIsolationExecutorSupport.java
@@ -21,9 +21,11 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.remoting.http12.HttpHeaders;
-import org.apache.dubbo.remoting.http12.h2.Http2Header;
+import org.apache.dubbo.remoting.http12.RequestMetadata;
import org.apache.dubbo.rpc.executor.AbstractIsolationExecutorSupport;
+import org.apache.dubbo.rpc.protocol.tri.RequestPath;
import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
+import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
public class TripleIsolationExecutorSupport extends
AbstractIsolationExecutorSupport {
private static final ErrorTypeAwareLogger logger =
@@ -35,21 +37,28 @@ public class TripleIsolationExecutorSupport extends
AbstractIsolationExecutorSup
@Override
protected ServiceKey getServiceKey(Object data) {
- if (!(data instanceof Http2Header)) {
+ if (!(data instanceof RequestMetadata)) {
return null;
}
- Http2Header http2Metadata = (Http2Header) data;
- HttpHeaders headers = http2Metadata.headers();
- String path = http2Metadata.path();
- String[] parts = path.split("/"); // path like
/{interfaceName}/{methodName}
- String interfaceName = parts[1];
- String version =
headers.containsKey(TripleHeaderEnum.SERVICE_VERSION.getHeader())
- ?
headers.getFirst(TripleHeaderEnum.SERVICE_VERSION.getHeader())
- : null;
- String group =
headers.containsKey(TripleHeaderEnum.SERVICE_GROUP.getHeader())
- ? headers.getFirst(TripleHeaderEnum.SERVICE_GROUP.getHeader())
- : null;
- return new ServiceKey(interfaceName, version, group);
+ RequestMetadata httpMetadata = (RequestMetadata) data;
+ RequestPath path = RequestPath.parse(httpMetadata.path());
+ if (path == null) {
+ return null;
+ }
+
+ HttpHeaders headers = httpMetadata.headers();
+ return new ServiceKey(
+ path.getServiceInterface(),
+ getHeader(headers, TripleHeaderEnum.SERVICE_VERSION,
RestConstants.HEADER_SERVICE_VERSION),
+ getHeader(headers, TripleHeaderEnum.SERVICE_GROUP,
RestConstants.HEADER_SERVICE_GROUP));
+ }
+
+ private static String getHeader(HttpHeaders headers, TripleHeaderEnum en,
String key) {
+ String value = headers.getFirst(en.getHeader());
+ if (value == null) {
+ value = headers.getFirst(key);
+ }
+ return value;
}
}
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolverTest.java
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolverTest.java
index 5e9d212bf0..9ec9532681 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolverTest.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TriplePathResolverTest.java
@@ -17,27 +17,41 @@
package org.apache.dubbo.rpc.protocol.tri;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.PathResolver;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+import org.apache.dubbo.rpc.model.ServiceModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
class TriplePathResolverTest {
private static final PathResolver PATH_RESOLVER =
-
ExtensionLoader.getExtensionLoader(PathResolver.class).getDefaultExtension();
+
FrameworkModel.defaultModel().getDefaultExtension(PathResolver.class);
+
+ private static final String SERVICE_NAME = "DemoService";
private static final Invoker<Object> INVOKER = new Invoker<Object>() {
@Override
public URL getUrl() {
- return null;
+ ServiceDescriptor serviceDescriptor =
Mockito.mock(ServiceDescriptor.class);
+
Mockito.when(serviceDescriptor.getInterfaceName()).thenReturn(SERVICE_NAME);
+ ServiceModel serviceModel = Mockito.mock(ServiceModel.class);
+
Mockito.when(serviceModel.getServiceModel()).thenReturn(serviceDescriptor);
+ return URL.valueOf("tri://localhost/demo/" + SERVICE_NAME)
+ .setServiceInterface(SERVICE_NAME)
+ .addParameter(CommonConstants.GROUP_KEY, "g1")
+ .addParameter(CommonConstants.VERSION_KEY, "1.0.1")
+ .setServiceModel(serviceModel);
}
@Override
@@ -61,8 +75,8 @@ class TriplePathResolverTest {
@BeforeEach
public void init() {
-
PATH_RESOLVER.add("/abc", INVOKER);
+ PATH_RESOLVER.register(INVOKER);
}
@AfterEach
@@ -75,6 +89,22 @@ class TriplePathResolverTest {
Assertions.assertEquals(INVOKER, getInvokerByPath("/abc"));
}
+ @Test
+ void testResolveWithContextPath() {
+ String path = "demo/" + SERVICE_NAME;
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(SERVICE_NAME,
null, null));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(path, null,
null));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(SERVICE_NAME,
"g1", "1.0.1"));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(path, "g1",
"1.0.1"));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(SERVICE_NAME,
"g2", "1.0.2"));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(path, "g2",
"1.0.2"));
+ TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT = false;
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(SERVICE_NAME,
"g1", "1.0.1"));
+ Assertions.assertEquals(INVOKER, PATH_RESOLVER.resolve(path, "g1",
"1.0.1"));
+ Assertions.assertNull(PATH_RESOLVER.resolve(SERVICE_NAME, "g2",
"1.0.2"));
+ Assertions.assertNull(PATH_RESOLVER.resolve(path, "g2", "1.0.2"));
+ }
+
@Test
void testRemove() {
Assertions.assertEquals(INVOKER, getInvokerByPath("/abc"));
@@ -102,7 +132,7 @@ class TriplePathResolverTest {
Assertions.assertNull(getInvokerByPath("/bcd"));
}
- private Invoker getInvokerByPath(String path) {
- return PATH_RESOLVER.resolve(path);
+ private Invoker<?> getInvokerByPath(String path) {
+ return PATH_RESOLVER.resolve(path, null, null);
}
}
diff --git
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinServiceTest.java
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinServiceTest.java
index d4d45a8e4a..ed731db3c0 100644
---
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinServiceTest.java
+++
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/service/TriBuiltinServiceTest.java
@@ -47,7 +47,7 @@ class TriBuiltinServiceTest {
Assertions.assertNotNull(triBuiltinService.getHealthStatusManager());
PathResolver pathResolver =
frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
- Assertions.assertNotNull(pathResolver.resolve(serviceName));
+ Assertions.assertNotNull(pathResolver.resolve(serviceName, null,
null));
ModuleServiceRepository repository =
frameworkModel.getInternalApplicationModel().getInternalModule().getServiceRepository();
Assertions.assertFalse(repository.getAllServices().isEmpty());