Merge branch 'apache-3.2' into apache-3.3
# Conflicts: # dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestProtocol.java # dubbo-test/dubbo-test-modules/src/test/java/org/apache/dubbo/dependency/FileTest.java
This commit is contained in:
commit
fd14e7b76f
|
|
@ -109,5 +109,9 @@ dubbo-spring-boot-tracing-otel-zipkin-starter
|
|||
dubbo-spring-boot-tracing-otel-otlp-starter
|
||||
dubbo-spring-boot-observability-starter
|
||||
dubbo-spring-boot-starter
|
||||
dubbo-spring-boot-starters
|
||||
dubbo-nacos-spring-boot-starter
|
||||
dubbo-zookeeper-spring-boot-starter
|
||||
dubbo-zookeeper-curator5-spring-boot-starter
|
||||
dubbo-spring-security
|
||||
dubbo-xds
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ public abstract class AbstractConfigurator implements Configurator {
|
|||
if (apiVersion != null && apiVersion.startsWith(RULE_VERSION_V30)) {
|
||||
ConditionMatch matcher = (ConditionMatch) configuratorUrl.getAttribute(MATCH_CONDITION);
|
||||
if (matcher != null) {
|
||||
if (matcher.isMatch(url)) {
|
||||
if (matcher.isMatch(host, url)) {
|
||||
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
|
||||
} else {
|
||||
logger.debug("Cannot apply configurator rule, param mismatch, current params are " + url + ", params in rule is " + matcher);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
|
|||
|
||||
public class ConditionMatch {
|
||||
private AddressMatch address;
|
||||
private AddressMatch providerAddress;
|
||||
private ListStringMatch service;
|
||||
private ListStringMatch app;
|
||||
private List<ParamMatch> param;
|
||||
|
|
@ -38,6 +39,14 @@ public class ConditionMatch {
|
|||
this.address = address;
|
||||
}
|
||||
|
||||
public AddressMatch getProviderAddress() {
|
||||
return providerAddress;
|
||||
}
|
||||
|
||||
public void setProviderAddress(AddressMatch providerAddress) {
|
||||
this.providerAddress = providerAddress;
|
||||
}
|
||||
|
||||
public ListStringMatch getService() {
|
||||
return service;
|
||||
}
|
||||
|
|
@ -62,8 +71,12 @@ public class ConditionMatch {
|
|||
this.param = param;
|
||||
}
|
||||
|
||||
public boolean isMatch(URL url) {
|
||||
if (getAddress() != null && !getAddress().isMatch(url.getAddress())) {
|
||||
public boolean isMatch(String host, URL url) {
|
||||
if (getAddress() != null && !getAddress().isMatch(host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getProviderAddress() != null && !getProviderAddress().isMatch(url.getAddress())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +103,7 @@ public class ConditionMatch {
|
|||
public String toString() {
|
||||
return "ConditionMatch{" +
|
||||
"address='" + address + '\'' +
|
||||
"providerAddress='" + providerAddress + '\'' +
|
||||
", service='" + service + '\'' +
|
||||
", app='" + app + '\'' +
|
||||
", param='" + param + '\'' +
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ public class ParamMatch {
|
|||
}
|
||||
|
||||
public boolean isMatch(URL url) {
|
||||
if (key == null) {
|
||||
if (key == null || value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String input = url.getParameter(key);
|
||||
return input != null && value.isMatch(input);
|
||||
return value.isMatch(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ public abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> im
|
|||
|
||||
@Override
|
||||
public synchronized void process(ConfigChangedEvent event) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Notification of condition rule, change type is: " + event.getChangeType() +
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Notification of condition rule, change type is: " + event.getChangeType() +
|
||||
", raw rule is:\n " + event.getContent());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ public class TagStateRouter<T> extends AbstractStateRouter<T> implements Configu
|
|||
|
||||
@Override
|
||||
public synchronized void process(ConfigChangedEvent event) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Notification of tag rule, change type is: " + event.getChangeType() + ", raw rule is:\n " +
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Notification of tag rule, change type is: " + event.getChangeType() + ", raw rule is:\n " +
|
||||
event.getContent());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class ParamMatch {
|
|||
}
|
||||
|
||||
public boolean isMatch(String input) {
|
||||
if (getValue() != null && input != null) {
|
||||
if (getValue() != null) {
|
||||
return getValue().isMatch(input);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.BROADCAST_CLUSTER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.BROADCAST_CLUSTER;
|
||||
|
||||
/**
|
||||
* ScopeClusterInvoker is a cluster invoker which handles the invocation logic of a single service in a specific scope.
|
||||
|
|
@ -100,7 +100,19 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return isExported.get() || directory.isAvailable();
|
||||
if (peerFlag || isBroadcast()) {
|
||||
// If it's a point-to-point direct connection or broadcasting, it should be called remotely.
|
||||
return invoker.isAvailable();
|
||||
}
|
||||
if (injvmFlag && isForceLocal()) {
|
||||
// If it's a local call, it should be called locally.
|
||||
return isExported.get();
|
||||
}
|
||||
if (injvmFlag && isExported.get()) {
|
||||
// If allow local call, check if local exported first
|
||||
return true;
|
||||
}
|
||||
return invoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -128,7 +140,7 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
// When broadcasting, it should be called remotely.
|
||||
if (BROADCAST_CLUSTER.equalsIgnoreCase(getUrl().getParameter(CLUSTER_KEY))) {
|
||||
if (isBroadcast()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Performing broadcast call for method: " + invocation.getMethodName() + " of service: " + getUrl().getServiceKey());
|
||||
}
|
||||
|
|
@ -155,6 +167,10 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
private boolean isBroadcast() {
|
||||
return BROADCAST_CLUSTER.equalsIgnoreCase(getUrl().getParameter(CLUSTER_KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExporterChangeExport(Exporter<?> exporter) {
|
||||
if (isExported.get()) {
|
||||
|
|
@ -230,9 +246,9 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
private boolean isInjvmExported() {
|
||||
Boolean localInvoke = RpcContext.getServiceContext().getLocalInvoke();
|
||||
boolean isExportedValue = isExported.get();
|
||||
boolean local = (localInvoke != null && localInvoke);
|
||||
boolean localOnce = (localInvoke != null && localInvoke);
|
||||
// Determine whether this call is local
|
||||
if (isExportedValue && local) {
|
||||
if (isExportedValue && localOnce) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -242,8 +258,7 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
}
|
||||
|
||||
// When calling locally, determine whether it does not meet the requirements
|
||||
if (!isExportedValue && (SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) ||
|
||||
Boolean.TRUE.toString().equalsIgnoreCase(getUrl().getParameter(LOCAL_PROTOCOL)) || local)) {
|
||||
if (!isExportedValue && (isForceLocal() || localOnce)) {
|
||||
// If it's supposed to be exported to the local JVM ,but it's not, throw an exception
|
||||
throw new RpcException("Local service for " + getUrl().getServiceInterface() + " has not been exposed yet!");
|
||||
}
|
||||
|
|
@ -251,6 +266,11 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
return isExportedValue && injvmFlag;
|
||||
}
|
||||
|
||||
private boolean isForceLocal() {
|
||||
return SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) ||
|
||||
Boolean.TRUE.toString().equalsIgnoreCase(getUrl().getParameter(LOCAL_PROTOCOL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Invoker for the current ScopeClusterInvoker and exports it to the local JVM.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -187,11 +187,11 @@ class ConfigParserTest {
|
|||
URL notMatchURL3 = URL.valueOf("dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match");// key not match
|
||||
|
||||
ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL1));
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL2));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL1));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL2));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL3));
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL1.getAddress(), matchURL1));
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL2.getAddress(), matchURL2));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL1.getAddress(), notMatchURL1));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL2.getAddress(), notMatchURL2));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL3.getAddress(), notMatchURL3));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,8 +211,8 @@ class ConfigParserTest {
|
|||
URL notMatchURL = URL.valueOf("dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match");// key not match
|
||||
|
||||
ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL));
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL.getAddress(), matchURL));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL.getAddress(), notMatchURL));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,8 +232,8 @@ class ConfigParserTest {
|
|||
URL notMatchURL = URL.valueOf("dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match");// key not match
|
||||
|
||||
ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL));
|
||||
Assertions.assertTrue(matcher.isMatch(matchURL.getAddress(), matchURL));
|
||||
Assertions.assertFalse(matcher.isMatch(notMatchURL.getAddress(), notMatchURL));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.apache.dubbo.rpc.cluster.support.wrapper;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
|
||||
import org.apache.dubbo.metrics.event.MetricsDispatcher;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
|
@ -165,7 +164,7 @@ class ScopeClusterInvokerTest {
|
|||
RpcInvocation invocation = new RpcInvocation();
|
||||
invocation.setMethodName("doSomething4");
|
||||
invocation.setParameterTypes(new Class[]{});
|
||||
Assertions.assertTrue(cluster.isAvailable(), "");
|
||||
Assertions.assertFalse(cluster.isAvailable(), "");
|
||||
RpcInvocation finalInvocation = invocation;
|
||||
Assertions.assertThrows(RpcException.class, () -> cluster.invoke(finalInvocation));
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,18 @@ public class ThreadlessExecutor extends AbstractExecutorService {
|
|||
* Waits until there is a task, executes the task and all queued tasks (if there're any). The task is either a normal
|
||||
* response or a timeout response.
|
||||
*/
|
||||
public void waitAndDrain() throws InterruptedException {
|
||||
public void waitAndDrain(long deadline) throws InterruptedException {
|
||||
throwIfInterrupted();
|
||||
Runnable runnable = queue.poll();
|
||||
if (runnable == null) {
|
||||
waiter = Thread.currentThread();
|
||||
try {
|
||||
while ((runnable = queue.poll()) == null) {
|
||||
LockSupport.park(this);
|
||||
long restTime = deadline - System.nanoTime();
|
||||
if (restTime <= 0) {
|
||||
return;
|
||||
}
|
||||
LockSupport.parkNanos(this, restTime);
|
||||
throwIfInterrupted();
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ public class ModuleConfig extends AbstractConfig {
|
|||
*/
|
||||
private Integer exportThreadNum;
|
||||
|
||||
/**
|
||||
* The timeout to check references
|
||||
*/
|
||||
private Long checkReferenceTimeout;
|
||||
|
||||
public ModuleConfig() {
|
||||
super();
|
||||
}
|
||||
|
|
@ -251,4 +256,12 @@ public class ModuleConfig extends AbstractConfig {
|
|||
public void setExportAsync(Boolean exportAsync) {
|
||||
this.exportAsync = exportAsync;
|
||||
}
|
||||
|
||||
public Long getCheckReferenceTimeout() {
|
||||
return checkReferenceTimeout;
|
||||
}
|
||||
|
||||
public void setCheckReferenceTimeout(Long checkReferenceTimeout) {
|
||||
this.checkReferenceTimeout = checkReferenceTimeout;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.threadpool;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
class ThreadlessExecutorTest {
|
||||
private static final ThreadlessExecutor executor;
|
||||
|
||||
|
|
@ -33,11 +34,13 @@ class ThreadlessExecutorTest {
|
|||
executor.execute(()->{throw new RuntimeException("test");});
|
||||
}
|
||||
|
||||
executor.waitAndDrain();
|
||||
executor.waitAndDrain(123);
|
||||
|
||||
executor.execute(()->{});
|
||||
AtomicBoolean invoked = new AtomicBoolean(false);
|
||||
executor.execute(()->{invoked.set(true);});
|
||||
|
||||
executor.waitAndDrain();
|
||||
executor.waitAndDrain(123);
|
||||
Assertions.assertTrue(invoked.get());
|
||||
|
||||
executor.shutdown();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ public class PageServlet extends HttpServlet {
|
|||
+ n
|
||||
+ "_' + i + '_' + j).innerHTML; if (iv.length > 0 && (tv.length < iv.length || tv.indexOf(iv) == -1)) { m = false; break; } } } document.getElementById('tr_"
|
||||
+ n
|
||||
+ "_' + i).style.display = (m ? '' : 'none');}\" sytle=\"width: 100%\" />";
|
||||
+ "_' + i).style.display = (m ? '' : 'none');}\" style=\"width: 100%\" />";
|
||||
}
|
||||
writer.println(" <td>" + col + "</td>");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,5 +95,21 @@ public interface Invoker<T> extends org.apache.dubbo.rpc.Invoker<T> {
|
|||
public org.apache.dubbo.rpc.Invoker<T> getOriginal() {
|
||||
return invoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return invoker.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof CompatibleInvoker)) {
|
||||
return false;
|
||||
}
|
||||
return invoker.equals(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -743,6 +743,10 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
|
|||
checkStubAndLocal(interfaceClass);
|
||||
ConfigValidationUtils.checkMock(interfaceClass, this);
|
||||
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
checkRegistry();
|
||||
}
|
||||
|
||||
resolveFile();
|
||||
ConfigValidationUtils.validateReferenceConfig(this);
|
||||
postProcessConfig();
|
||||
|
|
|
|||
|
|
@ -837,12 +837,18 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
|
|||
|
||||
if (StringUtils.isNotEmpty(configCenter.getConfigFile())) {
|
||||
String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
|
||||
if (StringUtils.isNotEmpty(configContent)) {
|
||||
logger.info(String.format("Got global remote configuration from config center with key-%s and group-%s: \n %s", configCenter.getConfigFile(), configCenter.getGroup(), configContent));
|
||||
}
|
||||
String appGroup = getApplication().getName();
|
||||
String appConfigContent = null;
|
||||
String appConfigFile = null;
|
||||
if (isNotEmpty(appGroup)) {
|
||||
appConfigFile = isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile();
|
||||
appConfigContent = dynamicConfiguration.getProperties(appConfigFile, appGroup);
|
||||
if (StringUtils.isNotEmpty(appConfigContent)) {
|
||||
logger.info(String.format("Got application specific remote configuration from config center with key %s and group %s: \n %s", appConfigFile, appGroup, appConfigContent));
|
||||
}
|
||||
}
|
||||
try {
|
||||
Map<String, String> configMap = parseProperties(configContent);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -395,8 +396,10 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
|
|||
}
|
||||
|
||||
private void checkReferences() {
|
||||
Optional<ModuleConfig> module = configManager.getModule();
|
||||
long timeout = module.map(ModuleConfig::getCheckReferenceTimeout).orElse(30000L);
|
||||
for (ReferenceConfigBase<?> rc : configManager.getReferences()) {
|
||||
referenceCache.check(rc, 3000);
|
||||
referenceCache.check(rc, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Hold a set of DubboSpringInitCustomizer, for register customizers by programing.
|
||||
* Hold a set of DubboSpringInitCustomizer, for register customizers by programming.
|
||||
* <p>All customizers are store in thread local, and they will be clear after apply once.</p>
|
||||
*
|
||||
* <p>Usages:</p>
|
||||
|
|
|
|||
|
|
@ -624,6 +624,11 @@
|
|||
<xsd:documentation><![CDATA[ Thread num for asynchronous export pool size. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="check-reference-timeout" type="xsd:long">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ The timeout to check references. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="registryType">
|
||||
|
|
|
|||
|
|
@ -17,11 +17,6 @@
|
|||
|
||||
package org.apache.dubbo.configcenter.support.nacos;
|
||||
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
|
|
@ -38,6 +33,12 @@ import org.apache.dubbo.metrics.config.event.ConfigCenterEvent;
|
|||
import org.apache.dubbo.metrics.event.MetricsEventBus;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
|
@ -107,11 +108,15 @@ public class NacosDynamicConfiguration implements DynamicConfiguration {
|
|||
try {
|
||||
for (int i = 0; i < retryTimes + 1; i++) {
|
||||
tmpConfigServices = NacosFactory.createConfigService(nacosProperties);
|
||||
if (!check || (UP.equals(tmpConfigServices.getServerStatus()) && testConfigService(tmpConfigServices))) {
|
||||
String serverStatus = tmpConfigServices.getServerStatus();
|
||||
boolean configServiceAvailable = testConfigService(tmpConfigServices);
|
||||
if (!check || (UP.equals(serverStatus) && configServiceAvailable)) {
|
||||
break;
|
||||
} else {
|
||||
logger.warn(LoggerCodeConstants.CONFIG_ERROR_NACOS, "", "",
|
||||
"Failed to connect to nacos config server. " +
|
||||
"Server status: " + serverStatus + ". " +
|
||||
"Config Service Available: " + configServiceAvailable + ". " +
|
||||
(i < retryTimes ? "Dubbo will try to retry in " + sleepMsBetweenRetries + ". " : "Exceed retry max times.") +
|
||||
"Try times: " + (i + 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import java.util.Map;
|
|||
*
|
||||
* @Consumers & @Produces can be not used ,we will make sure the content-type of request by arg type
|
||||
* but the Request method is forbidden disappear
|
||||
* parameters which annotation are not present , it is from the body (jaxrs anntation is diffrent from spring web from param(only request param can ignore anntation))
|
||||
* parameters which annotation are not present , it is from the body (jaxrs annotation is different from spring web from param(only request param can ignore annotation))
|
||||
*
|
||||
* Every method only one param from body
|
||||
*
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@
|
|||
<eureka.version>1.10.18</eureka.version>
|
||||
|
||||
<!-- Fabric8 for Kubernetes -->
|
||||
<fabric8_kubernetes_version>6.6.2</fabric8_kubernetes_version>
|
||||
<fabric8_kubernetes_version>6.7.1</fabric8_kubernetes_version>
|
||||
|
||||
<!-- Alibaba -->
|
||||
<alibaba_spring_context_support_version>1.0.11</alibaba_spring_context_support_version>
|
||||
|
|
|
|||
|
|
@ -501,6 +501,11 @@
|
|||
<type>pom</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-observability-starters</artifactId>
|
||||
|
|
@ -531,6 +536,21 @@
|
|||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-zookeeper-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -124,18 +124,20 @@ public abstract class AbstractServiceNameMapping implements ServiceNameMapping {
|
|||
@Override
|
||||
public MappingListener stopListen(URL subscribeURL, MappingListener listener) {
|
||||
synchronized (mappingListeners) {
|
||||
String mappingKey = ServiceNameMapping.buildMappingKey(subscribeURL);
|
||||
Set<MappingListener> listeners = mappingListeners.get(mappingKey);
|
||||
//todo, remove listener from remote metadata center
|
||||
if (CollectionUtils.isNotEmpty(listeners)) {
|
||||
listeners.remove(listener);
|
||||
listener.stop();
|
||||
removeListener(subscribeURL, listener);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(listeners)) {
|
||||
mappingListeners.remove(mappingKey);
|
||||
removeCachedMapping(mappingKey);
|
||||
removeMappingLock(mappingKey);
|
||||
if (listener != null) {
|
||||
String mappingKey = ServiceNameMapping.buildMappingKey(subscribeURL);
|
||||
Set<MappingListener> listeners = mappingListeners.get(mappingKey);
|
||||
//todo, remove listener from remote metadata center
|
||||
if (CollectionUtils.isNotEmpty(listeners)) {
|
||||
listeners.remove(listener);
|
||||
listener.stop();
|
||||
removeListener(subscribeURL, listener);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(listeners)) {
|
||||
mappingListeners.remove(mappingKey);
|
||||
removeCachedMapping(mappingKey);
|
||||
removeMappingLock(mappingKey);
|
||||
}
|
||||
}
|
||||
return listener;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.dubbo.metadata.rest;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
|
@ -32,8 +34,13 @@ public class PathMatcher {
|
|||
private boolean hasPathVariable;
|
||||
private String contextPath;
|
||||
private String httpMethod;
|
||||
// for provider http method compare
|
||||
private boolean needCompareMethod = true;
|
||||
// for provider http method compare,http 405
|
||||
private boolean needCompareHttpMethod = true;
|
||||
// compare method directly (for get Invoker by method)
|
||||
private boolean needCompareServiceMethod = false;
|
||||
|
||||
// service method
|
||||
private Method method;
|
||||
|
||||
|
||||
public PathMatcher(String path) {
|
||||
|
|
@ -53,7 +60,14 @@ public class PathMatcher {
|
|||
setHttpMethod(httpMethod);
|
||||
}
|
||||
|
||||
public PathMatcher(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
private void dealPathVariable(String path) {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
this.pathSplits = path.split(SEPARATOR);
|
||||
|
||||
for (String pathSplit : pathSplits) {
|
||||
|
|
@ -99,6 +113,10 @@ public class PathMatcher {
|
|||
return new PathMatcher(path, version, group, port, method).noNeedHttpMethodCompare();
|
||||
}
|
||||
|
||||
public static PathMatcher getInvokeCreatePathMatcher(Method serviceMethod) {
|
||||
return new PathMatcher(serviceMethod).setNeedCompareServiceMethod(true);
|
||||
}
|
||||
|
||||
public boolean hasPathVariable() {
|
||||
return hasPathVariable;
|
||||
}
|
||||
|
|
@ -117,7 +135,20 @@ public class PathMatcher {
|
|||
}
|
||||
|
||||
private PathMatcher noNeedHttpMethodCompare() {
|
||||
this.needCompareMethod = false;
|
||||
this.needCompareHttpMethod = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
private PathMatcher setNeedCompareServiceMethod(boolean needCompareServiceMethod) {
|
||||
this.needCompareServiceMethod = needCompareServiceMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -126,18 +157,48 @@ public class PathMatcher {
|
|||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PathMatcher that = (PathMatcher) o;
|
||||
return pathEqual(that)
|
||||
&& Objects.equals(version, that.version)
|
||||
&& (this.needCompareMethod ? Objects.equals(httpMethod, that.httpMethod) : true)
|
||||
return serviceMethodEqual(that, this)
|
||||
|| pathMatch(that);
|
||||
}
|
||||
|
||||
private boolean pathMatch(PathMatcher that) {
|
||||
return (!that.needCompareServiceMethod && !needCompareServiceMethod) // no need service method compare
|
||||
&& pathEqual(that) // path compare
|
||||
&& Objects.equals(version, that.version) // service version compare
|
||||
&& httpMethodMatch(that) // http method compare
|
||||
&& Objects.equals(group, that.group) && Objects.equals(port, that.port);
|
||||
}
|
||||
|
||||
/**
|
||||
* it is needed to compare http method when one of needCompareHttpMethod is true,and don`t compare when both needCompareHttpMethod are false
|
||||
*
|
||||
* @param that
|
||||
* @return
|
||||
*/
|
||||
private boolean httpMethodMatch(PathMatcher that) {
|
||||
return !that.needCompareHttpMethod || !this.needCompareHttpMethod ? true: Objects.equals(this.httpMethod, that.httpMethod);
|
||||
}
|
||||
|
||||
private boolean serviceMethodEqual(PathMatcher thatPathMatcher, PathMatcher thisPathMatcher) {
|
||||
Method thatMethod = thatPathMatcher.method;
|
||||
Method thisMethod = thisPathMatcher.method;
|
||||
return thatMethod != null
|
||||
&& thisMethod != null
|
||||
&& (thatPathMatcher.needCompareServiceMethod || thisPathMatcher.needCompareServiceMethod)
|
||||
&& thisMethod.getName().equals(thatMethod.getName())
|
||||
&& Arrays.equals(thisMethod.getParameterTypes(), thatMethod.getParameterTypes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(version, group, port);
|
||||
}
|
||||
|
||||
private boolean pathEqual(PathMatcher pathMatcher) {
|
||||
// path is null return false directly
|
||||
if (this.path == null || pathMatcher.path == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// no place hold
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ public class ServiceRestMetadata implements Serializable {
|
|||
public void addRestMethodMetadata(RestMethodMetadata restMethodMetadata) {
|
||||
PathMatcher pathMather = new PathMatcher(restMethodMetadata.getRequest().getPath(),
|
||||
this.getVersion(), this.getGroup(), this.getPort(),restMethodMetadata.getRequest().getMethod());
|
||||
pathMather.setMethod(restMethodMetadata.getReflectMethod());
|
||||
addPathToServiceMap(pathMather, restMethodMetadata);
|
||||
addMethodToServiceMap(restMethodMetadata);
|
||||
getMeta().add(restMethodMetadata);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import org.apache.dubbo.metadata.rest.PathMatcher;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class PathMatcherTest {
|
||||
|
||||
@Test
|
||||
|
|
@ -65,4 +67,37 @@ public class PathMatcherTest {
|
|||
Assertions.assertEquals(pathMatherMeta, pathMatherMeta1);
|
||||
Assertions.assertEquals(pathMatherMeta.toString(), pathMatherMeta1.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMethodCompare() {
|
||||
Method hashCode = null;
|
||||
Method equals = null;
|
||||
try {
|
||||
hashCode = Object.class.getDeclaredMethod("hashCode");
|
||||
equals = Object.class.getDeclaredMethod("equals", Object.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
|
||||
}
|
||||
|
||||
// no need to compare service method
|
||||
PathMatcher pathMatcher = new PathMatcher(hashCode);
|
||||
PathMatcher pathMatchers = new PathMatcher(hashCode);
|
||||
Assertions.assertNotEquals(pathMatcher, pathMatchers);
|
||||
|
||||
|
||||
// equal
|
||||
PathMatcher pathMatherMetaHashCode = PathMatcher.getInvokeCreatePathMatcher(hashCode);
|
||||
PathMatcher pathMatherMetaHashCodes = new PathMatcher(hashCode);
|
||||
Assertions.assertEquals(pathMatherMetaHashCode, pathMatherMetaHashCodes);
|
||||
|
||||
|
||||
PathMatcher pathMatherMetaEquals = PathMatcher.getInvokeCreatePathMatcher(equals);
|
||||
PathMatcher pathMatherMetaEqual = PathMatcher.getInvokeCreatePathMatcher(equals);
|
||||
Assertions.assertEquals(pathMatherMetaEqual, pathMatherMetaEquals);
|
||||
|
||||
|
||||
Assertions.assertNotEquals(pathMatherMetaHashCode, pathMatherMetaEquals);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,7 +248,9 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
|
|||
serviceDiscovery.unsubscribe(url, listener);
|
||||
String protocolServiceKey = url.getProtocolServiceKey();
|
||||
Set<String> serviceNames = serviceNameMapping.getMapping(url);
|
||||
serviceNameMapping.stopListen(url, mappingListeners.remove(protocolServiceKey));
|
||||
if (mappingListeners.get(protocolServiceKey) != null) {
|
||||
serviceNameMapping.stopListen(url, mappingListeners.remove(protocolServiceKey));
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(serviceNames)) {
|
||||
String serviceNamesKey = toStringKeys(serviceNames);
|
||||
Lock appSubscriptionLock = getAppSubscription(serviceNamesKey);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,18 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> {
|
|||
|
||||
@Override
|
||||
public void subscribe(URL url) {
|
||||
|
||||
// Fail-fast detection protocol spi
|
||||
String queryProtocols = this.queryMap.get(PROTOCOL_KEY);
|
||||
if (StringUtils.isNotBlank(queryProtocols)) {
|
||||
String[] acceptProtocols = queryProtocols.split(",");
|
||||
for (String acceptProtocol : acceptProtocols) {
|
||||
if (!moduleModel.getApplicationModel().getExtensionLoader(Protocol.class).hasExtension(acceptProtocol)) {
|
||||
throw new IllegalStateException("No such extension org.apache.dubbo.rpc.Protocol by name " + acceptProtocol + ", please check whether related SPI module is missing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationModel applicationModel = url.getApplicationModel();
|
||||
MetricsEventBus.post(RegistryEvent.toSubscribeEvent(applicationModel),() ->
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,11 +121,15 @@ public class NacosConnectionManager {
|
|||
try {
|
||||
for (int i = 0; i < retryTimes + 1; i++) {
|
||||
namingService = NacosFactory.createNamingService(nacosProperties);
|
||||
if (!check || (UP.equals(namingService.getServerStatus()) && testNamingService(namingService))) {
|
||||
String serverStatus = namingService.getServerStatus();
|
||||
boolean namingServiceAvailable = testNamingService(namingService);
|
||||
if (!check || (UP.equals(serverStatus) && namingServiceAvailable)) {
|
||||
break;
|
||||
} else {
|
||||
logger.warn(LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION, "", "",
|
||||
"Failed to connect to nacos naming server. " +
|
||||
"Server status: " + serverStatus + ". " +
|
||||
"Naming Service Available: " + namingServiceAvailable + ". " +
|
||||
(i < retryTimes ? "Dubbo will try to retry in " + sleepMsBetweenRetries + ". " : "Exceed retry max times.") +
|
||||
"Try times: " + (i + 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,8 @@ public interface Constants {
|
|||
|
||||
int DEFAULT_RECONNECT_PERIOD = 2000;
|
||||
|
||||
String CHANNEL_SHUTDOWN_TIMEOUT_KEY = "channel.shutdown.timeout";
|
||||
|
||||
String SEND_RECONNECT_KEY = "send.reconnect";
|
||||
|
||||
String CHECK_KEY = "check";
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.remoting.exchange.support;
|
|||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.resource.GlobalResourceInitializer;
|
||||
import org.apache.dubbo.common.serialize.SerializationException;
|
||||
import org.apache.dubbo.common.timer.HashedWheelTimer;
|
||||
import org.apache.dubbo.common.timer.Timeout;
|
||||
import org.apache.dubbo.common.timer.Timer;
|
||||
|
|
@ -26,7 +27,6 @@ import org.apache.dubbo.common.timer.TimerTask;
|
|||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.common.serialize.SerializationException;
|
||||
import org.apache.dubbo.remoting.TimeoutException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
|
|
@ -150,22 +150,39 @@ public class DefaultFuture extends CompletableFuture<Object> {
|
|||
*
|
||||
* @param channel channel to close
|
||||
*/
|
||||
public static void closeChannel(Channel channel) {
|
||||
public static void closeChannel(Channel channel, long timeout) {
|
||||
long deadline = timeout > 0 ? System.currentTimeMillis() + timeout : 0;
|
||||
for (Map.Entry<Long, Channel> entry : CHANNELS.entrySet()) {
|
||||
if (channel.equals(entry.getValue())) {
|
||||
DefaultFuture future = getFuture(entry.getKey());
|
||||
if (future != null && !future.isDone()) {
|
||||
Response disconnectResponse = new Response(future.getId());
|
||||
disconnectResponse.setStatus(Response.CHANNEL_INACTIVE);
|
||||
disconnectResponse.setErrorMessage("Channel " +
|
||||
channel + " is inactive. Directly return the unFinished request : " +
|
||||
(logger.isDebugEnabled() ? future.getRequest() : future.getRequest().copyWithoutData()));
|
||||
DefaultFuture.received(channel, disconnectResponse);
|
||||
long restTime = deadline - System.currentTimeMillis();
|
||||
if (restTime > 0) {
|
||||
try {
|
||||
future.get(restTime, TimeUnit.MILLISECONDS);
|
||||
} catch (java.util.concurrent.TimeoutException ignore) {
|
||||
logger.warn(PROTOCOL_TIMEOUT_SERVER, "", "",
|
||||
"Trying to close channel " + channel + ", but response is not received in "
|
||||
+ timeout + "ms, and the request id is " + future.id);
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
if (!future.isDone()) {
|
||||
respInactive(channel, future);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void respInactive(Channel channel, DefaultFuture future) {
|
||||
Response disconnectResponse = new Response(future.getId());
|
||||
disconnectResponse.setStatus(Response.CHANNEL_INACTIVE);
|
||||
disconnectResponse.setErrorMessage("Channel " +
|
||||
channel + " is inactive. Directly return the unFinished request : " +
|
||||
(logger.isDebugEnabled() ? future.getRequest() : future.getRequest().copyWithoutData()));
|
||||
DefaultFuture.received(channel, disconnectResponse);
|
||||
}
|
||||
|
||||
public static void received(Channel channel, Response response) {
|
||||
received(channel, response, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.remoting.exchange.support.header;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
|
|
@ -30,6 +31,7 @@ import org.apache.dubbo.remoting.exchange.Response;
|
|||
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
|
|
@ -48,6 +50,8 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
|
||||
private final Channel channel;
|
||||
|
||||
private final long shutdownTimeout;
|
||||
|
||||
private volatile boolean closed = false;
|
||||
|
||||
HeaderExchangeChannel(Channel channel) {
|
||||
|
|
@ -55,6 +59,10 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
throw new IllegalArgumentException("channel == null");
|
||||
}
|
||||
this.channel = channel;
|
||||
this.shutdownTimeout = Optional.ofNullable(channel.getUrl())
|
||||
.map(URL::getOrDefaultApplicationModel)
|
||||
.map(ConfigurationUtils::getServerShutdownTimeout)
|
||||
.orElse(DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
static HeaderExchangeChannel getOrAddChannel(Channel ch) {
|
||||
|
|
@ -159,7 +167,7 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
closed = true;
|
||||
try {
|
||||
// graceful close
|
||||
DefaultFuture.closeChannel(channel);
|
||||
DefaultFuture.closeChannel(channel, shutdownTimeout);
|
||||
} catch (Exception e) {
|
||||
logger.warn(TRANSPORT_FAILED_CLOSE, "", "", e.getMessage(), e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.dubbo.remoting.exchange.support.header;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
|
|
@ -132,6 +133,8 @@ public class HeaderExchangeHandler implements ChannelHandlerDelegate {
|
|||
public void connected(Channel channel) throws RemotingException {
|
||||
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
|
||||
handler.connected(exchangeChannel);
|
||||
channel.setAttribute(Constants.CHANNEL_SHUTDOWN_TIMEOUT_KEY,
|
||||
ConfigurationUtils.getServerShutdownTimeout(channel.getUrl().getOrDefaultApplicationModel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -140,7 +143,12 @@ public class HeaderExchangeHandler implements ChannelHandlerDelegate {
|
|||
try {
|
||||
handler.disconnected(exchangeChannel);
|
||||
} finally {
|
||||
DefaultFuture.closeChannel(channel);
|
||||
int shutdownTimeout = 0;
|
||||
Object timeoutObj = channel.getAttribute(Constants.CHANNEL_SHUTDOWN_TIMEOUT_KEY);
|
||||
if (timeoutObj instanceof Integer) {
|
||||
shutdownTimeout = (Integer) timeoutObj;
|
||||
}
|
||||
DefaultFuture.closeChannel(channel, shutdownTimeout);
|
||||
HeaderExchangeChannel.removeChannel(channel);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class DefaultFutureTest {
|
|||
try {
|
||||
new InterruptThread(Thread.currentThread()).start();
|
||||
while (!f. isDone()){
|
||||
executor.waitAndDrain();
|
||||
executor.waitAndDrain(Long.MAX_VALUE);
|
||||
}
|
||||
f.get();
|
||||
} catch (Exception e) {
|
||||
|
|
@ -167,7 +167,7 @@ class DefaultFutureTest {
|
|||
ExecutorService executor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class)
|
||||
.getDefaultExtension().createExecutorIfAbsent(URL.valueOf("dubbo://127.0.0.1:23456"));
|
||||
DefaultFuture.newFuture(channel, request, 1000, executor);
|
||||
DefaultFuture.closeChannel(channel);
|
||||
DefaultFuture.closeChannel(channel, 0);
|
||||
Assertions.assertFalse(executor.isTerminated());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ public class AsyncRpcResult implements Result {
|
|||
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
|
||||
try {
|
||||
while (!responseFuture.isDone()) {
|
||||
threadlessExecutor.waitAndDrain();
|
||||
threadlessExecutor.waitAndDrain(Long.MAX_VALUE);
|
||||
}
|
||||
} finally {
|
||||
threadlessExecutor.shutdown();
|
||||
|
|
@ -195,17 +195,27 @@ public class AsyncRpcResult implements Result {
|
|||
|
||||
@Override
|
||||
public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
long deadline = System.nanoTime() + unit.toNanos(timeout);
|
||||
if (executor != null && executor instanceof ThreadlessExecutor) {
|
||||
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
|
||||
try {
|
||||
while (!responseFuture.isDone()) {
|
||||
threadlessExecutor.waitAndDrain();
|
||||
long restTime = deadline - System.nanoTime();
|
||||
if (restTime > 0) {
|
||||
threadlessExecutor.waitAndDrain(deadline);
|
||||
} else {
|
||||
throw new TimeoutException("Timeout after " + unit.toMillis(timeout) + "ms waiting for result.");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
threadlessExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
return responseFuture.get(timeout, unit);
|
||||
long restTime = deadline - System.nanoTime();
|
||||
if (!responseFuture.isDone() && restTime < 0) {
|
||||
throw new TimeoutException("Timeout after " + unit.toMillis(timeout) + "ms waiting for result.");
|
||||
}
|
||||
return responseFuture.get(restTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||
|
|
@ -63,7 +62,7 @@ public abstract class AbstractProtocol implements Protocol, ScopeModelAware {
|
|||
/**
|
||||
* <host:port, ProtocolServer>
|
||||
*/
|
||||
protected final ConcurrentMap<String, ProtocolServer> serverMap = new ConcurrentHashMap<>();
|
||||
protected final Map<String, ProtocolServer> serverMap = new ConcurrentHashMap<>();
|
||||
|
||||
// TODO SoftReference
|
||||
protected final Set<Invoker<?>> invokers = new ConcurrentHashSet<>();
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@ package org.apache.dubbo.rpc.protocol;
|
|||
|
||||
import org.apache.dubbo.common.Parameters;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.RemotingServer;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
|
|
@ -30,7 +32,6 @@ import org.apache.dubbo.rpc.Invoker;
|
|||
import org.apache.dubbo.rpc.ProtocolServer;
|
||||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
|
@ -41,6 +42,8 @@ import java.util.Objects;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED;
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +51,7 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNS
|
|||
*/
|
||||
public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
||||
|
||||
protected final List<Class<?>> rpcExceptions = new CopyOnWriteArrayList<Class<?>>();
|
||||
private final List<Class<?>> rpcExceptions = new CopyOnWriteArrayList<Class<?>>();
|
||||
|
||||
protected ProxyFactory proxyFactory;
|
||||
|
||||
|
|
@ -84,35 +87,7 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
return exporter;
|
||||
}
|
||||
}
|
||||
final Runnable runnable = doExport(proxyFactory.getProxy(
|
||||
new Invoker<T>() {
|
||||
@Override
|
||||
public Class<T> getInterface() {
|
||||
return invoker.getInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
RpcContext.getServiceContext().getObjectAttachments().forEach(invocation::setObjectAttachment);
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return invoker.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return invoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
invoker.destroy();
|
||||
}
|
||||
}, true), invoker.getInterface(),
|
||||
invoker.getUrl());
|
||||
final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl());
|
||||
exporter = new AbstractExporter<T>(invoker) {
|
||||
@Override
|
||||
public void afterUnExport() {
|
||||
|
|
@ -130,6 +105,46 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
return exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> Invoker<T> protocolBindingRefer(final Class<T> type, final URL url) throws RpcException {
|
||||
final Invoker<T> target = proxyFactory.getInvoker(doRefer(type, url), type, url);
|
||||
Invoker<T> invoker = new AbstractInvoker<T>(type, url) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
try {
|
||||
Result result = target.invoke(invocation);
|
||||
// FIXME result is an AsyncRpcResult instance.
|
||||
Throwable e = result.getException();
|
||||
if (e != null) {
|
||||
for (Class<?> rpcException : rpcExceptions) {
|
||||
if (rpcException.isAssignableFrom(e.getClass())) {
|
||||
throw getRpcException(type, url, invocation, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (RpcException e) {
|
||||
if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
|
||||
e.setCode(getErrorCode(e.getCause()));
|
||||
}
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
throw getRpcException(type, url, invocation, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
target.destroy();
|
||||
invokers.remove(this);
|
||||
AbstractProxyProtocol.this.destroyInternal(url);
|
||||
}
|
||||
};
|
||||
invokers.add(invoker);
|
||||
return invoker;
|
||||
}
|
||||
|
||||
// used to destroy unused clients and other resource
|
||||
protected void destroyInternal(URL url) {
|
||||
// subclass override
|
||||
|
|
@ -142,12 +157,22 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
return re;
|
||||
}
|
||||
|
||||
protected String getAddr(URL url) {
|
||||
String bindIp = url.getParameter(Constants.BIND_IP_KEY, url.getHost());
|
||||
if (url.getParameter(ANYHOST_KEY, false)) {
|
||||
bindIp = ANYHOST_VALUE;
|
||||
}
|
||||
return NetUtils.getIpByHost(bindIp) + ":" + url.getParameter(Constants.BIND_PORT_KEY, url.getPort());
|
||||
}
|
||||
|
||||
protected int getErrorCode(Throwable e) {
|
||||
return RpcException.UNKNOWN_EXCEPTION;
|
||||
}
|
||||
|
||||
protected abstract <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException;
|
||||
|
||||
protected abstract <T> T doRefer(Class<T> type, URL url) throws RpcException;
|
||||
|
||||
protected class ProxyProtocolServer implements ProtocolServer {
|
||||
|
||||
private RemotingServer server;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.apache.dubbo.metadata.rest.PathMatcher;
|
|||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.protocol.rest.exception.DoublePathCheckException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.exception.PathNoFoundException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.pair.InvokerAndRestMethodMetadataPair;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -56,31 +55,26 @@ public class PathAndInvokerMapper {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* acquire metadata & invoker by service info
|
||||
*
|
||||
* @param path
|
||||
* @param version
|
||||
* @param group
|
||||
* @param port
|
||||
* get rest method metadata by path matcher
|
||||
* @param pathMatcher
|
||||
* @return
|
||||
*/
|
||||
public InvokerAndRestMethodMetadataPair getRestMethodMetadata(String path, String version, String group, Integer port,String method) {
|
||||
|
||||
|
||||
PathMatcher pathMather = PathMatcher.getInvokeCreatePathMatcher(path, version, group, port,method);
|
||||
public InvokerAndRestMethodMetadataPair getRestMethodMetadata(PathMatcher pathMatcher) {
|
||||
|
||||
// first search from pathToServiceMapNoPathVariable
|
||||
if (pathToServiceMapNoPathVariable.containsKey(pathMather)) {
|
||||
return pathToServiceMapNoPathVariable.get(pathMather);
|
||||
if (pathToServiceMapNoPathVariable.containsKey(pathMatcher)) {
|
||||
return pathToServiceMapNoPathVariable.get(pathMatcher);
|
||||
}
|
||||
|
||||
// second search from pathToServiceMapContainPathVariable
|
||||
if (pathToServiceMapContainPathVariable.containsKey(pathMather)) {
|
||||
return pathToServiceMapContainPathVariable.get(pathMather);
|
||||
if (pathToServiceMapContainPathVariable.containsKey(pathMatcher)) {
|
||||
return pathToServiceMapContainPathVariable.get(pathMatcher);
|
||||
}
|
||||
|
||||
throw new PathNoFoundException("rest service Path no found, current path info:" + pathMather);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import org.apache.dubbo.rpc.protocol.rest.annotation.metadata.MetadataResolver;
|
|||
import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployer;
|
||||
import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployerManager;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
|
|
|||
|
|
@ -20,16 +20,21 @@ import org.apache.dubbo.common.BaseServiceMetadata;
|
|||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.metadata.rest.ArgInfo;
|
||||
import org.apache.dubbo.metadata.rest.PathMatcher;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.ParamParserManager;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.provider.ProviderParseContext;
|
||||
import org.apache.dubbo.rpc.protocol.rest.constans.RestConstant;
|
||||
import org.apache.dubbo.rpc.protocol.rest.exception.ParamParseException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.pair.InvokerAndRestMethodMetadataPair;
|
||||
import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade;
|
||||
import org.apache.dubbo.rpc.protocol.rest.util.HttpHeaderUtil;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -77,15 +82,15 @@ public class RestRPCInvocationUtil {
|
|||
* create parseMethodArgs context
|
||||
*
|
||||
* @param request
|
||||
* @param servletRequest
|
||||
* @param servletResponse
|
||||
* @param originRequest
|
||||
* @param originResponse
|
||||
* @param restMethodMetadata
|
||||
* @return
|
||||
*/
|
||||
private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) {
|
||||
private static ProviderParseContext createParseContext(RequestFacade request, Object originRequest, Object originResponse, RestMethodMetadata restMethodMetadata) {
|
||||
ProviderParseContext parseContext = new ProviderParseContext(request);
|
||||
parseContext.setResponse(servletResponse);
|
||||
parseContext.setRequest(servletRequest);
|
||||
parseContext.setResponse(originResponse);
|
||||
parseContext.setRequest(originRequest);
|
||||
|
||||
Object[] objects = new Object[restMethodMetadata.getArgInfos().size()];
|
||||
parseContext.setArgs(Arrays.asList(objects));
|
||||
|
|
@ -124,19 +129,105 @@ public class RestRPCInvocationUtil {
|
|||
|
||||
|
||||
/**
|
||||
* get path mapping
|
||||
* get InvokerAndRestMethodMetadataPair by path matcher
|
||||
*
|
||||
* @param request
|
||||
* @param pathAndInvokerMapper
|
||||
* @param pathMatcher
|
||||
* @return
|
||||
*/
|
||||
public static InvokerAndRestMethodMetadataPair getRestMethodMetadata(RequestFacade request, PathAndInvokerMapper pathAndInvokerMapper) {
|
||||
public static InvokerAndRestMethodMetadataPair getRestMethodMetadataAndInvokerPair(PathMatcher pathMatcher) {
|
||||
|
||||
PathAndInvokerMapper pathAndInvokerMapper = (PathAndInvokerMapper) RpcContext.getServerAttachment().getObjectAttachment(RestConstant.PATH_AND_INVOKER_MAPPER);
|
||||
|
||||
if (pathAndInvokerMapper == null) {
|
||||
return null;
|
||||
}
|
||||
return pathAndInvokerMapper.getRestMethodMetadata(pathMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* get InvokerAndRestMethodMetadataPair from rpc context
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static InvokerAndRestMethodMetadataPair getRestMethodMetadataAndInvokerPair(RequestFacade request) {
|
||||
|
||||
|
||||
PathMatcher pathMather = createPathMatcher(request);
|
||||
|
||||
return getRestMethodMetadataAndInvokerPair(pathMather);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get invoker by request
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static Invoker getInvokerByRequest(RequestFacade request) {
|
||||
|
||||
PathMatcher pathMatcher = createPathMatcher(request);
|
||||
|
||||
return getInvoker(pathMatcher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get invoker by service method
|
||||
*
|
||||
* compare method`s name,param types
|
||||
*
|
||||
* @param serviceMethod
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static Invoker getInvokerByServiceInvokeMethod(Method serviceMethod) {
|
||||
|
||||
if (serviceMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(PathMatcher.getInvokeCreatePathMatcher(serviceMethod));
|
||||
|
||||
if (pair == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return pair.getInvoker();
|
||||
}
|
||||
|
||||
/**
|
||||
* get invoker by path matcher
|
||||
*
|
||||
* @param pathMatcher
|
||||
* @return
|
||||
*/
|
||||
public static Invoker getInvoker(PathMatcher pathMatcher) {
|
||||
InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(pathMatcher);
|
||||
|
||||
if (pair == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return pair.getInvoker();
|
||||
}
|
||||
|
||||
/**
|
||||
* create path matcher by request
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static PathMatcher createPathMatcher(RequestFacade request) {
|
||||
String path = request.getPath();
|
||||
String version = request.getHeader(RestHeaderEnum.VERSION.getHeader());
|
||||
String group = request.getHeader(RestHeaderEnum.GROUP.getHeader());
|
||||
String method = request.getMethod();
|
||||
|
||||
return pathAndInvokerMapper.getRestMethodMetadata(path, version, group, null, method);
|
||||
return PathMatcher.getInvokeCreatePathMatcher(path, version, group, null, method);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,5 +63,10 @@ public interface RestConstant {
|
|||
int IDLE_TIMEOUT = -1;
|
||||
int KEEP_ALIVE_TIMEOUT = 60;
|
||||
|
||||
/**
|
||||
* ServerAttachment pathAndInvokerMapper key
|
||||
*/
|
||||
String PATH_AND_INVOKER_MAPPER = "pathAndInvokerMapper";
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.dubbo.rpc.protocol.rest.handler;
|
||||
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
|
|
@ -45,6 +46,8 @@ import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.apache.dubbo.rpc.protocol.rest.constans.RestConstant.PATH_AND_INVOKER_MAPPER;
|
||||
|
||||
/**
|
||||
* netty http request handler
|
||||
*/
|
||||
|
|
@ -78,6 +81,8 @@ public class NettyHttpHandler implements HttpHandler<NettyRequestFacade, NettyHt
|
|||
|
||||
// set response
|
||||
RpcContext.getServiceContext().setResponse(nettyHttpResponse);
|
||||
|
||||
RpcContext.getServerAttachment().setObjectAttachment(PATH_AND_INVOKER_MAPPER, pathAndInvokerMapper);
|
||||
// TODO add request filter chain
|
||||
|
||||
FullHttpRequest nettyHttpRequest = requestFacade.getRequest();
|
||||
|
|
@ -102,9 +107,14 @@ public class NettyHttpHandler implements HttpHandler<NettyRequestFacade, NettyHt
|
|||
|
||||
}
|
||||
|
||||
private void doHandler(FullHttpRequest nettyHttpRequest, NettyHttpResponse nettyHttpResponse, RequestFacade request) throws Exception {
|
||||
protected void doHandler(HttpRequest nettyHttpRequest, NettyHttpResponse nettyHttpResponse, RequestFacade request) throws Exception {
|
||||
// acquire metadata by request
|
||||
InvokerAndRestMethodMetadataPair restMethodMetadataPair = RestRPCInvocationUtil.getRestMethodMetadata(request, pathAndInvokerMapper);
|
||||
InvokerAndRestMethodMetadataPair restMethodMetadataPair = RestRPCInvocationUtil.getRestMethodMetadataAndInvokerPair(request);
|
||||
|
||||
// path NoFound 404
|
||||
if (restMethodMetadataPair == null) {
|
||||
throw new PathNoFoundException("rest service Path no found, current path info:" + RestRPCInvocationUtil.createPathMatcher(request));
|
||||
}
|
||||
|
||||
Invoker invoker = restMethodMetadataPair.getInvoker();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ import org.apache.dubbo.rpc.protocol.rest.rest.HttpMethodServiceImpl;
|
|||
import org.apache.dubbo.rpc.protocol.rest.rest.RestDemoForTestException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.rest.RestDemoService;
|
||||
import org.apache.dubbo.rpc.protocol.rest.rest.RestDemoServiceImpl;
|
||||
import org.apache.dubbo.rpc.protocol.rest.rest.TestGetInvokerService;
|
||||
import org.apache.dubbo.rpc.protocol.rest.rest.TestGetInvokerServiceImpl;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
|
@ -596,6 +598,27 @@ class JaxrsRestProtocolTest {
|
|||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetInvoker() {
|
||||
Assertions.assertDoesNotThrow(()->{
|
||||
URL exportUrl = URL.valueOf("rest://127.0.0.1:" + availablePort + "/rest?interface=org.apache.dubbo.rpc.protocol.rest.rest.TestGetInvokerService");
|
||||
|
||||
TestGetInvokerService server = new TestGetInvokerServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<TestGetInvokerService> exporter = protocol.export(proxy.getInvoker(server, TestGetInvokerService.class, url));
|
||||
|
||||
TestGetInvokerService invokerService = this.proxy.getProxy(protocol.refer(TestGetInvokerService.class, url));
|
||||
|
||||
|
||||
String invoker = invokerService.getInvoker();
|
||||
Assertions.assertEquals("success", invoker);
|
||||
|
||||
exporter.unexport();
|
||||
});
|
||||
}
|
||||
|
||||
private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {
|
||||
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
|
||||
ProviderModel providerModel = new ProviderModel(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.rest.rest;
|
||||
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
@Path("/test")
|
||||
public interface TestGetInvokerService {
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/getInvoker")
|
||||
String getInvoker();
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.rest.rest;
|
||||
|
||||
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.protocol.rest.RestRPCInvocationUtil;
|
||||
import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestGetInvokerServiceImpl implements TestGetInvokerService {
|
||||
|
||||
|
||||
@Override
|
||||
public String getInvoker() {
|
||||
Object request = RpcContext.getServiceContext().getRequest();
|
||||
Invoker invokerByRequest = RestRPCInvocationUtil.getInvokerByRequest((RequestFacade) request);
|
||||
|
||||
|
||||
Method hello = null;
|
||||
Method hashcode = null;
|
||||
try {
|
||||
hello = TestGetInvokerServiceImpl.class.getDeclaredMethod("getInvoker");
|
||||
hashcode = TestGetInvokerServiceImpl.class.getDeclaredMethod("hashcode");
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
|
||||
}
|
||||
|
||||
Invoker invokerByServiceInvokeMethod = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hello);
|
||||
|
||||
Invoker invoker = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hashcode);
|
||||
|
||||
|
||||
Assertions.assertEquals(invokerByRequest, invokerByServiceInvokeMethod);
|
||||
Assertions.assertNull(invoker);
|
||||
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>Apache Dubbo Nacos Spring Boot Starter</description>
|
||||
|
||||
<properties>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>Apache Dubbo Zookeeper Curator5 Spring Boot Starter</description>
|
||||
|
||||
<properties>
|
||||
<curator5_version>5.1.0</curator5_version>
|
||||
<zookeeper_version>3.8.1</zookeeper_version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>${zookeeper_version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-x-discovery</artifactId>
|
||||
<version>${curator5_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
<version>${zookeeper_version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-annotations</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial.snappy</groupId>
|
||||
<artifactId>snappy-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-zookeeper-spring-boot-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>Apache Dubbo Zookeeper Spring Boot Starter</description>
|
||||
|
||||
<properties>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-x-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot</artifactId>
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
<properties>
|
||||
<micrometer.version>1.11.0</micrometer.version>
|
||||
<micrometer-tracing.version>1.1.1</micrometer-tracing.version>
|
||||
<opentelemetry.version>1.26.0</opentelemetry.version>
|
||||
<opentelemetry.version>1.27.0</opentelemetry.version>
|
||||
<zipkin-reporter.version>2.16.4</zipkin-reporter.version>
|
||||
<prometheus-client.version>0.16.0</prometheus-client.version>
|
||||
</properties>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-spring-boot-starters</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<description>Apache Dubbo Spring Boot Starters</description>
|
||||
|
||||
<modules>
|
||||
<module>observability</module>
|
||||
<module>dubbo-nacos-spring-boot-starter</module>
|
||||
<module>dubbo-zookeeper-spring-boot-starter</module>
|
||||
<module>dubbo-zookeeper-curator5-spring-boot-starter</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<module>dubbo-spring-boot-autoconfigure</module>
|
||||
<module>dubbo-spring-boot-compatible</module>
|
||||
<module>dubbo-spring-boot-starter</module>
|
||||
<module>dubbo-spring-boot-observability-starters</module>
|
||||
<module>dubbo-spring-boot-starters</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<log4j2_version>2.20.0</log4j2_version>
|
||||
<!-- Spring boot buddy is lower than the delivery dependency package version and can only show the defined dependency version -->
|
||||
<byte-buddy.version>1.14.4</byte-buddy.version>
|
||||
<byte-buddy.version>1.14.5</byte-buddy.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
|
|||
|
|
@ -417,6 +417,21 @@
|
|||
<artifactId>dubbo-spring-boot-observability-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-zookeeper-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class FileTest {
|
|||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-metadata-processor"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-native.*"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-config-spring6.*"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-spring-boot.*"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile(".*spring-boot.*"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-annotation-processor.*"));
|
||||
ignoredModulesInDubboAll.add(Pattern.compile("dubbo-maven-plugin"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue