support exception process when service not found (#11088)
This commit is contained in:
parent
08f3c6b018
commit
3f8a16f0ac
|
|
@ -620,5 +620,10 @@ public interface CommonConstants {
|
|||
String ENCODE_IN_IO_THREAD_KEY = "encode.in.io";
|
||||
boolean DEFAULT_ENCODE_IN_IO_THREAD = false;
|
||||
|
||||
/**
|
||||
* @since 3.2.0
|
||||
*/
|
||||
String BYTE_ACCESSOR_KEY = "byte.accessor";
|
||||
|
||||
String PAYLOAD = "payload";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,12 @@
|
|||
META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.dubbo.ByteAccessor
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.dubbo;
|
||||
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.apache.dubbo.common.extension.ExtensionScope.FRAMEWORK;
|
||||
|
||||
/**
|
||||
* Extension of Byte Accessor, holding attributes as RpcInvocation objects
|
||||
* so that the decoded service can be used more flexibly
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@SPI(scope = FRAMEWORK)
|
||||
public interface ByteAccessor {
|
||||
|
||||
/**
|
||||
* Get an enhanced DecodeableRpcInvocation subclass to allow custom decode.
|
||||
* The parameters are the same as {@link DecodeableRpcInvocation}
|
||||
*/
|
||||
DecodeableRpcInvocation getRpcInvocation(Channel channel, Request req, InputStream is, byte proto);
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.protocol.dubbo;
|
||||
|
||||
|
||||
import org.apache.dubbo.common.utils.CacheableSupplier;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
|
|
@ -60,21 +59,21 @@ import static org.apache.dubbo.rpc.Constants.SERIALIZATION_SECURITY_CHECK_KEY;
|
|||
|
||||
public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable {
|
||||
|
||||
private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(DecodeableRpcInvocation.class);
|
||||
protected static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(DecodeableRpcInvocation.class);
|
||||
|
||||
private final Channel channel;
|
||||
protected final transient Channel channel;
|
||||
|
||||
private final byte serializationType;
|
||||
protected final byte serializationType;
|
||||
|
||||
private final InputStream inputStream;
|
||||
protected final transient InputStream inputStream;
|
||||
|
||||
private final Request request;
|
||||
protected final transient Request request;
|
||||
|
||||
private volatile boolean hasDecoded;
|
||||
protected volatile boolean hasDecoded;
|
||||
|
||||
protected final FrameworkModel frameworkModel;
|
||||
|
||||
private final Supplier<CallbackServiceCodec> callbackServiceCodecFactory;
|
||||
protected final transient Supplier<CallbackServiceCodec> callbackServiceCodecFactory;
|
||||
|
||||
public DecodeableRpcInvocation(FrameworkModel frameworkModel, Channel channel, Request request, InputStream is, byte id) {
|
||||
this.frameworkModel = frameworkModel;
|
||||
|
|
@ -85,7 +84,7 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
this.request = request;
|
||||
this.inputStream = is;
|
||||
this.serializationType = id;
|
||||
this.callbackServiceCodecFactory = CacheableSupplier.newSupplier(()->
|
||||
this.callbackServiceCodecFactory = CacheableSupplier.newSupplier(() ->
|
||||
new CallbackServiceCodec(frameworkModel));
|
||||
}
|
||||
|
||||
|
|
@ -111,10 +110,6 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void checkSerializationTypeFromRemote() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Channel channel, InputStream input) throws IOException {
|
||||
ObjectInput in = CodecSupport.getSerialization(serializationType)
|
||||
|
|
@ -143,78 +138,14 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
Object[] args = DubboCodec.EMPTY_OBJECT_ARRAY;
|
||||
Class<?>[] pts = DubboCodec.EMPTY_CLASS_ARRAY;
|
||||
if (desc.length() > 0) {
|
||||
// if (RpcUtils.isGenericCall(path, getMethodName()) || RpcUtils.isEcho(path, getMethodName())) {
|
||||
// pts = ReflectUtils.desc2classArray(desc);
|
||||
// } else {
|
||||
FrameworkServiceRepository repository = frameworkModel.getServiceRepository();
|
||||
List<ProviderModel> providerModels = repository.lookupExportedServicesWithoutGroup(keyWithoutGroup(path, version));
|
||||
ServiceDescriptor serviceDescriptor = null;
|
||||
if (CollectionUtils.isNotEmpty(providerModels)) {
|
||||
for (ProviderModel providerModel : providerModels) {
|
||||
serviceDescriptor = providerModel.getServiceModel();
|
||||
if (serviceDescriptor != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (serviceDescriptor == null) {
|
||||
// Unable to find ProviderModel from Exported Services
|
||||
for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {
|
||||
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
|
||||
serviceDescriptor = moduleModel.getServiceRepository().lookupService(path);
|
||||
if (serviceDescriptor != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceDescriptor != null) {
|
||||
MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(getMethodName(), desc);
|
||||
if (methodDescriptor != null) {
|
||||
pts = methodDescriptor.getParameterClasses();
|
||||
this.setReturnTypes(methodDescriptor.getReturnTypes());
|
||||
|
||||
// switch TCCL
|
||||
if (CollectionUtils.isNotEmpty(providerModels)) {
|
||||
if (providerModels.size() == 1) {
|
||||
Thread.currentThread().setContextClassLoader(providerModels.get(0).getClassLoader());
|
||||
} else {
|
||||
// try all providerModels' classLoader can load pts, use the first one
|
||||
for (ProviderModel providerModel : providerModels) {
|
||||
ClassLoader classLoader = providerModel.getClassLoader();
|
||||
boolean match = true;
|
||||
for (Class<?> pt : pts) {
|
||||
try {
|
||||
if (!pt.equals(classLoader.loadClass(pt.getName()))) {
|
||||
match = false;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pts = drawPts(path, version, desc, pts);
|
||||
if (pts == DubboCodec.EMPTY_CLASS_ARRAY) {
|
||||
if (!RpcUtils.isGenericCall(desc, getMethodName()) && !RpcUtils.isEcho(desc, getMethodName())) {
|
||||
throw new IllegalArgumentException("Service not found:" + path + ", " + getMethodName());
|
||||
}
|
||||
pts = ReflectUtils.desc2classArray(desc);
|
||||
}
|
||||
// }
|
||||
|
||||
args = new Object[pts.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = in.readObject(pts[i]);
|
||||
}
|
||||
args = drawArgs(in, pts);
|
||||
}
|
||||
setParameterTypes(pts);
|
||||
|
||||
|
|
@ -223,17 +154,7 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
addObjectAttachments(map);
|
||||
}
|
||||
|
||||
//decode argument ,may be callback
|
||||
CallbackServiceCodec callbackServiceCodec = callbackServiceCodecFactory.get();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = callbackServiceCodec.decodeInvocationArgument(channel, this, pts, i, args[i]);
|
||||
}
|
||||
|
||||
setArguments(args);
|
||||
String targetServiceName = buildKey(getAttachment(PATH_KEY),
|
||||
getAttachment(GROUP_KEY),
|
||||
getAttachment(VERSION_KEY));
|
||||
setTargetServiceUniqueName(targetServiceName);
|
||||
decodeArgument(channel, pts, args);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IOException(StringUtils.toString("Read invocation data failed.", e));
|
||||
} finally {
|
||||
|
|
@ -245,4 +166,86 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
protected void decodeArgument(Channel channel, Class<?>[] pts, Object[] args) throws IOException {
|
||||
CallbackServiceCodec callbackServiceCodec = callbackServiceCodecFactory.get();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = callbackServiceCodec.decodeInvocationArgument(channel, this, pts, i, args[i]);
|
||||
}
|
||||
|
||||
setArguments(args);
|
||||
String targetServiceName = buildKey(getAttachment(PATH_KEY),
|
||||
getAttachment(GROUP_KEY),
|
||||
getAttachment(VERSION_KEY));
|
||||
setTargetServiceUniqueName(targetServiceName);
|
||||
}
|
||||
|
||||
protected Class<?>[] drawPts(String path, String version, String desc, Class<?>[] pts) {
|
||||
FrameworkServiceRepository repository = frameworkModel.getServiceRepository();
|
||||
List<ProviderModel> providerModels = repository.lookupExportedServicesWithoutGroup(keyWithoutGroup(path, version));
|
||||
ServiceDescriptor serviceDescriptor = null;
|
||||
if (CollectionUtils.isNotEmpty(providerModels)) {
|
||||
for (ProviderModel providerModel : providerModels) {
|
||||
serviceDescriptor = providerModel.getServiceModel();
|
||||
if (serviceDescriptor != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (serviceDescriptor == null) {
|
||||
// Unable to find ProviderModel from Exported Services
|
||||
for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {
|
||||
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
|
||||
serviceDescriptor = moduleModel.getServiceRepository().lookupService(path);
|
||||
if (serviceDescriptor != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceDescriptor != null) {
|
||||
MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(getMethodName(), desc);
|
||||
if (methodDescriptor != null) {
|
||||
pts = methodDescriptor.getParameterClasses();
|
||||
this.setReturnTypes(methodDescriptor.getReturnTypes());
|
||||
|
||||
// switch TCCL
|
||||
if (CollectionUtils.isNotEmpty(providerModels)) {
|
||||
if (providerModels.size() == 1) {
|
||||
Thread.currentThread().setContextClassLoader(providerModels.get(0).getClassLoader());
|
||||
} else {
|
||||
// try all providerModels' classLoader can load pts, use the first one
|
||||
for (ProviderModel providerModel : providerModels) {
|
||||
ClassLoader classLoader = providerModel.getClassLoader();
|
||||
boolean match = true;
|
||||
for (Class<?> pt : pts) {
|
||||
try {
|
||||
if (!pt.equals(classLoader.loadClass(pt.getName()))) {
|
||||
match = false;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
|
||||
protected Object[] drawArgs(ObjectInput in, Class<?>[] pts) throws IOException, ClassNotFoundException {
|
||||
Object[] args;
|
||||
args = new Object[pts.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
args[i] = in.readObject(pts[i]);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@ import org.apache.dubbo.rpc.model.FrameworkModel;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.BYTE_ACCESSOR_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
|
|
@ -73,10 +75,15 @@ public class DubboCodec extends ExchangeCodec {
|
|||
private static final AtomicBoolean decodeInUserThreadLogged = new AtomicBoolean(false);
|
||||
private final CallbackServiceCodec callbackServiceCodec;
|
||||
private final FrameworkModel frameworkModel;
|
||||
private final ByteAccessor customByteAccessor;
|
||||
|
||||
public DubboCodec(FrameworkModel frameworkModel) {
|
||||
this.frameworkModel = frameworkModel;
|
||||
callbackServiceCodec = new CallbackServiceCodec(frameworkModel);
|
||||
customByteAccessor = Optional.ofNullable(System.getProperty(BYTE_ACCESSOR_KEY))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(key -> frameworkModel.getExtensionLoader(ByteAccessor.class).getExtension(key))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -153,11 +160,20 @@ public class DubboCodec extends ExchangeCodec {
|
|||
req = new HeartBeatRequest(id);
|
||||
DecodeableRpcInvocation inv;
|
||||
if (isDecodeDataInIoThread(channel)) {
|
||||
inv = new DecodeableRpcInvocation(frameworkModel, channel, req, is, proto);
|
||||
if (customByteAccessor != null) {
|
||||
inv = customByteAccessor.getRpcInvocation(channel, req, is, proto);
|
||||
} else {
|
||||
inv = new DecodeableRpcInvocation(frameworkModel, channel, req, is, proto);
|
||||
}
|
||||
inv.decode();
|
||||
} else {
|
||||
inv = new DecodeableRpcInvocation(frameworkModel, channel, req,
|
||||
new UnsafeByteArrayInputStream(readMessageData(is)), proto);
|
||||
if (customByteAccessor != null) {
|
||||
inv = customByteAccessor.getRpcInvocation(channel, req,
|
||||
new UnsafeByteArrayInputStream(readMessageData(is)), proto);
|
||||
} else {
|
||||
inv = new DecodeableRpcInvocation(frameworkModel, channel, req,
|
||||
new UnsafeByteArrayInputStream(readMessageData(is)), proto);
|
||||
}
|
||||
}
|
||||
data = inv;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue