Merge branch '3.x-dev'
This commit is contained in:
commit
9f5cc83d34
|
|
@ -6,6 +6,7 @@ target/
|
|||
*.zip
|
||||
*.tar
|
||||
*.tar.gz
|
||||
.flattened-pom.xml
|
||||
|
||||
# eclipse ignore
|
||||
.settings/
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class RouterChain<T> {
|
|||
|
||||
private RouterChain(URL url) {
|
||||
List<RouterFactory> extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
|
||||
.getActivateExtension(url, (String[]) null);
|
||||
.getActivateExtension(url, "router");
|
||||
|
||||
List<Router> routers = extensionFactories.stream()
|
||||
.map(factory -> factory.getRouter(url))
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class MockInvokersSelector extends AbstractRouter {
|
|||
if (invocation.getAttachments() == null) {
|
||||
return getNormalInvokers(invokers);
|
||||
} else {
|
||||
String value = invocation.getAttachments().get(INVOCATION_NEED_MOCK);
|
||||
String value = (String) invocation.getAttachments().get(INVOCATION_NEED_MOCK);
|
||||
if (value == null) {
|
||||
return getNormalInvokers(invokers);
|
||||
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
|
|||
|
||||
List<Invoker<T>> result = invokers;
|
||||
String tag = StringUtils.isEmpty(invocation.getAttachment(Constants.TAG_KEY)) ? url.getParameter(Constants.TAG_KEY) :
|
||||
invocation.getAttachment(Constants.TAG_KEY);
|
||||
(String) invocation.getAttachment(Constants.TAG_KEY);
|
||||
|
||||
// if we are requesting for a Provider with a specific tag
|
||||
if (StringUtils.isNotEmpty(tag)) {
|
||||
|
|
@ -164,7 +164,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
|
|||
List<Invoker<T>> result = invokers;
|
||||
// Dynamic param
|
||||
String tag = StringUtils.isEmpty(invocation.getAttachment(Constants.TAG_KEY)) ? url.getParameter(Constants.TAG_KEY) :
|
||||
invocation.getAttachment(Constants.TAG_KEY);
|
||||
(String) invocation.getAttachment(Constants.TAG_KEY);
|
||||
// Tag request
|
||||
if (!StringUtils.isEmpty(tag)) {
|
||||
result = filterInvoker(invokers, invoker -> tag.equals(invoker.getUrl().getParameter(TAG_KEY)));
|
||||
|
|
@ -189,7 +189,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
|
|||
}
|
||||
|
||||
private boolean isForceUseTag(Invocation invocation) {
|
||||
return Boolean.valueOf(invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
|
||||
return Boolean.valueOf((String) invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
|
||||
}
|
||||
|
||||
private <T> List<Invoker<T>> filterInvoker(List<Invoker<T>> invokers, Predicate<Invoker<T>> predicate) {
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
|
|||
checkWhetherDestroyed();
|
||||
|
||||
// binding attachments into invocation.
|
||||
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
|
||||
Map<String, Object> contextAttachments = RpcContext.getContext().getAttachments();
|
||||
if (contextAttachments != null && contextAttachments.size() != 0) {
|
||||
((RpcInvocation) invocation).addAttachments(contextAttachments);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ public class MockDirInvocation implements Invocation {
|
|||
return new Object[]{"aa"};
|
||||
}
|
||||
|
||||
public Map<String, String> getAttachments() {
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
public Map<String, Object> getAttachments() {
|
||||
Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
|
|
@ -58,12 +58,12 @@ public class MockDirInvocation implements Invocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
public void setAttachment(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
public void setAttachmentIfAbsent(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -71,12 +71,27 @@ public class MockDirInvocation implements Invocation {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getAttachment(String key) {
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ public class AbstractClusterInvokerTest {
|
|||
|
||||
// setup attachment
|
||||
RpcContext.getContext().setAttachment(attachKey, attachValue);
|
||||
Map<String, String> attachments = RpcContext.getContext().getAttachments();
|
||||
Map<String, Object> attachments = RpcContext.getContext().getAttachments();
|
||||
Assertions.assertTrue( attachments != null && attachments.size() == 1,"set attachment failed!");
|
||||
|
||||
cluster = new AbstractClusterInvoker(dic) {
|
||||
|
|
@ -158,7 +158,7 @@ public class AbstractClusterInvokerTest {
|
|||
protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
|
||||
throws RpcException {
|
||||
// attachment will be bind to invocation
|
||||
String value = invocation.getAttachment(attachKey);
|
||||
String value = (String) invocation.getAttachment(attachKey);
|
||||
Assertions.assertTrue(value != null && value.equals(attachValue),"binding attachment failed!");
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,156 +1,155 @@
|
|||
/*
|
||||
* 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.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* ForkingClusterInvokerTest
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ForkingClusterInvokerTest {
|
||||
|
||||
private List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
|
||||
private URL url = URL.valueOf("test://test:11/test?forks=2");
|
||||
private Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
|
||||
private Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
|
||||
private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
|
||||
private RpcInvocation invocation = new RpcInvocation();
|
||||
private Directory<ForkingClusterInvokerTest> dic;
|
||||
private Result result = new AppResponse();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
||||
dic = mock(Directory.class);
|
||||
|
||||
given(dic.getUrl()).willReturn(url);
|
||||
given(dic.list(invocation)).willReturn(invokers);
|
||||
given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
invocation.setMethodName("method1");
|
||||
|
||||
invokers.add(invoker1);
|
||||
invokers.add(invoker2);
|
||||
invokers.add(invoker3);
|
||||
|
||||
}
|
||||
|
||||
private void resetInvokerToException() {
|
||||
given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker1.getUrl()).willReturn(url);
|
||||
given(invoker1.isAvailable()).willReturn(true);
|
||||
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker2.getUrl()).willReturn(url);
|
||||
given(invoker2.isAvailable()).willReturn(true);
|
||||
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker3.getUrl()).willReturn(url);
|
||||
given(invoker3.isAvailable()).willReturn(true);
|
||||
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
}
|
||||
|
||||
private void resetInvokerToNoException() {
|
||||
given(invoker1.invoke(invocation)).willReturn(result);
|
||||
given(invoker1.getUrl()).willReturn(url);
|
||||
given(invoker1.isAvailable()).willReturn(true);
|
||||
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker2.invoke(invocation)).willReturn(result);
|
||||
given(invoker2.getUrl()).willReturn(url);
|
||||
given(invoker2.isAvailable()).willReturn(true);
|
||||
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker3.invoke(invocation)).willReturn(result);
|
||||
given(invoker3.getUrl()).willReturn(url);
|
||||
given(invoker3.isAvailable()).willReturn(true);
|
||||
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeException() {
|
||||
resetInvokerToException();
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
|
||||
try {
|
||||
invoker.invoke(invocation);
|
||||
Assertions.fail();
|
||||
} catch (RpcException expected) {
|
||||
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
|
||||
assertFalse(expected.getCause() instanceof RpcException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearRpcContext() {
|
||||
resetInvokerToException();
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
|
||||
String attachKey = "attach";
|
||||
String attachValue = "value";
|
||||
|
||||
RpcContext.getContext().setAttachment(attachKey, attachValue);
|
||||
|
||||
Map<String, String> attachments = RpcContext.getContext().getAttachments();
|
||||
Assertions.assertTrue(attachments != null && attachments.size() == 1, "set attachment failed!");
|
||||
try {
|
||||
invoker.invoke(invocation);
|
||||
Assertions.fail();
|
||||
} catch (RpcException expected) {
|
||||
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"), "Succeeded to forking invoke provider !");
|
||||
assertFalse(expected.getCause() instanceof RpcException);
|
||||
}
|
||||
Map<String, String> afterInvoke = RpcContext.getContext().getAttachments();
|
||||
Assertions.assertTrue(afterInvoke != null && afterInvoke.size() == 0, "clear attachment failed!");
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void testInvokeNoException() {
|
||||
|
||||
resetInvokerToNoException();
|
||||
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
Result ret = invoker.invoke(invocation);
|
||||
Assertions.assertSame(result, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* ForkingClusterInvokerTest
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ForkingClusterInvokerTest {
|
||||
|
||||
private List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
|
||||
private URL url = URL.valueOf("test://test:11/test?forks=2");
|
||||
private Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
|
||||
private Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
|
||||
private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
|
||||
private RpcInvocation invocation = new RpcInvocation();
|
||||
private Directory<ForkingClusterInvokerTest> dic;
|
||||
private Result result = new AppResponse();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
||||
dic = mock(Directory.class);
|
||||
|
||||
given(dic.getUrl()).willReturn(url);
|
||||
given(dic.list(invocation)).willReturn(invokers);
|
||||
given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
invocation.setMethodName("method1");
|
||||
|
||||
invokers.add(invoker1);
|
||||
invokers.add(invoker2);
|
||||
invokers.add(invoker3);
|
||||
|
||||
}
|
||||
|
||||
private void resetInvokerToException() {
|
||||
given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker1.getUrl()).willReturn(url);
|
||||
given(invoker1.isAvailable()).willReturn(true);
|
||||
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker2.getUrl()).willReturn(url);
|
||||
given(invoker2.isAvailable()).willReturn(true);
|
||||
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
|
||||
given(invoker3.getUrl()).willReturn(url);
|
||||
given(invoker3.isAvailable()).willReturn(true);
|
||||
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
}
|
||||
|
||||
private void resetInvokerToNoException() {
|
||||
given(invoker1.invoke(invocation)).willReturn(result);
|
||||
given(invoker1.getUrl()).willReturn(url);
|
||||
given(invoker1.isAvailable()).willReturn(true);
|
||||
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker2.invoke(invocation)).willReturn(result);
|
||||
given(invoker2.getUrl()).willReturn(url);
|
||||
given(invoker2.isAvailable()).willReturn(true);
|
||||
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
|
||||
given(invoker3.invoke(invocation)).willReturn(result);
|
||||
given(invoker3.getUrl()).willReturn(url);
|
||||
given(invoker3.isAvailable()).willReturn(true);
|
||||
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeException() {
|
||||
resetInvokerToException();
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
|
||||
try {
|
||||
invoker.invoke(invocation);
|
||||
Assertions.fail();
|
||||
} catch (RpcException expected) {
|
||||
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
|
||||
assertFalse(expected.getCause() instanceof RpcException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearRpcContext() {
|
||||
resetInvokerToException();
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
|
||||
String attachKey = "attach";
|
||||
String attachValue = "value";
|
||||
|
||||
RpcContext.getContext().setAttachment(attachKey, attachValue);
|
||||
|
||||
Map<String, Object> attachments = RpcContext.getContext().getAttachments();
|
||||
Assertions.assertTrue(attachments != null && attachments.size() == 1, "set attachment failed!");
|
||||
try {
|
||||
invoker.invoke(invocation);
|
||||
Assertions.fail();
|
||||
} catch (RpcException expected) {
|
||||
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"), "Succeeded to forking invoke provider !");
|
||||
assertFalse(expected.getCause() instanceof RpcException);
|
||||
}
|
||||
Map<String, Object> afterInvoke = RpcContext.getContext().getAttachments();
|
||||
Assertions.assertTrue(afterInvoke != null && afterInvoke.size() == 0, "clear attachment failed!");
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void testInvokeNoException() {
|
||||
|
||||
resetInvokerToNoException();
|
||||
|
||||
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
|
||||
dic);
|
||||
Result ret = invoker.invoke(invocation);
|
||||
Assertions.assertSame(result, ret);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ public class MergeableClusterInvokerTest {
|
|||
given(invocation.getMethodName()).willReturn("getMenu");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{});
|
||||
given(invocation.getAttachments()).willReturn(new HashMap<String, String>())
|
||||
given(invocation.getAttachments()).willReturn(new HashMap<String, Object>())
|
||||
;
|
||||
given(invocation.getInvoker()).willReturn(firstInvoker);
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ public class MergeableClusterInvokerTest {
|
|||
new Class<?>[]{String.class, List.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{menu, menuItems})
|
||||
;
|
||||
given(invocation.getAttachments()).willReturn(new HashMap<String, String>())
|
||||
given(invocation.getAttachments()).willReturn(new HashMap<String, Object>())
|
||||
;
|
||||
given(invocation.getInvoker()).willReturn(firstInvoker);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,18 +16,47 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.config;
|
||||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Configuration from system properties and dubbo.properties
|
||||
*/
|
||||
public class PropertiesConfiguration extends AbstractPrefixConfiguration {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertiesConfiguration.class);
|
||||
|
||||
public PropertiesConfiguration(String prefix, String id) {
|
||||
super(prefix, id);
|
||||
|
||||
ExtensionLoader<OrderedPropertiesProvider> propertiesProviderExtensionLoader = ExtensionLoader.getExtensionLoader(OrderedPropertiesProvider.class);
|
||||
Set<String> propertiesProviderNames = propertiesProviderExtensionLoader.getSupportedExtensions();
|
||||
if (propertiesProviderNames == null || propertiesProviderNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<OrderedPropertiesProvider> orderedPropertiesProviders = new ArrayList<>();
|
||||
for (String propertiesProviderName : propertiesProviderNames) {
|
||||
orderedPropertiesProviders.add(propertiesProviderExtensionLoader.getExtension(propertiesProviderName));
|
||||
}
|
||||
|
||||
//order the propertiesProvider according the priority descending
|
||||
orderedPropertiesProviders.sort((OrderedPropertiesProvider a, OrderedPropertiesProvider b) -> {
|
||||
return b.priority() - a.priority();
|
||||
});
|
||||
|
||||
//load the default properties
|
||||
Properties properties = ConfigUtils.getProperties();
|
||||
|
||||
//override the properties.
|
||||
for (OrderedPropertiesProvider orderedPropertiesProvider :
|
||||
orderedPropertiesProviders) {
|
||||
properties.putAll(orderedPropertiesProvider.initProperties());
|
||||
}
|
||||
|
||||
ConfigUtils.setProperties(properties);
|
||||
}
|
||||
|
||||
public PropertiesConfiguration() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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.common.threadpool;
|
||||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.AbstractExecutorService;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* The most important difference between this Executor and other normal Executor is that this one doesn't manage
|
||||
* any thread.
|
||||
*
|
||||
* Tasks submitted to this executor through {@link #execute(Runnable)} will not get scheduled to a specific thread, though normal executors always do the schedule.
|
||||
* Those tasks are stored in a blocking queue and will only be executed when a thead calls {@link #waitAndDrain()}, the thead executing the task
|
||||
* is exactly the same as the one calling waitAndDrain.
|
||||
*/
|
||||
public class ThreadlessExecutor extends AbstractExecutorService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ThreadlessExecutor.class.getName());
|
||||
|
||||
private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
private ExecutorService sharedExecutor;
|
||||
|
||||
private volatile boolean waiting = true;
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
public ThreadlessExecutor(ExecutorService sharedExecutor) {
|
||||
this.sharedExecutor = sharedExecutor;
|
||||
}
|
||||
|
||||
public boolean isWaiting() {
|
||||
return waiting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until there is a Runnable, then executes it and all queued Runnables after it.
|
||||
*/
|
||||
public void waitAndDrain() throws InterruptedException {
|
||||
Runnable runnable = queue.take();
|
||||
|
||||
synchronized (lock) {
|
||||
waiting = false;
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
runnable = queue.poll();
|
||||
while (runnable != null) {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Throwable t) {
|
||||
logger.info(t);
|
||||
|
||||
}
|
||||
runnable = queue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
public long waitAndDrain(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
|
||||
/*long startInMs = System.currentTimeMillis();
|
||||
Runnable runnable = queue.poll(timeout, unit);
|
||||
if (runnable == null) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
runnable.run();
|
||||
long elapsedInMs = System.currentTimeMillis() - startInMs;
|
||||
long timeLeft = timeout - elapsedInMs;
|
||||
if (timeLeft < 0) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
return timeLeft;*/
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the calling thread is still waiting for a callback task, add the task into the blocking queue to wait for schedule.
|
||||
* Otherwise, submit to shared callback executor directly.
|
||||
*
|
||||
* @param runnable
|
||||
*/
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
synchronized (lock) {
|
||||
if (!waiting) {
|
||||
sharedExecutor.execute(runnable);
|
||||
} else {
|
||||
queue.add(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tells the thread blocking on {@link #waitAndDrain()} to return, despite of the current status, to avoid endless waiting.
|
||||
*/
|
||||
public void notifyReturn() {
|
||||
// an empty runnable task.
|
||||
execute(() -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The following methods are still not supported
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Runnable> shutdownNow() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.common.threadpool.manager;
|
||||
|
||||
import org.apache.dubbo.common.Constants;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.threadpool.ThreadPool;
|
||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* Consider implementing {@link Licycle} to enable executors shutdown when the process stops.
|
||||
*/
|
||||
public class DefaultExecutorRepository implements ExecutorRepository {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultExecutorRepository.class);
|
||||
|
||||
private int DEFAULT_SCHEDULER_SIZE = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
private final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true));
|
||||
|
||||
private Ring<ScheduledExecutorService> scheduledExecutors = new Ring<>();
|
||||
|
||||
private ScheduledExecutorService reconnectScheduledExecutor;
|
||||
|
||||
private ConcurrentMap<String, ConcurrentMap<String, ExecutorService>> data = new ConcurrentHashMap<>();
|
||||
|
||||
public DefaultExecutorRepository() {
|
||||
for (int i = 0; i < DEFAULT_SCHEDULER_SIZE; i++) {
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-framework-scheduler"));
|
||||
scheduledExecutors.addItem(scheduler);
|
||||
}
|
||||
|
||||
reconnectScheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-reconnect-scheduler"));
|
||||
}
|
||||
|
||||
public ExecutorService createExecutorIfAbsent(URL url) {
|
||||
String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
|
||||
if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) {
|
||||
componentKey = Constants.CONSUMER_SIDE;
|
||||
}
|
||||
Map<String, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
|
||||
return executors.computeIfAbsent(Integer.toString(url.getPort()), k -> (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateThreadpool(URL url, ExecutorService executor) {
|
||||
try {
|
||||
if (url.hasParameter(Constants.THREADS_KEY)
|
||||
&& executor instanceof ThreadPoolExecutor && !executor.isShutdown()) {
|
||||
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
|
||||
int threads = url.getParameter(Constants.THREADS_KEY, 0);
|
||||
int max = threadPoolExecutor.getMaximumPoolSize();
|
||||
int core = threadPoolExecutor.getCorePoolSize();
|
||||
if (threads > 0 && (threads != max || threads != core)) {
|
||||
if (threads < core) {
|
||||
threadPoolExecutor.setCorePoolSize(threads);
|
||||
if (core == max) {
|
||||
threadPoolExecutor.setMaximumPoolSize(threads);
|
||||
}
|
||||
} else {
|
||||
threadPoolExecutor.setMaximumPoolSize(threads);
|
||||
if (core == max) {
|
||||
threadPoolExecutor.setCorePoolSize(threads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService nextScheduledExecutor() {
|
||||
return scheduledExecutors.pollItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService getSharedExecutor() {
|
||||
return SHARED_EXECUTOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.common.threadpool.manager;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@SPI("default")
|
||||
public interface ExecutorRepository {
|
||||
|
||||
/**
|
||||
* Called by both Client and Server. TODO, consider separate these two parts.
|
||||
* When the Client or Server starts for the first time, generate a new threadpool according to the parameters passed in usr.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
ExecutorService createExecutorIfAbsent(URL url);
|
||||
|
||||
/**
|
||||
* Modify some of the threadpool's properties according to the url, for example, coreSize, maxSize, ...
|
||||
*
|
||||
* @param url
|
||||
* @param executor
|
||||
*/
|
||||
void updateThreadpool(URL url, ExecutorService executor);
|
||||
|
||||
/**
|
||||
* Returns a scheduler from the scheduler list, call this method whenever you need a scheduler for a cron job.
|
||||
* If your cron cannot burden the possible schedule delay caused by sharing the same scheduler, please consider define a dedicate one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ScheduledExecutorService nextScheduledExecutor();
|
||||
|
||||
/**
|
||||
* Get the default shared threadpool.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ExecutorService getSharedExecutor();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.common.threadpool.manager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Ring<T> {
|
||||
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
|
||||
private List<T> itemList = new CopyOnWriteArrayList<T>();
|
||||
|
||||
public void addItem(T t) {
|
||||
if (t != null) {
|
||||
itemList.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public T pollItem() {
|
||||
if (itemList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (itemList.size() == 1) {
|
||||
return itemList.get(0);
|
||||
}
|
||||
|
||||
if (count.intValue() > Integer.MAX_VALUE - 10000) {
|
||||
count.set(count.get() % itemList.size());
|
||||
}
|
||||
|
||||
int index = Math.abs(count.getAndIncrement()) % itemList.size();
|
||||
return itemList.get(index);
|
||||
}
|
||||
|
||||
public T peekItem() {
|
||||
if (itemList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (itemList.size() == 1) {
|
||||
return itemList.get(0);
|
||||
}
|
||||
int index = Math.abs(count.get()) % itemList.size();
|
||||
return itemList.get(index);
|
||||
}
|
||||
|
||||
public List<T> listItems() {
|
||||
return Collections.unmodifiableList(itemList);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
default=org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.common.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class MockOrderedPropertiesProvider2 implements OrderedPropertiesProvider {
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties initProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.put("testKey", "999");
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.common.config;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PropertiesConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void testOrderPropertiesProviders() {
|
||||
PropertiesConfiguration configuration = new PropertiesConfiguration("test", null);
|
||||
Assertions.assertTrue(configuration.getInternalProperty("testKey").equals("999"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
mock1=org.apache.dubbo.common.config.MockOrderedPropertiesProvider1
|
||||
mock2=org.apache.dubbo.common.config.MockOrderedPropertiesProvider2
|
||||
|
|
@ -30,15 +30,15 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
default void setAttachmentIfAbsent(String key, String value) {
|
||||
default void setAttachmentIfAbsent(String key, Object value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setAttachment(String key, String value) {
|
||||
default void setAttachment(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
class CompatibleInvocation implements Invocation, org.apache.dubbo.rpc.Invocation {
|
||||
class CompatibleInvocation implements Invocation {
|
||||
|
||||
private org.apache.dubbo.rpc.Invocation delegate;
|
||||
|
||||
|
|
@ -62,17 +62,17 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return delegate.getAttachments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return delegate.getAttachment(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return delegate.getAttachment(key, defaultValue);
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +81,21 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
|
|||
return new Invoker.CompatibleInvoker(delegate.getInvoker());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return delegate.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return delegate.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return delegate.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.apache.dubbo.rpc.Invocation getOriginal() {
|
||||
return delegate;
|
||||
|
|
|
|||
|
|
@ -83,32 +83,32 @@ public interface Result extends org.apache.dubbo.rpc.Result {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return delegate.getAttachments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
public void addAttachments(Map<String, Object> map) {
|
||||
delegate.addAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
public void setAttachments(Map<String, Object> map) {
|
||||
delegate.setAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return delegate.getAttachment(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return delegate.getAttachment(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
public void setAttachment(String key, Object value) {
|
||||
delegate.setAttachment(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,17 +65,17 @@ public class CacheTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -83,5 +83,20 @@ public class CacheTest {
|
|||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.filter;
|
|||
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.common.Constants;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -53,8 +54,8 @@ public class LegacyInvocation implements Invocation {
|
|||
return new Object[]{arg0};
|
||||
}
|
||||
|
||||
public Map<String, String> getAttachments() {
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
public Map<String, Object> getAttachments() {
|
||||
Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
|
|
@ -68,11 +69,26 @@ public class LegacyInvocation implements Invocation {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getAttachment(String key) {
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,88 +1,103 @@
|
|||
/*
|
||||
* 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.service;
|
||||
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* MockInvocation.java
|
||||
*/
|
||||
public class MockInvocation implements Invocation {
|
||||
|
||||
private String arg0;
|
||||
|
||||
public MockInvocation(String arg0) {
|
||||
this.arg0 = arg0;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return "echo";
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return new Class[]{String.class};
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return new Object[]{arg0};
|
||||
}
|
||||
|
||||
public Map<String, String> getAttachments() {
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
|
||||
attachments.put(TOKEN_KEY, "sfag");
|
||||
attachments.put(TIMEOUT_KEY, "1000");
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.service;
|
||||
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* MockInvocation.java
|
||||
*/
|
||||
public class MockInvocation implements Invocation {
|
||||
|
||||
private String arg0;
|
||||
|
||||
public MockInvocation(String arg0) {
|
||||
this.arg0 = arg0;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return "echo";
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return new Class[]{String.class};
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return new Object[]{arg0};
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttachments() {
|
||||
Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
|
||||
attachments.put(TOKEN_KEY, "sfag");
|
||||
attachments.put(TIMEOUT_KEY, "1000");
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
/**
|
||||
* Dynamically add some parameters / check config
|
||||
*/
|
||||
|
||||
@SPI
|
||||
public interface AppendParametersComponent {
|
||||
default void appendReferParameters(ReferenceConfig referenceConfig) {
|
||||
|
||||
}
|
||||
|
||||
default void appendExportParameters(ServiceConfig serviceConfig) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,9 @@ import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
|
|||
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
|
||||
import org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ConsumerMethodModel;
|
||||
import org.apache.dubbo.rpc.model.ConsumerModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceMetadata;
|
||||
import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.ProtocolUtils;
|
||||
|
|
@ -46,7 +48,6 @@ import org.apache.dubbo.rpc.support.ProtocolUtils;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -172,6 +173,8 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
*/
|
||||
private transient volatile boolean destroyed;
|
||||
|
||||
private ServiceMetadata serviceMetadata;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Object finalizerGuardian = new Object() {
|
||||
@Override
|
||||
|
|
@ -193,9 +196,13 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
};
|
||||
|
||||
public ReferenceConfig() {
|
||||
serviceMetadata = new ServiceMetadata();
|
||||
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
|
||||
}
|
||||
|
||||
public ReferenceConfig(Reference reference) {
|
||||
serviceMetadata = new ServiceMetadata();
|
||||
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
|
||||
appendAnnotation(Reference.class, reference);
|
||||
setMethods(MethodConfig.constructMethodConfig(reference.methods()));
|
||||
}
|
||||
|
|
@ -238,6 +245,13 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
resolveFile();
|
||||
checkApplication();
|
||||
checkMetadataReport();
|
||||
appendParameters();
|
||||
}
|
||||
|
||||
private void appendParameters() {
|
||||
URL appendParametersUrl = URL.valueOf("appendParameters://");
|
||||
List<AppendParametersComponent> appendParametersComponents = ExtensionLoader.getExtensionLoader(AppendParametersComponent.class).getActivateExtension(appendParametersUrl, (String[]) null);
|
||||
appendParametersComponents.forEach(component -> component.appendReferParameters(this));
|
||||
}
|
||||
|
||||
public synchronized T get() {
|
||||
|
|
@ -275,11 +289,18 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
}
|
||||
checkStubAndLocal(interfaceClass);
|
||||
checkMock(interfaceClass);
|
||||
|
||||
//init serivceMetadata
|
||||
serviceMetadata.setVersion(version);
|
||||
serviceMetadata.setGroup(group);
|
||||
serviceMetadata.setDefaultGroup(group);
|
||||
serviceMetadata.setServiceType(getActualInterface());
|
||||
serviceMetadata.setServiceInterfaceName(interfaceName);
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
map.put(SIDE_KEY, CONSUMER_SIDE);
|
||||
|
||||
appendRuntimeParameters(map);
|
||||
|
||||
if (!isGeneric()) {
|
||||
String revision = Version.getVersion(interfaceClass, version);
|
||||
if (revision != null && revision.length() > 0) {
|
||||
|
|
@ -326,13 +347,29 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
}
|
||||
map.put(REGISTER_IP_KEY, hostToRegistry);
|
||||
|
||||
serviceMetadata.getAttachments().putAll(map);
|
||||
|
||||
ref = createProxy(map);
|
||||
|
||||
String serviceKey = URL.buildKey(interfaceName, group, version);
|
||||
ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
|
||||
ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes, serviceMetadata));
|
||||
serviceMetadata.setTarget(ref);
|
||||
consumerModel.getServiceMetadata().addAttribute(Constants.PROXY_CLASS_REF, ref);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private Class<?> getActualInterface() {
|
||||
Class actualInterface = interfaceClass;
|
||||
if (interfaceClass == GenericService.class) {
|
||||
try {
|
||||
actualInterface = Class.forName(interfaceName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return actualInterface;
|
||||
}
|
||||
|
||||
private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
|
||||
Method[] methods = interfaceClass.getMethods();
|
||||
Class serviceInterface = interfaceClass;
|
||||
|
|
@ -622,6 +659,10 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
return invoker;
|
||||
}
|
||||
|
||||
public ServiceMetadata getServiceMetadata() {
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Parameter(excluded = true)
|
||||
public String getPrefix() {
|
||||
|
|
@ -661,4 +702,9 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Parameter(excluded = true)
|
||||
public String getUniqueServiceName() {
|
||||
return URL.buildKey(interfaceName, group, version);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.apache.dubbo.rpc.ProxyFactory;
|
|||
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ProviderModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceMetadata;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.ProtocolUtils;
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
*
|
||||
* <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
|
||||
* the protocol is <b>DubboProtocol</b></li>
|
||||
* <p>
|
||||
*
|
||||
* Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
|
||||
* layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
|
||||
*/
|
||||
|
|
@ -194,10 +195,16 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
*/
|
||||
private volatile String generic;
|
||||
|
||||
private ServiceMetadata serviceMetadata;
|
||||
|
||||
public ServiceConfig() {
|
||||
serviceMetadata = new ServiceMetadata();
|
||||
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
|
||||
}
|
||||
|
||||
public ServiceConfig(Service service) {
|
||||
serviceMetadata = new ServiceMetadata();
|
||||
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
|
||||
appendAnnotation(Service.class, service);
|
||||
setMethods(MethodConfig.constructMethodConfig(service.methods()));
|
||||
}
|
||||
|
|
@ -354,6 +361,13 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
}
|
||||
checkStubAndLocal(interfaceClass);
|
||||
checkMock(interfaceClass);
|
||||
appendParameters();
|
||||
}
|
||||
|
||||
private void appendParameters() {
|
||||
URL appendParametersUrl = URL.valueOf("appendParameters://");
|
||||
List<AppendParametersComponent> appendParametersComponents = ExtensionLoader.getExtensionLoader(AppendParametersComponent.class).getActivateExtension(appendParametersUrl, (String[]) null);
|
||||
appendParametersComponents.forEach(component -> component.appendExportParameters(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -368,6 +382,14 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
public synchronized void export() {
|
||||
checkAndUpdateSubConfigs();
|
||||
|
||||
//init serviceMetadata
|
||||
serviceMetadata.setVersion(version);
|
||||
serviceMetadata.setGroup(group);
|
||||
serviceMetadata.setDefaultGroup(group);
|
||||
serviceMetadata.setServiceType(interfaceClass);
|
||||
serviceMetadata.setServiceInterfaceName(interfaceName);
|
||||
serviceMetadata.setTarget(ref);
|
||||
|
||||
if (!shouldExport()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -556,6 +578,9 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
map.put(TOKEN_KEY, token);
|
||||
}
|
||||
}
|
||||
//init serviceMetadata attachments
|
||||
serviceMetadata.getAttachments().putAll(map);
|
||||
|
||||
// export service
|
||||
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
|
||||
Integer port = this.findConfigedPorts(protocolConfig, name, map);
|
||||
|
|
@ -1032,6 +1057,10 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
return urls;
|
||||
}
|
||||
|
||||
public ServiceMetadata getServiceMetadata() {
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Replace to getProtocols()
|
||||
*/
|
||||
|
|
@ -1053,4 +1082,9 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
public String getPrefix() {
|
||||
return DUBBO + ".service." + interfaceName;
|
||||
}
|
||||
|
||||
@Parameter(excluded = true)
|
||||
public String getUniqueServiceName() {
|
||||
return URL.buildKey(interfaceName, group, version);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,5 @@
|
|||
<artifactId>tomcat-embed-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public interface DynamicConfiguration extends Configuration {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* {@link #removeListener(String, String, ConfigurationListener)}
|
||||
*
|
||||
* @param key the key to represent a configuration
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import org.apache.dubbo.demo.DemoService;
|
|||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component("demoServiceComponent")
|
||||
public class DemoServiceComponent implements DemoService {
|
||||
@Reference
|
||||
|
|
@ -33,4 +35,9 @@ public class DemoServiceComponent implements DemoService {
|
|||
public String sayHello(String name) {
|
||||
return demoService.sayHello(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> sayHelloAsync(String name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import org.apache.dubbo.rpc.RpcContext;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Service
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
|
||||
|
|
@ -35,4 +37,9 @@ public class DemoServiceImpl implements DemoService {
|
|||
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> sayHelloAsync(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.RpcContext;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
|
||||
|
||||
|
|
@ -31,4 +33,9 @@ public class DemoServiceImpl implements DemoService {
|
|||
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> sayHelloAsync(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@
|
|||
*/
|
||||
package org.apache.dubbo.demo;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface DemoService {
|
||||
|
||||
String sayHello(String name);
|
||||
|
||||
CompletableFuture<String> sayHelloAsync(String name);
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.RpcContext;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
|
||||
|
||||
|
|
@ -31,4 +33,14 @@ public class DemoServiceImpl implements DemoService {
|
|||
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> sayHelloAsync(String name) {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return CompletableFuture.completedFuture("future return value!");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ public interface JValidatorTestTarget {
|
|||
|
||||
void someMethod5(Map<String, String> map);
|
||||
|
||||
public void someMethod3(ValidationParameter[] parameters);
|
||||
|
||||
public void someMethod4(List<String> strings);
|
||||
|
||||
public void someMethod5(Map<String, String> map);
|
||||
|
||||
@interface Test2 {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,5 +88,4 @@ public interface MonitorService {
|
|||
*/
|
||||
List<URL> lookup(URL query);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.registry;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SPI
|
||||
public interface AddressListener {
|
||||
|
||||
/**
|
||||
* processing when receiving the address list
|
||||
*
|
||||
* @param addresses provider address list
|
||||
* @param registryDirectoryUrl
|
||||
*/
|
||||
List<URL> notify(List<URL> addresses, URL registryDirectoryUrl);
|
||||
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import org.apache.dubbo.common.utils.NetUtils;
|
|||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.common.utils.UrlUtils;
|
||||
import org.apache.dubbo.configcenter.DynamicConfiguration;
|
||||
import org.apache.dubbo.registry.AddressListener;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
|
|
@ -230,6 +231,16 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
|
|||
|
||||
// providers
|
||||
List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());
|
||||
/**
|
||||
* 3.x added for extend URL address
|
||||
*/
|
||||
ExtensionLoader<AddressListener> addressListenerExtensionLoader = ExtensionLoader.getExtensionLoader(AddressListener.class);
|
||||
List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);
|
||||
if (supportedListeners != null && !supportedListeners.isEmpty()) {
|
||||
for (AddressListener addressListener : supportedListeners) {
|
||||
providerURLs = addressListener.notify(providerURLs, getUrl());
|
||||
}
|
||||
}
|
||||
refreshOverrideAndInvoker(providerURLs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
|||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class MockChannel implements ExchangeChannel {
|
||||
|
||||
|
|
@ -93,6 +94,16 @@ public class MockChannel implements ExchangeChannel {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExchangeHandler getExchangeHandler() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import java.net.InetSocketAddress;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
|
|
@ -81,13 +82,23 @@ public class MockedClient implements ExchangeClient {
|
|||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object msg) throws RemotingException {
|
||||
return request(msg, 0);
|
||||
return request(msg, null);
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> request(Object msg, int timeout) throws RemotingException {
|
||||
return this.request(msg, timeout, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object msg, ExecutorService executor) throws RemotingException {
|
||||
return this.request(msg, 0, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object msg, int timeout, ExecutorService executor) throws RemotingException {
|
||||
this.invoked = msg;
|
||||
return new CompletableFuture<Object>() {
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
return received;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,20 +33,17 @@
|
|||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Libraries -->
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.Channel;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* ExchangeChannel. (API/SPI, Prototype, ThreadSafe)
|
||||
|
|
@ -33,6 +34,7 @@ public interface ExchangeChannel extends Channel {
|
|||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
@Deprecated
|
||||
CompletableFuture<Object> request(Object request) throws RemotingException;
|
||||
|
||||
/**
|
||||
|
|
@ -43,8 +45,28 @@ public interface ExchangeChannel extends Channel {
|
|||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
@Deprecated
|
||||
CompletableFuture<Object> request(Object request, int timeout) throws RemotingException;
|
||||
|
||||
/**
|
||||
* send request.
|
||||
*
|
||||
* @param request
|
||||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException;
|
||||
|
||||
/**
|
||||
* send request.
|
||||
*
|
||||
* @param request
|
||||
* @param timeout
|
||||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException;
|
||||
|
||||
/**
|
||||
* get message handler.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,6 +16,16 @@
|
|||
*/
|
||||
package org.apache.dubbo.remoting.exchange;
|
||||
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.Codec;
|
||||
import org.apache.dubbo.remoting.Decodeable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*/
|
||||
|
|
@ -173,4 +183,55 @@ public class Response {
|
|||
return "Response [id=" + mId + ", version=" + mVersion + ", status=" + mStatus + ", event=" + mEvent
|
||||
+ ", error=" + mErrorMsg + ", result=" + (mResult == this ? "this" : mResult) + "]";
|
||||
}
|
||||
|
||||
public static class AppResult {
|
||||
|
||||
protected Map<String, String> attachments = new HashMap<String, String>();
|
||||
|
||||
protected Object result;
|
||||
|
||||
protected Throwable exception;
|
||||
|
||||
public Map<String, String> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public void setAttachments(Map<String, String> attachments) {
|
||||
this.attachments = attachments;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public void setException(Throwable exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DecodeableAppResult implements Codec, Decodeable {
|
||||
|
||||
@Override
|
||||
public void decode() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Channel channel, OutputStream output, Object message) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(Channel channel, InputStream input) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,9 +31,7 @@ import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
|||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* ExchangeReceiver
|
||||
|
|
@ -100,11 +98,21 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request) throws RemotingException {
|
||||
return request(request, channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT));
|
||||
return request(request, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
|
||||
return request(request, timeout, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
return request(request, channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
if (closed) {
|
||||
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
|
||||
}
|
||||
|
|
@ -113,7 +121,7 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
req.setVersion(Version.getProtocolVersion());
|
||||
req.setTwoWay(true);
|
||||
req.setData(request);
|
||||
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
|
||||
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
|
||||
try {
|
||||
channel.send(req);
|
||||
} catch (RemotingException e) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.dubbo.remoting.utils.UrlUtils.getHeartbeat;
|
||||
|
|
@ -84,6 +85,16 @@ public class HeaderExchangeClient implements ExchangeClient {
|
|||
return channel.request(request, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
return channel.request(request, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
return channel.request(request, timeout, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getChannelHandler() {
|
||||
return channel.getChannelHandler();
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import org.apache.dubbo.common.Version;
|
|||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.store.DataStore;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
import org.apache.dubbo.common.utils.ExecutorUtil;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
|
|
@ -50,6 +50,7 @@ public abstract class AbstractClient extends AbstractEndpoint implements Client
|
|||
private final Lock connectLock = new ReentrantLock();
|
||||
private final boolean needReconnect;
|
||||
protected volatile ExecutorService executor;
|
||||
private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
|
||||
|
||||
public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
|
||||
super(url, handler);
|
||||
|
|
@ -84,11 +85,7 @@ public abstract class AbstractClient extends AbstractEndpoint implements Client
|
|||
"Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress()
|
||||
+ " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
|
||||
executor = (ExecutorService) ExtensionLoader.getExtensionLoader(DataStore.class)
|
||||
.getDefaultExtension().get(CONSUMER_SIDE, Integer.toString(url.getPort()));
|
||||
ExtensionLoader.getExtensionLoader(DataStore.class)
|
||||
.getDefaultExtension().remove(CONSUMER_SIDE, Integer.toString(url.getPort()));
|
||||
executor = executorRepository.createExecutorIfAbsent(url);
|
||||
}
|
||||
|
||||
protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handler) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import org.apache.dubbo.common.URL;
|
|||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.store.DataStore;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
import org.apache.dubbo.common.utils.ExecutorUtil;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
|
|
@ -32,7 +32,6 @@ import org.apache.dubbo.remoting.Server;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||
|
|
@ -55,6 +54,8 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
|
|||
private int accepts;
|
||||
private int idleTimeout;
|
||||
|
||||
private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
|
||||
|
||||
public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
|
||||
super(url, handler);
|
||||
localAddress = getUrl().toInetSocketAddress();
|
||||
|
|
@ -76,9 +77,7 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
|
|||
throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
|
||||
+ " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
//fixme replace this with better method
|
||||
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
|
||||
executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
|
||||
executor = executorRepository.createExecutorIfAbsent(url);
|
||||
}
|
||||
|
||||
protected abstract void doOpen() throws Throwable;
|
||||
|
|
@ -110,30 +109,7 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
|
|||
} catch (Throwable t) {
|
||||
logger.error(t.getMessage(), t);
|
||||
}
|
||||
try {
|
||||
if (url.hasParameter(THREADS_KEY)
|
||||
&& executor instanceof ThreadPoolExecutor && !executor.isShutdown()) {
|
||||
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
|
||||
int threads = url.getParameter(THREADS_KEY, 0);
|
||||
int max = threadPoolExecutor.getMaximumPoolSize();
|
||||
int core = threadPoolExecutor.getCorePoolSize();
|
||||
if (threads > 0 && (threads != max || threads != core)) {
|
||||
if (threads < core) {
|
||||
threadPoolExecutor.setCorePoolSize(threads);
|
||||
if (core == max) {
|
||||
threadPoolExecutor.setMaximumPoolSize(threads);
|
||||
}
|
||||
} else {
|
||||
threadPoolExecutor.setMaximumPoolSize(threads);
|
||||
if (core == max) {
|
||||
threadPoolExecutor.setCorePoolSize(threads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error(t.getMessage(), t);
|
||||
}
|
||||
executorRepository.updateThreadpool(url, executor);
|
||||
super.setUrl(getUrl().addParameters(url.getParameters()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class CodecSupport {
|
|||
private static final Logger logger = LoggerFactory.getLogger(CodecSupport.class);
|
||||
private static Map<Byte, Serialization> ID_SERIALIZATION_MAP = new HashMap<Byte, Serialization>();
|
||||
private static Map<Byte, String> ID_SERIALIZATIONNAME_MAP = new HashMap<Byte, String>();
|
||||
private static Map<String, Byte> SERIALIZATIONNAME_ID_MAP = new HashMap<String, Byte>();
|
||||
|
||||
static {
|
||||
Set<String> supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions();
|
||||
|
|
@ -55,6 +56,7 @@ public class CodecSupport {
|
|||
}
|
||||
ID_SERIALIZATION_MAP.put(idByte, serialization);
|
||||
ID_SERIALIZATIONNAME_MAP.put(idByte, name);
|
||||
SERIALIZATIONNAME_ID_MAP.put(name, idByte);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +67,10 @@ public class CodecSupport {
|
|||
return ID_SERIALIZATION_MAP.get(id);
|
||||
}
|
||||
|
||||
public static byte getIDByName(String name) {
|
||||
return SERIALIZATIONNAME_ID_MAP.get(name);
|
||||
}
|
||||
|
||||
public static Serialization getSerialization(URL url) {
|
||||
return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(
|
||||
url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION));
|
||||
|
|
|
|||
|
|
@ -20,29 +20,21 @@ import org.apache.dubbo.common.URL;
|
|||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.store.DataStore;
|
||||
import org.apache.dubbo.common.threadpool.ThreadPool;
|
||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
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.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
||||
import org.apache.dubbo.remoting.transport.ChannelHandlerDelegate;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
|
||||
|
||||
public class WrappedChannelHandler implements ChannelHandlerDelegate {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class);
|
||||
|
||||
protected static final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true));
|
||||
|
||||
protected final ExecutorService executor;
|
||||
|
||||
protected final ChannelHandler handler;
|
||||
|
||||
protected final URL url;
|
||||
|
|
@ -50,24 +42,10 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
|
|||
public WrappedChannelHandler(ChannelHandler handler, URL url) {
|
||||
this.handler = handler;
|
||||
this.url = url;
|
||||
executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url);
|
||||
|
||||
String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
|
||||
if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
|
||||
componentKey = CONSUMER_SIDE;
|
||||
}
|
||||
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
|
||||
dataStore.put(componentKey, Integer.toString(url.getPort()), executor);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -95,8 +73,16 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
|
|||
handler.caught(channel, exception);
|
||||
}
|
||||
|
||||
public ExecutorService getExecutor() {
|
||||
return executor;
|
||||
protected void sendFeedback(Channel channel, Request request, Throwable t) throws RemotingException {
|
||||
if (request.isTwoWay()) {
|
||||
String msg = "Server side(" + url.getIp() + "," + url.getPort()
|
||||
+ ") thread pool is exhausted, detail msg:" + t.getMessage();
|
||||
Response response = new Response(request.getId(), request.getVersion());
|
||||
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
|
||||
response.setErrorMessage(msg);
|
||||
channel.send(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -112,8 +98,45 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
|
|||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently, this method is mainly customized to facilitate the thread model on consumer side.
|
||||
* 1. Use ThreadlessExecutor, aka., delegate callback directly to the thread initiating the call.
|
||||
* 2. Use shared executor to execute the callback.
|
||||
*
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
public ExecutorService getPreferredExecutorService(Object msg) {
|
||||
if (msg instanceof Response) {
|
||||
Response response = (Response) msg;
|
||||
DefaultFuture responseFuture = DefaultFuture.getFuture(response.getId());
|
||||
// a typical scenario is the response returned after timeout, the timeout response may has completed the future
|
||||
if (responseFuture == null) {
|
||||
return getSharedExecutorService();
|
||||
} else {
|
||||
ExecutorService executor = responseFuture.getExecutor();
|
||||
if (executor == null || executor.isShutdown()) {
|
||||
executor = getSharedExecutorService();
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
} else {
|
||||
return getSharedExecutorService();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the shared executor for current Server or Client
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ExecutorService getSharedExecutorService() {
|
||||
return ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().createExecutorIfAbsent(url);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ExecutorService getExecutorService() {
|
||||
return executor == null || executor.isShutdown() ? SHARED_EXECUTOR : executor;
|
||||
return getSharedExecutorService();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.apache.dubbo.remoting.ChannelHandler;
|
|||
import org.apache.dubbo.remoting.ExecutionException;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
|
||||
|
|
@ -58,22 +57,13 @@ public class AllChannelHandler extends WrappedChannelHandler {
|
|||
|
||||
@Override
|
||||
public void received(Channel channel, Object message) throws RemotingException {
|
||||
ExecutorService executor = getExecutorService();
|
||||
ExecutorService executor = getPreferredExecutorService(message);
|
||||
try {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
} catch (Throwable t) {
|
||||
//TODO A temporary solution to the problem that the exception information can not be sent to the opposite end after the thread pool is full. Need a refactoring
|
||||
//fix The thread pool is full, refuses to call, does not return, and causes the consumer to wait for time out
|
||||
if(message instanceof Request && t instanceof RejectedExecutionException){
|
||||
Request request = (Request)message;
|
||||
if(request.isTwoWay()){
|
||||
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
|
||||
Response response = new Response(request.getId(), request.getVersion());
|
||||
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
|
||||
response.setErrorMessage(msg);
|
||||
channel.send(response);
|
||||
return;
|
||||
}
|
||||
sendFeedback(channel, (Request) message, t);
|
||||
return;
|
||||
}
|
||||
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import org.apache.dubbo.remoting.ChannelHandler;
|
|||
import org.apache.dubbo.remoting.ExecutionException;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
|
||||
|
|
@ -80,21 +79,13 @@ public class ConnectionOrderedChannelHandler extends WrappedChannelHandler {
|
|||
|
||||
@Override
|
||||
public void received(Channel channel, Object message) throws RemotingException {
|
||||
ExecutorService executor = getExecutorService();
|
||||
ExecutorService executor = getPreferredExecutorService(message);
|
||||
try {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
} catch (Throwable t) {
|
||||
//fix, reject exception can not be sent to consumer because thread pool is full, resulting in consumers waiting till timeout.
|
||||
if (message instanceof Request && t instanceof RejectedExecutionException) {
|
||||
Request request = (Request) message;
|
||||
if (request.isTwoWay()) {
|
||||
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
|
||||
Response response = new Response(request.getId(), request.getVersion());
|
||||
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
|
||||
response.setErrorMessage(msg);
|
||||
channel.send(response);
|
||||
return;
|
||||
}
|
||||
sendFeedback(channel, (Request) message, t);
|
||||
return;
|
||||
}
|
||||
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.remoting.transport.dispatcher.direct;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.ExecutionException;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class DirectChannelHandler extends WrappedChannelHandler {
|
||||
|
||||
public DirectChannelHandler(ChannelHandler handler, URL url) {
|
||||
super(handler, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Channel channel, Object message) throws RemotingException {
|
||||
ExecutorService executor = getPreferredExecutorService(message);
|
||||
if (executor instanceof ThreadlessExecutor) {
|
||||
try {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
} catch (Throwable t) {
|
||||
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
|
||||
}
|
||||
} else {
|
||||
handler.received(channel, message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ public class DirectDispatcher implements Dispatcher {
|
|||
|
||||
@Override
|
||||
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
|
||||
return handler;
|
||||
return new DirectChannelHandler(handler, url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package org.apache.dubbo.remoting.transport.dispatcher.execution;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.ExecutionException;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
|
||||
|
|
@ -42,7 +42,8 @@ public class ExecutionChannelHandler extends WrappedChannelHandler {
|
|||
|
||||
@Override
|
||||
public void received(Channel channel, Object message) throws RemotingException {
|
||||
ExecutorService executor = getExecutorService();
|
||||
ExecutorService executor = getPreferredExecutorService(message);
|
||||
|
||||
if (message instanceof Request) {
|
||||
try {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
|
|
@ -51,19 +52,12 @@ public class ExecutionChannelHandler extends WrappedChannelHandler {
|
|||
// therefore the consumer side has to wait until gets timeout. This is a temporary solution to prevent
|
||||
// this scenario from happening, but a better solution should be considered later.
|
||||
if (t instanceof RejectedExecutionException) {
|
||||
Request request = (Request) message;
|
||||
if (request.isTwoWay()) {
|
||||
String msg = "Server side(" + url.getIp() + "," + url.getPort()
|
||||
+ ") thread pool is exhausted, detail msg:" + t.getMessage();
|
||||
Response response = new Response(request.getId(), request.getVersion());
|
||||
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
|
||||
response.setErrorMessage(msg);
|
||||
channel.send(response);
|
||||
return;
|
||||
}
|
||||
sendFeedback(channel, (Request) message, t);
|
||||
}
|
||||
throw new ExecutionException(message, channel, getClass() + " error when process received event.", t);
|
||||
}
|
||||
} else if (executor instanceof ThreadlessExecutor) {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
} else {
|
||||
handler.received(channel, message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public class MessageOnlyChannelHandler extends WrappedChannelHandler {
|
|||
|
||||
@Override
|
||||
public void received(Channel channel, Object message) throws RemotingException {
|
||||
ExecutorService executor = getExecutorService();
|
||||
ExecutorService executor = getPreferredExecutorService(message);
|
||||
try {
|
||||
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
|
||||
} catch (Throwable t) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.dubbo.remoting.exchange.Request;
|
|||
import org.apache.dubbo.remoting.handler.MockedChannel;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
|
@ -59,6 +60,7 @@ public class DefaultFutureTest {
|
|||
* start time: 2018-06-21 15:13:02.215, end time: 2018-06-21 15:13:07.231...
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
public void timeoutNotSend() throws Exception {
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter));
|
||||
|
|
@ -89,13 +91,14 @@ public class DefaultFutureTest {
|
|||
* start time: 2018-06-21 15:12:38.337, end time: 2018-06-21 15:12:43.354...
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
public void timeoutSend() throws Exception {
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter));
|
||||
// timeout after 5 seconds.
|
||||
Channel channel = new MockedChannel();
|
||||
Request request = new Request(10);
|
||||
DefaultFuture f = DefaultFuture.newFuture(channel, request, 5000);
|
||||
DefaultFuture f = DefaultFuture.newFuture(channel, request, 5000, null);
|
||||
//mark the future is sent
|
||||
DefaultFuture.sent(channel, request);
|
||||
while (!f.isDone()) {
|
||||
|
|
@ -119,7 +122,7 @@ public class DefaultFutureTest {
|
|||
private DefaultFuture defaultFuture(int timeout) {
|
||||
Channel channel = new MockedChannel();
|
||||
Request request = new Request(index.getAndIncrement());
|
||||
return DefaultFuture.newFuture(channel, request, timeout);
|
||||
return DefaultFuture.newFuture(channel, request, timeout, null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,23 +17,21 @@
|
|||
package org.apache.dubbo.remoting.exchange.support.header;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class HeaderExchangeChannelTest {
|
||||
|
|
@ -193,7 +191,7 @@ public class HeaderExchangeChannelTest {
|
|||
public void closeWithTimeoutTest02() {
|
||||
Assertions.assertFalse(channel.isClosed());
|
||||
Request request = new Request();
|
||||
DefaultFuture.newFuture(channel, request, 100);
|
||||
DefaultFuture.newFuture(channel, request, 100, null);
|
||||
header.close(100);
|
||||
//return directly
|
||||
header.close(1000);
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
|
|||
handler.disconnected(new MockedChannel());
|
||||
Assertions.assertTrue(executor.getActiveCount() <= 1, executor.getActiveCount() + " must <=1");
|
||||
}
|
||||
//queue.size
|
||||
//queue.size
|
||||
Assertions.assertEquals(taskCount - 1, executor.getQueue().size());
|
||||
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
|
|
@ -107,6 +107,7 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Disabled("FIXME")
|
||||
public void test_Received_InvokeInExecuter() throws RemotingException {
|
||||
Assertions.assertThrows(ExecutionException.class, () -> {
|
||||
handler = new ConnectionOrderedChannelHandler(new BizChannelHander(false), url);
|
||||
|
|
@ -142,4 +143,4 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
|
|||
}, req);
|
||||
Assertions.assertEquals(1, count.get(), "channel.send must be invoke");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
package org.apache.dubbo.rpc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -49,7 +52,7 @@ public class AppResponse extends AbstractResult implements Serializable {
|
|||
|
||||
private Throwable exception;
|
||||
|
||||
private Map<String, String> attachments = new HashMap<String, String>();
|
||||
private Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
|
||||
public AppResponse() {
|
||||
}
|
||||
|
|
@ -113,7 +116,7 @@ public class AppResponse extends AbstractResult implements Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
|
|
@ -122,38 +125,35 @@ public class AppResponse extends AbstractResult implements Serializable {
|
|||
*
|
||||
* @param map contains all key-value pairs to append
|
||||
*/
|
||||
@Override
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
this.attachments = map == null ? new HashMap<String, String>() : map;
|
||||
public void setAttachments(Map<String, Object> map) {
|
||||
this.attachments = map == null ? new HashMap<String, Object>() : map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
public void addAttachments(Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
if (this.attachments == null) {
|
||||
this.attachments = new HashMap<String, String>();
|
||||
this.attachments = new HashMap<String, Object>();
|
||||
}
|
||||
this.attachments.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return attachments.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
String result = attachments.get(key);
|
||||
if (result == null || result.length() == 0) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
Object result = attachments.get(key);
|
||||
if (result == null) {
|
||||
result = defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
public void setAttachment(String key, Object value) {
|
||||
attachments.put(key, value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class AsyncRpcResult extends AbstractResult {
|
|||
*/
|
||||
private RpcContext storedContext;
|
||||
private RpcContext storedServerContext;
|
||||
private Executor executor;
|
||||
|
||||
private Invocation invocation;
|
||||
|
||||
|
|
@ -136,6 +137,30 @@ public class AsyncRpcResult extends AbstractResult {
|
|||
return new AppResponse();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method will always return after a maximum 'timeout' waiting:
|
||||
* 1. if value returns before timeout, return normally.
|
||||
* 2. if no value returns after timeout, throw TimeoutException.
|
||||
*
|
||||
* @return
|
||||
* @throws InterruptedException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Override
|
||||
public Result get() throws InterruptedException, ExecutionException {
|
||||
if (executor != null) {
|
||||
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
|
||||
threadlessExecutor.waitAndDrain();
|
||||
}
|
||||
return super.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return this.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object recreate() throws Throwable {
|
||||
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
|
||||
|
|
@ -172,32 +197,32 @@ public class AsyncRpcResult extends AbstractResult {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return getAppResponse().getAttachments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
public void setAttachments(Map<String, Object> map) {
|
||||
getAppResponse().setAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
public void addAttachments(Map<String, Object> map) {
|
||||
getAppResponse().addAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return getAppResponse().getAttachment(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return getAppResponse().getAttachment(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
public void setAttachment(String key, Object value) {
|
||||
getAppResponse().setAttachment(key, value);
|
||||
}
|
||||
|
||||
|
|
@ -213,6 +238,14 @@ public class AsyncRpcResult extends AbstractResult {
|
|||
return invocation;
|
||||
}
|
||||
|
||||
public Executor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* tmp context to use when the thread switch to Dubbo thread.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,90 +1,95 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Invocation. (API, Prototype, NonThreadSafe)
|
||||
*
|
||||
* @serial Don't change the class name and package name.
|
||||
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
|
||||
* @see org.apache.dubbo.rpc.RpcInvocation
|
||||
*/
|
||||
public interface Invocation {
|
||||
|
||||
/**
|
||||
* get method name.
|
||||
*
|
||||
* @return method name.
|
||||
* @serial
|
||||
*/
|
||||
String getMethodName();
|
||||
|
||||
/**
|
||||
* get parameter types.
|
||||
*
|
||||
* @return parameter types.
|
||||
* @serial
|
||||
*/
|
||||
Class<?>[] getParameterTypes();
|
||||
|
||||
/**
|
||||
* get arguments.
|
||||
*
|
||||
* @return arguments.
|
||||
* @serial
|
||||
*/
|
||||
Object[] getArguments();
|
||||
|
||||
/**
|
||||
* get attachments.
|
||||
*
|
||||
* @return attachments.
|
||||
* @serial
|
||||
*/
|
||||
Map<String, String> getAttachments();
|
||||
|
||||
void setAttachment(String key, String value);
|
||||
|
||||
void setAttachmentIfAbsent(String key, String value);
|
||||
|
||||
/**
|
||||
* get attachment by key.
|
||||
*
|
||||
* @return attachment value.
|
||||
* @serial
|
||||
*/
|
||||
String getAttachment(String key);
|
||||
|
||||
/**
|
||||
* get attachment by key with default value.
|
||||
*
|
||||
* @return attachment value.
|
||||
* @serial
|
||||
*/
|
||||
String getAttachment(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* get the invoker in current context.
|
||||
*
|
||||
* @return invoker.
|
||||
* @transient
|
||||
*/
|
||||
Invoker<?> getInvoker();
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Invocation. (API, Prototype, NonThreadSafe)
|
||||
*
|
||||
* @serial Don't change the class name and package name.
|
||||
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
|
||||
* @see org.apache.dubbo.rpc.RpcInvocation
|
||||
*/
|
||||
public interface Invocation {
|
||||
|
||||
/**
|
||||
* get method name.
|
||||
*
|
||||
* @return method name.
|
||||
* @serial
|
||||
*/
|
||||
String getMethodName();
|
||||
|
||||
/**
|
||||
* get parameter types.
|
||||
*
|
||||
* @return parameter types.
|
||||
* @serial
|
||||
*/
|
||||
Class<?>[] getParameterTypes();
|
||||
|
||||
/**
|
||||
* get arguments.
|
||||
*
|
||||
* @return arguments.
|
||||
* @serial
|
||||
*/
|
||||
Object[] getArguments();
|
||||
|
||||
/**
|
||||
* get attachments.
|
||||
*
|
||||
* @return attachments.
|
||||
* @serial
|
||||
*/
|
||||
Map<String, Object> getAttachments();
|
||||
|
||||
void setAttachment(String key, Object value);
|
||||
|
||||
void setAttachmentIfAbsent(String key, Object value);
|
||||
|
||||
/**
|
||||
* get attachment by key.
|
||||
*
|
||||
* @return attachment value.
|
||||
* @serial
|
||||
*/
|
||||
Object getAttachment(String key);
|
||||
|
||||
/**
|
||||
* get attachment by key with default value.
|
||||
*
|
||||
* @return attachment value.
|
||||
* @serial
|
||||
*/
|
||||
Object getAttachment(String key, Object defaultValue);
|
||||
|
||||
/**
|
||||
* get the invoker in current context.
|
||||
*
|
||||
* @return invoker.
|
||||
* @transient
|
||||
*/
|
||||
Invoker<?> getInvoker();
|
||||
|
||||
Object put(Object key, Object value);
|
||||
|
||||
Object get(Object key);
|
||||
|
||||
Map<Object, Object> getAttributes();
|
||||
}
|
||||
|
|
@ -18,6 +18,6 @@ package org.apache.dubbo.rpc;
|
|||
|
||||
public enum InvokeMode {
|
||||
|
||||
SYNC, ASYNC, FUTURE
|
||||
SYNC, ASYNC, FUTURE;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,37 +86,37 @@ public interface Result extends CompletionStage<Result>, Future<Result>, Seriali
|
|||
*
|
||||
* @return attachments.
|
||||
*/
|
||||
Map<String, String> getAttachments();
|
||||
Map<String, Object> getAttachments();
|
||||
|
||||
/**
|
||||
* Add the specified map to existing attachments in this instance.
|
||||
*
|
||||
* @param map
|
||||
*/
|
||||
void addAttachments(Map<String, String> map);
|
||||
void addAttachments(Map<String, Object> map);
|
||||
|
||||
/**
|
||||
* Replace the existing attachments with the specified param.
|
||||
*
|
||||
* @param map
|
||||
*/
|
||||
void setAttachments(Map<String, String> map);
|
||||
void setAttachments(Map<String, Object> map);
|
||||
|
||||
/**
|
||||
* get attachment by key.
|
||||
*
|
||||
* @return attachment value.
|
||||
*/
|
||||
String getAttachment(String key);
|
||||
Object getAttachment(String key);
|
||||
|
||||
/**
|
||||
* get attachment by key with default value.
|
||||
*
|
||||
* @return attachment value.
|
||||
*/
|
||||
String getAttachment(String key, String defaultValue);
|
||||
Object getAttachment(String key, Object defaultValue);
|
||||
|
||||
void setAttachment(String key, String value);
|
||||
void setAttachment(String key, Object value);
|
||||
|
||||
/**
|
||||
* Returns the specified {@code valueIfAbsent} when not complete, or
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class RpcContext {
|
|||
}
|
||||
};
|
||||
|
||||
private final Map<String, String> attachments = new HashMap<String, String>();
|
||||
private final Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
private final Map<String, Object> values = new HashMap<String, Object>();
|
||||
|
||||
private List<URL> urls;
|
||||
|
|
@ -105,7 +105,6 @@ public class RpcContext {
|
|||
private Object response;
|
||||
private AsyncContext asyncContext;
|
||||
|
||||
|
||||
protected RpcContext() {
|
||||
}
|
||||
|
||||
|
|
@ -467,7 +466,7 @@ public class RpcContext {
|
|||
* @param key
|
||||
* @return attachment
|
||||
*/
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
return attachments.get(key);
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +477,7 @@ public class RpcContext {
|
|||
* @param value
|
||||
* @return context
|
||||
*/
|
||||
public RpcContext setAttachment(String key, String value) {
|
||||
public RpcContext setAttachment(String key, Object value) {
|
||||
if (value == null) {
|
||||
attachments.remove(key);
|
||||
} else {
|
||||
|
|
@ -503,7 +502,7 @@ public class RpcContext {
|
|||
*
|
||||
* @return attachments
|
||||
*/
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +512,7 @@ public class RpcContext {
|
|||
* @param attachment
|
||||
* @return context
|
||||
*/
|
||||
public RpcContext setAttachments(Map<String, String> attachment) {
|
||||
public RpcContext setAttachments(Map<String, Object> attachment) {
|
||||
this.attachments.clear();
|
||||
if (attachment != null && attachment.size() > 0) {
|
||||
this.attachments.putAll(attachment);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.apache.dubbo.rpc;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
|
@ -48,7 +47,9 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
|
||||
private Object[] arguments;
|
||||
|
||||
private Map<String, String> attachments;
|
||||
private Map<String, Object> attachments;
|
||||
|
||||
private Map<Object, Object> attributes = new HashMap<Object, Object>();
|
||||
|
||||
private transient Invoker<?> invoker;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
|
||||
public RpcInvocation(Invocation invocation, Invoker<?> invoker) {
|
||||
this(invocation.getMethodName(), invocation.getParameterTypes(),
|
||||
invocation.getArguments(), new HashMap<String, String>(invocation.getAttachments()),
|
||||
invocation.getArguments(), new HashMap<String, Object>(invocation.getAttachments()),
|
||||
invocation.getInvoker());
|
||||
if (invoker != null) {
|
||||
URL url = invoker.getUrl();
|
||||
|
|
@ -96,24 +97,25 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
this(method, arguments, null);
|
||||
}
|
||||
|
||||
public RpcInvocation(Method method, Object[] arguments, Map<String, String> attachment) {
|
||||
public RpcInvocation(Method method, Object[] arguments, Map<String, Object> attachment, Map<Object, Object> attributes) {
|
||||
this(method.getName(), method.getParameterTypes(), arguments, attachment, null);
|
||||
this.returnType = method.getReturnType();
|
||||
this.attributes = attributes == null ? new HashMap<>() : attributes;
|
||||
}
|
||||
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) {
|
||||
this(methodName, parameterTypes, arguments, null, null);
|
||||
}
|
||||
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments) {
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, Object> attachments) {
|
||||
this(methodName, parameterTypes, arguments, attachments, null);
|
||||
}
|
||||
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments, Invoker<?> invoker) {
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, Object> attachments, Invoker<?> invoker) {
|
||||
this.methodName = methodName;
|
||||
this.parameterTypes = parameterTypes == null ? new Class<?>[0] : parameterTypes;
|
||||
this.arguments = arguments == null ? new Object[0] : arguments;
|
||||
this.attachments = attachments == null ? new HashMap<String, String>() : attachments;
|
||||
this.attachments = attachments == null ? new HashMap<String, Object>() : attachments;
|
||||
this.invoker = invoker;
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +128,19 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
this.invoker = invoker;
|
||||
}
|
||||
|
||||
public Object put(Object key, Object value) {
|
||||
return attributes.put(key, value);
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
return attributes.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
|
|
@ -154,53 +169,53 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
public Map<String, Object> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public void setAttachments(Map<String, String> attachments) {
|
||||
this.attachments = attachments == null ? new HashMap<String, String>() : attachments;
|
||||
public void setAttachments(Map<String, Object> attachments) {
|
||||
this.attachments = attachments == null ? new HashMap<String, Object>() : attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
public void setAttachment(String key, Object value) {
|
||||
if (attachments == null) {
|
||||
attachments = new HashMap<String, String>();
|
||||
attachments = new HashMap<String, Object>();
|
||||
}
|
||||
attachments.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
public void setAttachmentIfAbsent(String key, Object value) {
|
||||
if (attachments == null) {
|
||||
attachments = new HashMap<String, String>();
|
||||
attachments = new HashMap<String, Object>();
|
||||
}
|
||||
if (!attachments.containsKey(key)) {
|
||||
attachments.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void addAttachments(Map<String, String> attachments) {
|
||||
public void addAttachments(Map<String, Object> attachments) {
|
||||
if (attachments == null) {
|
||||
return;
|
||||
}
|
||||
if (this.attachments == null) {
|
||||
this.attachments = new HashMap<String, String>();
|
||||
this.attachments = new HashMap<String, Object>();
|
||||
}
|
||||
this.attachments.putAll(attachments);
|
||||
}
|
||||
|
||||
public void addAttachmentsIfAbsent(Map<String, String> attachments) {
|
||||
public void addAttachmentsIfAbsent(Map<String, Object> attachments) {
|
||||
if (attachments == null) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, String> entry : attachments.entrySet()) {
|
||||
for (Map.Entry<String, Object> entry : attachments.entrySet()) {
|
||||
setAttachmentIfAbsent(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
public Object getAttachment(String key) {
|
||||
if (attachments == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -208,12 +223,12 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
if (attachments == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
String value = attachments.get(key);
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
Object value = attachments.get(key);
|
||||
if (null == value) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
@SPI
|
||||
public interface ApplicationInitListener {
|
||||
/**
|
||||
* init the application
|
||||
*/
|
||||
void init();
|
||||
}
|
||||
|
|
@ -16,20 +16,23 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.model;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Represent a application which is using Dubbo and store basic metadata info for using
|
||||
* during the processing of RPC invoking.
|
||||
*
|
||||
* <p>
|
||||
* ApplicationModel includes many ProviderModel which is about published services
|
||||
* and many Consumer Model which is about subscribed services.
|
||||
*
|
||||
* <p>
|
||||
* adjust project structure in order to fully utilize the methods introduced here.
|
||||
*/
|
||||
public class ApplicationModel {
|
||||
|
|
@ -47,6 +50,8 @@ public class ApplicationModel {
|
|||
|
||||
private static String application;
|
||||
|
||||
private static AtomicBoolean INIT_FLAG = new AtomicBoolean(false);
|
||||
|
||||
public static Collection<ConsumerModel> allConsumerModels() {
|
||||
return CONSUMED_SERVICES.values();
|
||||
}
|
||||
|
|
@ -63,6 +68,16 @@ public class ApplicationModel {
|
|||
return CONSUMED_SERVICES.get(serviceName);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (INIT_FLAG.compareAndSet(false, true)) {
|
||||
ExtensionLoader<ApplicationInitListener> extensionLoader = ExtensionLoader.getExtensionLoader(ApplicationInitListener.class);
|
||||
Set<String> listenerNames = extensionLoader.getSupportedExtensions();
|
||||
for (String listenerName : listenerNames) {
|
||||
extensionLoader.getExtension(listenerName).init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void initConsumerModel(String serviceName, ConsumerModel consumerModel) {
|
||||
if (CONSUMED_SERVICES.putIfAbsent(serviceName, consumerModel) != null) {
|
||||
LOGGER.warn("Already register the same consumer:" + serviceName);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ package org.apache.dubbo.rpc.model;
|
|||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.$INVOKE;
|
||||
|
||||
|
|
@ -32,10 +33,9 @@ public class ConsumerMethodModel {
|
|||
private final String methodName;
|
||||
private final boolean generic;
|
||||
|
||||
private final AsyncMethodInfo asyncInfo;
|
||||
private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public ConsumerMethodModel(Method method, Map<String, Object> attributes) {
|
||||
public ConsumerMethodModel(Method method) {
|
||||
this.method = method;
|
||||
this.parameterClasses = method.getParameterTypes();
|
||||
this.returnClass = method.getReturnType();
|
||||
|
|
@ -43,24 +43,32 @@ public class ConsumerMethodModel {
|
|||
this.methodName = method.getName();
|
||||
this.generic = methodName.equals($INVOKE) && parameterTypes != null && parameterTypes.length == 3;
|
||||
|
||||
if (attributes != null) {
|
||||
asyncInfo = (AsyncMethodInfo) attributes.get(methodName);
|
||||
} else {
|
||||
asyncInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
// public ConcurrentMap<String, Object> getAttributeMap() {
|
||||
// return attributeMap;
|
||||
// }
|
||||
|
||||
public void addAttribute(String key, Object value) {
|
||||
this.attributeMap.put(key, value);
|
||||
}
|
||||
|
||||
public Object getAttribute(String key) {
|
||||
return this.attributeMap.get(key);
|
||||
}
|
||||
|
||||
|
||||
public Class<?> getReturnClass() {
|
||||
return returnClass;
|
||||
}
|
||||
|
||||
public AsyncMethodInfo getAsyncInfo() {
|
||||
return asyncInfo;
|
||||
}
|
||||
// public AsyncMethodInfo getAsyncInfo() {
|
||||
// return (AsyncMethodInfo) attributeMap.get(Constants.ASYNC_KEY);
|
||||
// }
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
|
|
|
|||
|
|
@ -16,10 +16,9 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.model;
|
||||
|
||||
import org.apache.dubbo.common.utils.Assert;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -29,47 +28,31 @@ import java.util.Optional;
|
|||
* Consumer Model which is about subscribed services.
|
||||
*/
|
||||
public class ConsumerModel {
|
||||
private final Object proxyObject;
|
||||
private final String serviceName;
|
||||
private final Class<?> serviceInterfaceClass;
|
||||
|
||||
private final ServiceMetadata serviceMetadata;
|
||||
private final Map<Method, ConsumerMethodModel> methodModels = new IdentityHashMap<Method, ConsumerMethodModel>();
|
||||
|
||||
/**
|
||||
* This constructor create an instance of ConsumerModel and passed objects should not be null.
|
||||
* If service name, service instance, proxy object,methods should not be null. If these are null
|
||||
* then this constructor will throw {@link IllegalArgumentException}
|
||||
* @param serviceName Name of the service.
|
||||
* @param serviceInterfaceClass Service interface class.
|
||||
* @param proxyObject Proxy object.
|
||||
* @param methods Methods of service class
|
||||
* @param attributes Attributes of methods.
|
||||
*/
|
||||
public ConsumerModel(String serviceName
|
||||
, Class<?> serviceInterfaceClass
|
||||
, Object proxyObject
|
||||
, Method[] methods
|
||||
, Map<String, Object> attributes) {
|
||||
public ConsumerModel(String serviceName, String group, String version, Class<?> interfaceClass) {
|
||||
this.serviceMetadata = new ServiceMetadata(serviceName, group, version, interfaceClass);
|
||||
|
||||
Assert.notEmptyString(serviceName, "Service name can't be null or blank");
|
||||
Assert.notNull(serviceInterfaceClass, "Service interface class can't null");
|
||||
Assert.notNull(proxyObject, "Proxy object can't be null");
|
||||
Assert.notNull(methods, "Methods can't be null");
|
||||
|
||||
this.serviceName = serviceName;
|
||||
this.serviceInterfaceClass = serviceInterfaceClass;
|
||||
this.proxyObject = proxyObject;
|
||||
Method[] methods = interfaceClass.getMethods();
|
||||
for (Method method : methods) {
|
||||
methodModels.put(method, new ConsumerMethodModel(method, attributes));
|
||||
methodModels.put(method, new ConsumerMethodModel(method));
|
||||
}
|
||||
}
|
||||
|
||||
public ConsumerModel(ServiceMetadata serviceMetadata) {
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
Method[] methods = serviceMetadata.getServiceType().getMethods();
|
||||
for (Method method : methods) {
|
||||
methodModels.put(method, new ConsumerMethodModel(method));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the proxy object used by called while creating instance of ConsumerModel
|
||||
* @return
|
||||
* @return serviceMetadata
|
||||
*/
|
||||
public Object getProxyObject() {
|
||||
return proxyObject;
|
||||
public ServiceMetadata getServiceMetadata() {
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -93,6 +76,27 @@ public class ConsumerModel {
|
|||
return consumerMethodModelEntry.map(Map.Entry::getValue).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param method metodName
|
||||
* @param argsType method arguments type
|
||||
* @return
|
||||
*/
|
||||
public ConsumerMethodModel getMethodModel(String method, String[] argsType) {
|
||||
Optional<ConsumerMethodModel> consumerMethodModel = methodModels.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().getName().equals(method))
|
||||
.map(Map.Entry::getValue).filter(methodModel -> Arrays.equals(argsType, methodModel.getParameterTypes()))
|
||||
.findFirst();
|
||||
return consumerMethodModel.orElse(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getServiceInterfaceClass() {
|
||||
return serviceMetadata.getServiceType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all method models for the current service
|
||||
*
|
||||
|
|
@ -102,11 +106,7 @@ public class ConsumerModel {
|
|||
return new ArrayList<ConsumerMethodModel>(methodModels.values());
|
||||
}
|
||||
|
||||
public Class<?> getServiceInterfaceClass() {
|
||||
return serviceInterfaceClass;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
return this.serviceMetadata.getServiceKey();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,24 @@
|
|||
package org.apache.dubbo.rpc.model;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class ProviderMethodModel {
|
||||
private transient final Method method;
|
||||
private final Method method;
|
||||
private final String methodName;
|
||||
private final Class<?>[] parameterClasses;
|
||||
private final String[] methodArgTypes;
|
||||
private final String serviceName;
|
||||
private final Type[] genericParameterTypes;
|
||||
private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public ProviderMethodModel(Method method, String serviceName) {
|
||||
public ProviderMethodModel(Method method) {
|
||||
this.method = method;
|
||||
this.serviceName = serviceName;
|
||||
this.methodName = method.getName();
|
||||
this.parameterClasses = method.getParameterTypes();
|
||||
this.methodArgTypes = getArgTypes(method);
|
||||
this.genericParameterTypes = method.getGenericParameterTypes();
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
|
|
@ -44,8 +49,8 @@ public class ProviderMethodModel {
|
|||
return methodArgTypes;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
public ConcurrentMap<String, Object> getAttributeMap() {
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
private static String[] getArgTypes(Method method) {
|
||||
|
|
@ -60,4 +65,12 @@ public class ProviderMethodModel {
|
|||
}
|
||||
return methodArgTypes;
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterClasses() {
|
||||
return parameterClasses;
|
||||
}
|
||||
|
||||
public Type[] getGenericParameterTypes() {
|
||||
return genericParameterTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.model;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -27,30 +28,35 @@ import java.util.Map;
|
|||
* ProviderModel which is about published services
|
||||
*/
|
||||
public class ProviderModel {
|
||||
private final String serviceName;
|
||||
private final Object serviceInstance;
|
||||
private final Class<?> serviceInterfaceClass;
|
||||
private final ServiceMetadata serviceMetadata;
|
||||
private final String serivceKey;
|
||||
private final Map<String, List<ProviderMethodModel>> methods = new HashMap<String, List<ProviderMethodModel>>();
|
||||
|
||||
public ProviderModel(String serviceName, Object serviceInstance, Class<?> serviceInterfaceClass) {
|
||||
public ProviderModel(String serviceName, String group, String version, Object serviceInstance, Class<?> serviceInterfaceClass) {
|
||||
if (null == serviceInstance) {
|
||||
throw new IllegalArgumentException("Service[" + serviceName + "]Target is NULL.");
|
||||
}
|
||||
|
||||
this.serviceName = serviceName;
|
||||
this.serviceInstance = serviceInstance;
|
||||
this.serviceInterfaceClass = serviceInterfaceClass;
|
||||
|
||||
initMethod();
|
||||
this.serviceMetadata = new ServiceMetadata(serviceName, group, version, serviceInterfaceClass);
|
||||
this.serivceKey = serviceMetadata.getServiceKey();
|
||||
initMethod(serviceInterfaceClass);
|
||||
}
|
||||
|
||||
public ProviderModel(Object serviceInstance, ServiceMetadata serviceMetadata) {
|
||||
this.serviceInstance = serviceInstance;
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
this.serivceKey = serviceMetadata.getServiceKey();
|
||||
initMethod(serviceMetadata.getServiceType());
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
return this.serviceMetadata.getServiceKey();
|
||||
}
|
||||
|
||||
public Class<?> getServiceInterfaceClass() {
|
||||
return serviceInterfaceClass;
|
||||
return this.serviceMetadata.getServiceType();
|
||||
}
|
||||
|
||||
public Object getServiceInstance() {
|
||||
|
|
@ -77,20 +83,32 @@ public class ProviderModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void initMethod() {
|
||||
Method[] methodsToExport = null;
|
||||
methodsToExport = this.serviceInterfaceClass.getMethods();
|
||||
public List<ProviderMethodModel> getMethodModelList(String methodName) {
|
||||
List<ProviderMethodModel> resultList = methods.get(methodName);
|
||||
return resultList == null ? Collections.emptyList() : resultList;
|
||||
}
|
||||
|
||||
|
||||
private void initMethod(Class<?> serviceInterfaceClass) {
|
||||
Method[] methodsToExport;
|
||||
methodsToExport = serviceInterfaceClass.getMethods();
|
||||
|
||||
for (Method method : methodsToExport) {
|
||||
method.setAccessible(true);
|
||||
|
||||
List<ProviderMethodModel> methodModels = methods.get(method.getName());
|
||||
if (methodModels == null) {
|
||||
methodModels = new ArrayList<ProviderMethodModel>(1);
|
||||
methodModels = new ArrayList<ProviderMethodModel>();
|
||||
methods.put(method.getName(), methodModels);
|
||||
}
|
||||
methodModels.add(new ProviderMethodModel(method, serviceName));
|
||||
methodModels.add(new ProviderMethodModel(method));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return serviceMetadata
|
||||
*/
|
||||
public ServiceMetadata getServiceMetadata() {
|
||||
return serviceMetadata;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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.model;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* data related to service level such as name, version, classloader of business service,
|
||||
* security info, etc. Also with a AttributeMap for extension.
|
||||
*/
|
||||
public class ServiceMetadata {
|
||||
|
||||
private String serviceKey;
|
||||
private String serviceInterfaceName;
|
||||
private String defaultGroup;
|
||||
private String version;
|
||||
private Class<?> serviceType;
|
||||
|
||||
private volatile String group;
|
||||
|
||||
private Object target;
|
||||
|
||||
/* will be transferred to remote side */
|
||||
private final Map<String, Object> attachments = new ConcurrentHashMap<String, Object>();
|
||||
/* used locally*/
|
||||
private final Map<String, Object> attributeMap = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
public ServiceMetadata(String serviceInterfaceName, String group, String version, Class<?> serviceType) {
|
||||
this.serviceInterfaceName = serviceInterfaceName;
|
||||
this.defaultGroup = group;
|
||||
this.group = group;
|
||||
this.version = version;
|
||||
this.serviceKey = serviceInterfaceName + ":" + version;
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
|
||||
public ServiceMetadata() {
|
||||
}
|
||||
|
||||
public String getServiceKey() {
|
||||
return serviceInterfaceName + ":" + version;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttributeMap() {
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
public Object getAttribute(String key) {
|
||||
return attributeMap.get(key);
|
||||
}
|
||||
|
||||
public void addAttribute(String key, Object value) {
|
||||
this.attributeMap.put(key, value);
|
||||
}
|
||||
|
||||
public void addAttachment(String key, Object value) {
|
||||
this.attributeMap.put(key, value);
|
||||
}
|
||||
|
||||
public Class<?> getServiceType() {
|
||||
return serviceType;
|
||||
}
|
||||
|
||||
public String getServiceInterfaceName() {
|
||||
return serviceInterfaceName;
|
||||
}
|
||||
|
||||
public String getDefaultGroup() {
|
||||
return defaultGroup;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public void setServiceInterfaceName(String serviceInterfaceName) {
|
||||
this.serviceInterfaceName = serviceInterfaceName;
|
||||
}
|
||||
|
||||
public void setDefaultGroup(String defaultGroup) {
|
||||
this.defaultGroup = defaultGroup;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setServiceType(Class<?> serviceType) {
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
|
||||
public void setServiceKey(String serviceKey) {
|
||||
this.serviceKey = serviceKey;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(Object target) {
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,13 +18,18 @@ package org.apache.dubbo.rpc.protocol;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.FutureAdapter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.InvokeMode;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
|
|
@ -36,6 +41,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
|
|
@ -49,21 +55,21 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
|
||||
private final URL url;
|
||||
|
||||
private final Map<String, String> attachment;
|
||||
private final Map<String, Object> attachment;
|
||||
|
||||
private volatile boolean available = true;
|
||||
|
||||
private AtomicBoolean destroyed = new AtomicBoolean(false);
|
||||
|
||||
public AbstractInvoker(Class<T> type, URL url) {
|
||||
this(type, url, (Map<String, String>) null);
|
||||
this(type, url, (Map<String, Object>) null);
|
||||
}
|
||||
|
||||
public AbstractInvoker(Class<T> type, URL url, String[] keys) {
|
||||
this(type, url, convertAttachment(url, keys));
|
||||
}
|
||||
|
||||
public AbstractInvoker(Class<T> type, URL url, Map<String, String> attachment) {
|
||||
public AbstractInvoker(Class<T> type, URL url, Map<String, Object> attachment) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("service type == null");
|
||||
}
|
||||
|
|
@ -75,11 +81,11 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
this.attachment = attachment == null ? null : Collections.unmodifiableMap(attachment);
|
||||
}
|
||||
|
||||
private static Map<String, String> convertAttachment(URL url, String[] keys) {
|
||||
private static Map<String, Object> convertAttachment(URL url, String[] keys) {
|
||||
if (ArrayUtils.isEmpty(keys)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> attachment = new HashMap<String, String>();
|
||||
Map<String, Object> attachment = new HashMap<String, Object>();
|
||||
for (String key : keys) {
|
||||
String value = url.getParameter(key);
|
||||
if (value != null && value.length() > 0) {
|
||||
|
|
@ -137,11 +143,11 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
if (CollectionUtils.isNotEmptyMap(attachment)) {
|
||||
invocation.addAttachmentsIfAbsent(attachment);
|
||||
}
|
||||
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
|
||||
Map<String, Object> contextAttachments = RpcContext.getContext().getAttachments();
|
||||
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
|
||||
/**
|
||||
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
|
||||
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
|
||||
* because the {@link RpcContext#setAttachment(String, Object)} is passed in the Filter when the call is triggered
|
||||
* by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is
|
||||
* a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).
|
||||
*/
|
||||
|
|
@ -151,26 +157,38 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
|
||||
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
|
||||
|
||||
AsyncRpcResult asyncResult;
|
||||
try {
|
||||
return doInvoke(invocation);
|
||||
asyncResult = (AsyncRpcResult) doInvoke(invocation);
|
||||
} catch (InvocationTargetException e) { // biz exception
|
||||
Throwable te = e.getTargetException();
|
||||
if (te == null) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
} else {
|
||||
if (te instanceof RpcException) {
|
||||
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
|
||||
}
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
|
||||
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
if (e.isBiz()) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
}
|
||||
RpcContext.getContext().setFuture(new FutureAdapter(asyncResult, inv));
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
protected ExecutorService getCallbackExecutor(URL url, Invocation inv) {
|
||||
ExecutorService sharedExecutor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().createExecutorIfAbsent(url);
|
||||
if (InvokeMode.SYNC == RpcUtils.getInvokeMode(getUrl(), inv)) {
|
||||
return new ThreadlessExecutor(sharedExecutor);
|
||||
} else {
|
||||
return sharedExecutor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,203 +1,200 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.InvokeMode;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.$INVOKE;
|
||||
import static org.apache.dubbo.rpc.Constants.$INVOKE_ASYNC;
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.ID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
|
||||
/**
|
||||
* RpcUtils
|
||||
*/
|
||||
public class RpcUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RpcUtils.class);
|
||||
private static final AtomicLong INVOKE_ID = new AtomicLong(0);
|
||||
|
||||
public static Class<?> getReturnType(Invocation invocation) {
|
||||
try {
|
||||
if (invocation != null && invocation.getInvoker() != null
|
||||
&& invocation.getInvoker().getUrl() != null
|
||||
&& !invocation.getMethodName().startsWith("$")) {
|
||||
String service = invocation.getInvoker().getUrl().getServiceInterface();
|
||||
if (StringUtils.isNotEmpty(service)) {
|
||||
Class<?> invokerInterface = invocation.getInvoker().getInterface();
|
||||
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
|
||||
: ReflectUtils.forName(service);
|
||||
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
if (method.getReturnType() == void.class) {
|
||||
return null;
|
||||
}
|
||||
return method.getReturnType();
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Type[] getReturnTypes(Invocation invocation) {
|
||||
try {
|
||||
if (invocation != null && invocation.getInvoker() != null
|
||||
&& invocation.getInvoker().getUrl() != null
|
||||
&& !invocation.getMethodName().startsWith("$")) {
|
||||
String service = invocation.getInvoker().getUrl().getServiceInterface();
|
||||
if (StringUtils.isNotEmpty(service)) {
|
||||
Class<?> invokerInterface = invocation.getInvoker().getInterface();
|
||||
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
|
||||
: ReflectUtils.forName(service);
|
||||
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
if (method.getReturnType() == void.class) {
|
||||
return null;
|
||||
}
|
||||
return ReflectUtils.getReturnTypes(method);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Long getInvocationId(Invocation inv) {
|
||||
String id = inv.getAttachment(ID_KEY);
|
||||
return id == null ? null : new Long(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Idempotent operation: invocation id will be added in async operation by default
|
||||
*
|
||||
* @param url
|
||||
* @param inv
|
||||
*/
|
||||
public static void attachInvocationIdIfAsync(URL url, Invocation inv) {
|
||||
if (isAttachInvocationId(url, inv) && getInvocationId(inv) == null && inv instanceof RpcInvocation) {
|
||||
((RpcInvocation) inv).setAttachment(ID_KEY, String.valueOf(INVOKE_ID.getAndIncrement()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAttachInvocationId(URL url, Invocation invocation) {
|
||||
String value = url.getMethodParameter(invocation.getMethodName(), AUTO_ATTACH_INVOCATIONID_KEY);
|
||||
if (value == null) {
|
||||
// add invocationid in async operation by default
|
||||
return isAsync(url, invocation);
|
||||
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMethodName(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 0
|
||||
&& invocation.getArguments()[0] instanceof String) {
|
||||
return (String) invocation.getArguments()[0];
|
||||
}
|
||||
return invocation.getMethodName();
|
||||
}
|
||||
|
||||
public static Object[] getArguments(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 2
|
||||
&& invocation.getArguments()[2] instanceof Object[]) {
|
||||
return (Object[]) invocation.getArguments()[2];
|
||||
}
|
||||
return invocation.getArguments();
|
||||
}
|
||||
|
||||
public static Class<?>[] getParameterTypes(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 1
|
||||
&& invocation.getArguments()[1] instanceof String[]) {
|
||||
String[] types = (String[]) invocation.getArguments()[1];
|
||||
if (types == null) {
|
||||
return new Class<?>[0];
|
||||
}
|
||||
Class<?>[] parameterTypes = new Class<?>[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
parameterTypes[i] = ReflectUtils.forName(types[0]);
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
return invocation.getParameterTypes();
|
||||
}
|
||||
|
||||
public static boolean isAsync(URL url, Invocation inv) {
|
||||
boolean isAsync;
|
||||
if (Boolean.TRUE.toString().equals(inv.getAttachment(ASYNC_KEY))) {
|
||||
isAsync = true;
|
||||
} else {
|
||||
isAsync = url.getMethodParameter(getMethodName(inv), ASYNC_KEY, false);
|
||||
}
|
||||
return isAsync;
|
||||
}
|
||||
|
||||
public static boolean isReturnTypeFuture(Invocation inv) {
|
||||
Class<?> clazz;
|
||||
if (inv instanceof RpcInvocation) {
|
||||
clazz = ((RpcInvocation) inv).getReturnType();
|
||||
} else {
|
||||
clazz = getReturnType(inv);
|
||||
}
|
||||
return (clazz != null && CompletableFuture.class.isAssignableFrom(clazz)) || isGenericAsync(inv);
|
||||
}
|
||||
|
||||
public static InvokeMode getInvokeMode(URL url, Invocation inv) {
|
||||
if (isReturnTypeFuture(inv)) {
|
||||
return InvokeMode.FUTURE;
|
||||
} else if (isAsync(url, inv)) {
|
||||
return InvokeMode.ASYNC;
|
||||
} else {
|
||||
return InvokeMode.SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGenericAsync(Invocation inv) {
|
||||
return $INVOKE_ASYNC.equals(inv.getMethodName());
|
||||
}
|
||||
|
||||
public static boolean isOneway(URL url, Invocation inv) {
|
||||
boolean isOneway;
|
||||
if (Boolean.FALSE.toString().equals(inv.getAttachment(RETURN_KEY))) {
|
||||
isOneway = true;
|
||||
} else {
|
||||
isOneway = !url.getMethodParameter(getMethodName(inv), RETURN_KEY, true);
|
||||
}
|
||||
return isOneway;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.InvokeMode;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.$INVOKE;
|
||||
import static org.apache.dubbo.rpc.Constants.$INVOKE_ASYNC;
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.ID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
|
||||
/**
|
||||
* RpcUtils
|
||||
*/
|
||||
public class RpcUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RpcUtils.class);
|
||||
private static final AtomicLong INVOKE_ID = new AtomicLong(0);
|
||||
|
||||
public static Class<?> getReturnType(Invocation invocation) {
|
||||
try {
|
||||
if (invocation != null && invocation.getInvoker() != null
|
||||
&& invocation.getInvoker().getUrl() != null
|
||||
&& !invocation.getMethodName().startsWith("$")) {
|
||||
String service = invocation.getInvoker().getUrl().getServiceInterface();
|
||||
if (StringUtils.isNotEmpty(service)) {
|
||||
Class<?> invokerInterface = invocation.getInvoker().getInterface();
|
||||
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
|
||||
: ReflectUtils.forName(service);
|
||||
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
if (method.getReturnType() == void.class) {
|
||||
return null;
|
||||
}
|
||||
return method.getReturnType();
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Type[] getReturnTypes(Invocation invocation) {
|
||||
try {
|
||||
if (invocation != null && invocation.getInvoker() != null
|
||||
&& invocation.getInvoker().getUrl() != null
|
||||
&& !invocation.getMethodName().startsWith("$")) {
|
||||
String service = invocation.getInvoker().getUrl().getServiceInterface();
|
||||
if (StringUtils.isNotEmpty(service)) {
|
||||
Class<?> invokerInterface = invocation.getInvoker().getInterface();
|
||||
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
|
||||
: ReflectUtils.forName(service);
|
||||
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
if (method.getReturnType() == void.class) {
|
||||
return null;
|
||||
}
|
||||
return ReflectUtils.getReturnTypes(method);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Long getInvocationId(Invocation inv) {
|
||||
String id = (String)inv.getAttachment(ID_KEY);
|
||||
return id == null ? null : new Long(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Idempotent operation: invocation id will be added in async operation by default
|
||||
*
|
||||
* @param url
|
||||
* @param inv
|
||||
*/
|
||||
public static void attachInvocationIdIfAsync(URL url, Invocation inv) {
|
||||
if (isAttachInvocationId(url, inv) && getInvocationId(inv) == null && inv instanceof RpcInvocation) {
|
||||
((RpcInvocation) inv).setAttachment(ID_KEY, String.valueOf(INVOKE_ID.getAndIncrement()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAttachInvocationId(URL url, Invocation invocation) {
|
||||
String value = url.getMethodParameter(invocation.getMethodName(), AUTO_ATTACH_INVOCATIONID_KEY);
|
||||
if (value == null) {
|
||||
// add invocationid in async operation by default
|
||||
return isAsync(url, invocation);
|
||||
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMethodName(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 0
|
||||
&& invocation.getArguments()[0] instanceof String) {
|
||||
return (String) invocation.getArguments()[0];
|
||||
}
|
||||
return invocation.getMethodName();
|
||||
}
|
||||
|
||||
public static Object[] getArguments(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 2
|
||||
&& invocation.getArguments()[2] instanceof Object[]) {
|
||||
return (Object[]) invocation.getArguments()[2];
|
||||
}
|
||||
return invocation.getArguments();
|
||||
}
|
||||
|
||||
public static Class<?>[] getParameterTypes(Invocation invocation) {
|
||||
if ($INVOKE.equals(invocation.getMethodName())
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length > 1
|
||||
&& invocation.getArguments()[1] instanceof String[]) {
|
||||
String[] types = (String[]) invocation.getArguments()[1];
|
||||
if (types == null) {
|
||||
return new Class<?>[0];
|
||||
}
|
||||
Class<?>[] parameterTypes = new Class<?>[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
parameterTypes[i] = ReflectUtils.forName(types[0]);
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
return invocation.getParameterTypes();
|
||||
}
|
||||
|
||||
public static boolean isAsync(URL url, Invocation inv) {
|
||||
boolean isAsync;
|
||||
if (Boolean.TRUE.toString().equals(inv.getAttachment(ASYNC_KEY))) {
|
||||
isAsync = true;
|
||||
} else {
|
||||
isAsync = url.getMethodParameter(getMethodName(inv), ASYNC_KEY, false);
|
||||
}
|
||||
return isAsync;
|
||||
}
|
||||
|
||||
public static boolean isReturnTypeFuture(Invocation inv) {
|
||||
Class<?> clazz = getReturnType(inv);
|
||||
return (clazz != null && CompletableFuture.class.isAssignableFrom(clazz)) || isGenericAsync(inv);
|
||||
}
|
||||
|
||||
public static boolean isGenericAsync(Invocation inv) {
|
||||
return $INVOKE_ASYNC.equals(inv.getMethodName());
|
||||
public static InvokeMode getInvokeMode(URL url, Invocation inv) {
|
||||
if (isReturnTypeFuture(inv)) {
|
||||
return InvokeMode.FUTURE;
|
||||
} else if (isAsync(url, inv)) {
|
||||
return InvokeMode.ASYNC;
|
||||
} else {
|
||||
return InvokeMode.SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGenericAsync(Invocation inv) {
|
||||
return Constants.$INVOKE_ASYNC.equals(inv.getMethodName());
|
||||
}
|
||||
|
||||
public static boolean isOneway(URL url, Invocation inv) {
|
||||
boolean isOneway;
|
||||
if (Boolean.FALSE.toString().equals(inv.getAttachment(RETURN_KEY))) {
|
||||
isOneway = true;
|
||||
} else {
|
||||
isOneway = !url.getMethodParameter(getMethodName(inv), RETURN_KEY, true);
|
||||
}
|
||||
return isOneway;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class RpcContextTest {
|
|||
public void testAttachments() {
|
||||
|
||||
RpcContext context = RpcContext.getContext();
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("_11", "1111");
|
||||
map.put("_22", "2222");
|
||||
map.put(".33", "3333");
|
||||
|
|
|
|||
|
|
@ -1,82 +1,97 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* MockInvocation.java
|
||||
*/
|
||||
public class MockInvocation implements Invocation {
|
||||
|
||||
public String getMethodName() {
|
||||
return "echo";
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return new Class[]{String.class};
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return new Object[]{"aa"};
|
||||
}
|
||||
|
||||
public Map<String, String> getAttachments() {
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
|
||||
attachments.put(TOKEN_KEY, "sfag");
|
||||
attachments.put(TIMEOUT_KEY, "1000");
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* MockInvocation.java
|
||||
*/
|
||||
public class MockInvocation implements Invocation {
|
||||
|
||||
public String getMethodName() {
|
||||
return "echo";
|
||||
}
|
||||
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return new Class[]{String.class};
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return new Object[]{"aa"};
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttachments() {
|
||||
Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
attachments.put(PATH_KEY, "dubbo");
|
||||
attachments.put(GROUP_KEY, "dubbo");
|
||||
attachments.put(VERSION_KEY, "1.0.0");
|
||||
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
|
||||
attachments.put(TOKEN_KEY, "sfag");
|
||||
attachments.put(TIMEOUT_KEY, "1000");
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getAttachment(String key) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
public Object getAttachment(String key, Object defaultValue) {
|
||||
return getAttachments().get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,152 +1,152 @@
|
|||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
|
||||
public class RpcUtilsTest {
|
||||
|
||||
/**
|
||||
* regular scenario: async invocation in URL
|
||||
* verify: 1. whether invocationId is set correctly, 2. idempotent or not
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_normal() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
attachments.put("aa", "bb");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{}, attachments);
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
long id1 = RpcUtils.getInvocationId(inv);
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
long id2 = RpcUtils.getInvocationId(inv);
|
||||
assertEquals(id1, id2); // verify if it's idempotent
|
||||
assertTrue(id1 >= 0);
|
||||
assertEquals("bb", attachments.get("aa"));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: sync invocation, no attachment added by default
|
||||
* verify: no id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_sync() {
|
||||
URL url = URL.valueOf("dubbo://localhost/");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: async invocation, add attachment by default
|
||||
* verify: no error report when the original attachment is null
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_nullAttachments() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertTrue(RpcUtils.getInvocationId(inv) >= 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: explicitly configure to not add attachment
|
||||
* verify: no id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_forceNotAttache() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true&" + AUTO_ATTACH_INVOCATIONID_KEY + "=false");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: explicitly configure to add attachment
|
||||
* verify: id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_forceAttache() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?" + AUTO_ATTACH_INVOCATIONID_KEY + "=true");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNotNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReturnTypes() throws Exception {
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
given(invoker.getUrl()).willReturn(URL.valueOf("test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
|
||||
Invocation inv = new RpcInvocation("testReturnType", new Class<?>[]{String.class}, null, null, invoker);
|
||||
|
||||
java.lang.reflect.Type[] types = RpcUtils.getReturnTypes(inv);
|
||||
Assertions.assertEquals(2, types.length);
|
||||
Assertions.assertEquals(String.class, types[0]);
|
||||
Assertions.assertEquals(String.class, types[1]);
|
||||
|
||||
Invocation inv1 = new RpcInvocation("testReturnType1", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
|
||||
Assertions.assertEquals(2, types1.length);
|
||||
Assertions.assertEquals(List.class, types1[0]);
|
||||
Assertions.assertEquals(DemoService.class.getMethod("testReturnType1", new Class<?>[]{String.class}).getGenericReturnType(), types1[1]);
|
||||
|
||||
Invocation inv2 = new RpcInvocation("testReturnType2", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
|
||||
Assertions.assertEquals(2, types2.length);
|
||||
Assertions.assertEquals(String.class, types2[0]);
|
||||
Assertions.assertEquals(String.class, types2[1]);
|
||||
|
||||
Invocation inv3 = new RpcInvocation("testReturnType3", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
|
||||
Assertions.assertEquals(2, types3.length);
|
||||
Assertions.assertEquals(List.class, types3[0]);
|
||||
java.lang.reflect.Type genericReturnType3 = DemoService.class.getMethod("testReturnType3", new Class<?>[]{String.class}).getGenericReturnType();
|
||||
Assertions.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]);
|
||||
|
||||
Invocation inv4 = new RpcInvocation("testReturnType4", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
|
||||
Assertions.assertEquals(2, types4.length);
|
||||
Assertions.assertNull(types4[0]);
|
||||
Assertions.assertNull(types4[1]);
|
||||
|
||||
Invocation inv5 = new RpcInvocation("testReturnType5", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
|
||||
Assertions.assertEquals(2, types5.length);
|
||||
Assertions.assertEquals(Map.class, types5[0]);
|
||||
java.lang.reflect.Type genericReturnType5 = DemoService.class.getMethod("testReturnType5", new Class<?>[]{String.class}).getGenericReturnType();
|
||||
Assertions.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
|
||||
public class RpcUtilsTest {
|
||||
|
||||
/**
|
||||
* regular scenario: async invocation in URL
|
||||
* verify: 1. whether invocationId is set correctly, 2. idempotent or not
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_normal() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
|
||||
Map<String, Object> attachments = new HashMap<String, Object>();
|
||||
attachments.put("aa", "bb");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{}, attachments);
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
long id1 = RpcUtils.getInvocationId(inv);
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
long id2 = RpcUtils.getInvocationId(inv);
|
||||
assertEquals(id1, id2); // verify if it's idempotent
|
||||
assertTrue(id1 >= 0);
|
||||
assertEquals("bb", attachments.get("aa"));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: sync invocation, no attachment added by default
|
||||
* verify: no id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_sync() {
|
||||
URL url = URL.valueOf("dubbo://localhost/");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: async invocation, add attachment by default
|
||||
* verify: no error report when the original attachment is null
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_nullAttachments() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertTrue(RpcUtils.getInvocationId(inv) >= 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: explicitly configure to not add attachment
|
||||
* verify: no id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_forceNotAttache() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?test.async=true&" + AUTO_ATTACH_INVOCATIONID_KEY + "=false");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
/**
|
||||
* scenario: explicitly configure to add attachment
|
||||
* verify: id attribute added in attachment
|
||||
*/
|
||||
@Test
|
||||
public void testAttachInvocationIdIfAsync_forceAttache() {
|
||||
URL url = URL.valueOf("dubbo://localhost/?" + AUTO_ATTACH_INVOCATIONID_KEY + "=true");
|
||||
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
|
||||
RpcUtils.attachInvocationIdIfAsync(url, inv);
|
||||
assertNotNull(RpcUtils.getInvocationId(inv));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReturnTypes() throws Exception {
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
given(invoker.getUrl()).willReturn(URL.valueOf("test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
|
||||
Invocation inv = new RpcInvocation("testReturnType", new Class<?>[]{String.class}, null, null, invoker);
|
||||
|
||||
java.lang.reflect.Type[] types = RpcUtils.getReturnTypes(inv);
|
||||
Assertions.assertEquals(2, types.length);
|
||||
Assertions.assertEquals(String.class, types[0]);
|
||||
Assertions.assertEquals(String.class, types[1]);
|
||||
|
||||
Invocation inv1 = new RpcInvocation("testReturnType1", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
|
||||
Assertions.assertEquals(2, types1.length);
|
||||
Assertions.assertEquals(List.class, types1[0]);
|
||||
Assertions.assertEquals(DemoService.class.getMethod("testReturnType1", new Class<?>[]{String.class}).getGenericReturnType(), types1[1]);
|
||||
|
||||
Invocation inv2 = new RpcInvocation("testReturnType2", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
|
||||
Assertions.assertEquals(2, types2.length);
|
||||
Assertions.assertEquals(String.class, types2[0]);
|
||||
Assertions.assertEquals(String.class, types2[1]);
|
||||
|
||||
Invocation inv3 = new RpcInvocation("testReturnType3", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
|
||||
Assertions.assertEquals(2, types3.length);
|
||||
Assertions.assertEquals(List.class, types3[0]);
|
||||
java.lang.reflect.Type genericReturnType3 = DemoService.class.getMethod("testReturnType3", new Class<?>[]{String.class}).getGenericReturnType();
|
||||
Assertions.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]);
|
||||
|
||||
Invocation inv4 = new RpcInvocation("testReturnType4", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
|
||||
Assertions.assertEquals(2, types4.length);
|
||||
Assertions.assertNull(types4[0]);
|
||||
Assertions.assertNull(types4[1]);
|
||||
|
||||
Invocation inv5 = new RpcInvocation("testReturnType5", new Class<?>[]{String.class}, null, null, invoker);
|
||||
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
|
||||
Assertions.assertEquals(2, types5.length);
|
||||
Assertions.assertEquals(Map.class, types5[0]);
|
||||
java.lang.reflect.Type genericReturnType5 = DemoService.class.getMethod("testReturnType5", new Class<?>[]{String.class}).getGenericReturnType();
|
||||
Assertions.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,14 +288,14 @@ class CallbackServiceCodec {
|
|||
switch (callbackstatus) {
|
||||
case CallbackServiceCodec.CALLBACK_CREATE:
|
||||
try {
|
||||
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true);
|
||||
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt((String) inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
throw new IOException(StringUtils.toString(e));
|
||||
}
|
||||
case CallbackServiceCodec.CALLBACK_DESTROY:
|
||||
try {
|
||||
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), false);
|
||||
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt((String) inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), false);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(StringUtils.toString(e));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
|
||||
Map<String, String> map = (Map<String, String>) in.readObject(Map.class);
|
||||
if (map != null && map.size() > 0) {
|
||||
Map<String, String> attachment = getAttachments();
|
||||
Map<String, Object> attachment = getAttachments();
|
||||
if (attachment == null) {
|
||||
attachment = new HashMap<String, String>();
|
||||
attachment = new HashMap<String, Object>();
|
||||
}
|
||||
attachment.putAll(map);
|
||||
setAttachments(attachment);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
|
|||
|
||||
@Override
|
||||
public Object decode(Channel channel, InputStream input) throws IOException {
|
||||
log.debug("Decoding in thread -- " + Thread.currentThread().getName());
|
||||
ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
|
||||
.deserialize(channel.getUrl(), input);
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
|
|||
|
||||
private void handleAttachment(ObjectInput in) throws IOException {
|
||||
try {
|
||||
setAttachments((Map<String, String>) in.readObject(Map.class));
|
||||
setAttachments((Map<String, Object>) in.readObject(Map.class));
|
||||
} catch (ClassNotFoundException e) {
|
||||
rethrow(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,8 +175,8 @@ public class DubboCodec extends ExchangeCodec {
|
|||
RpcInvocation inv = (RpcInvocation) data;
|
||||
|
||||
out.writeUTF(version);
|
||||
out.writeUTF(inv.getAttachment(PATH_KEY));
|
||||
out.writeUTF(inv.getAttachment(VERSION_KEY));
|
||||
out.writeUTF((String) inv.getAttachment(PATH_KEY));
|
||||
out.writeUTF((String) inv.getAttachment(VERSION_KEY));
|
||||
|
||||
out.writeUTF(inv.getMethodName());
|
||||
out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
boolean isCallBackServiceInvoke = false;
|
||||
boolean isStubServiceInvoke = false;
|
||||
int port = channel.getLocalAddress().getPort();
|
||||
String path = inv.getAttachments().get(PATH_KEY);
|
||||
String path = (String) inv.getAttachments().get(PATH_KEY);
|
||||
|
||||
// if it's callback service on client side
|
||||
isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(STUB_EVENT_KEY));
|
||||
|
|
@ -258,7 +258,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
String serviceKey = serviceKey(port, path, inv.getAttachments().get(VERSION_KEY), inv.getAttachments().get(GROUP_KEY));
|
||||
String serviceKey = serviceKey(port, path, (String) inv.getAttachments().get(VERSION_KEY), (String) inv.getAttachments().get(GROUP_KEY));
|
||||
DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
|
||||
|
||||
if (exporter == null) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.apache.dubbo.remoting.exchange.Exchangers;
|
|||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
|
@ -114,6 +115,20 @@ final class LazyConnectExchangeClient implements ExchangeClient {
|
|||
return client.request(request, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
warning();
|
||||
initClient();
|
||||
return client.request(request, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
warning();
|
||||
initClient();
|
||||
return client.request(request, timeout, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link #REQUEST_WITH_WARNING_KEY} is configured, then warn once every 5000 invocations.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
|||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.apache.dubbo.remoting.Constants.RECONNECT_KEY;
|
||||
|
|
@ -80,6 +81,16 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
|
|||
return client.request(request, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
|
||||
return client.request(request, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
|
||||
return client.request(request, timeout, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return client.isConnected();
|
||||
|
|
|
|||
|
|
@ -111,8 +111,9 @@ public class ImplicitCallBackTest {
|
|||
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
|
||||
asyncMethodInfo.setOnthrowInstance(notify);
|
||||
asyncMethodInfo.setOnthrowMethod(onThrowMethod);
|
||||
attitudes.put("get", asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
|
||||
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
|
||||
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
|
||||
}
|
||||
|
||||
//================================================================================================
|
||||
|
|
@ -122,8 +123,9 @@ public class ImplicitCallBackTest {
|
|||
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
|
||||
asyncMethodInfo.setOnreturnInstance(notify);
|
||||
asyncMethodInfo.setOnreturnMethod(onReturnMethod);
|
||||
attitudes.put("get", asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
|
||||
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
|
||||
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
|
||||
}
|
||||
|
||||
public void initImplicitCallBackURL_onlyOninvoke() throws Exception {
|
||||
|
|
@ -131,8 +133,9 @@ public class ImplicitCallBackTest {
|
|||
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
|
||||
asyncMethodInfo.setOninvokeInstance(notify);
|
||||
asyncMethodInfo.setOninvokeMethod(onInvokeMethod);
|
||||
attitudes.put("get", asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
|
||||
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
|
||||
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
|
||||
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
|
|||
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoService;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -68,7 +69,7 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
|
||||
String result = invoke.telnet(mockChannel, "echo(\"ok\")");
|
||||
|
|
@ -83,8 +84,8 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = invoke.telnet(mockChannel, "DemoService.echo(\"ok\")");
|
||||
assertTrue(result.contains("result: \"ok\""));
|
||||
|
|
@ -98,8 +99,9 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
try {
|
||||
invoke.telnet(mockChannel, "sayHello(null)");
|
||||
} catch (Exception ex) {
|
||||
|
|
@ -114,8 +116,8 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = invoke.telnet(mockChannel, "getType(\"High\")");
|
||||
assertTrue(result.contains("result: \"High\""));
|
||||
|
|
@ -130,8 +132,9 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = invoke.telnet(mockChannel, "getPerson({\"name\":\"zhangsan\",\"age\":12,\"class\":\"org.apache.dubbo.rpc.protocol.dubbo.support.Person\"})");
|
||||
assertTrue(result.contains("result: 12"));
|
||||
}
|
||||
|
|
@ -144,8 +147,9 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String param = "{\"name\":\"Dubbo\",\"age\":8}";
|
||||
String result = invoke.telnet(mockChannel, "getPerson(" + param + ")");
|
||||
assertTrue(result.contains("Please use the select command to select the method you want to invoke. eg: select 1"));
|
||||
|
|
@ -161,8 +165,9 @@ public class InvokerTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String param = "{\"name\":\"Dubbo\",\"age\":8},{\"name\":\"Apache\",\"age\":20}";
|
||||
String result = invoke.telnet(mockChannel, "getPerson(" + param + ")");
|
||||
assertTrue(result.contains("result: 28"));
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class ListTelnetHandlerTest {
|
|||
mockChannel = mock(Channel.class);
|
||||
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
|
||||
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = list.telnet(mockChannel, "-l DemoService");
|
||||
|
|
@ -80,7 +80,7 @@ public class ListTelnetHandlerTest {
|
|||
mockChannel = mock(Channel.class);
|
||||
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
|
||||
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = list.telnet(mockChannel, "DemoService");
|
||||
|
|
@ -94,11 +94,11 @@ public class ListTelnetHandlerTest {
|
|||
mockChannel = mock(Channel.class);
|
||||
given(mockChannel.getAttribute("telnet.service")).willReturn(null);
|
||||
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = list.telnet(mockChannel, "");
|
||||
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService\r\n", result);
|
||||
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0\r\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -106,11 +106,11 @@ public class ListTelnetHandlerTest {
|
|||
mockChannel = mock(Channel.class);
|
||||
given(mockChannel.getAttribute("telnet.service")).willReturn(null);
|
||||
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = list.telnet(mockChannel, "-l");
|
||||
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService -> published: N\r\n", result);
|
||||
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0 -> published: N\r\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -118,12 +118,12 @@ public class ListTelnetHandlerTest {
|
|||
mockChannel = mock(Channel.class);
|
||||
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
|
||||
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
|
||||
|
||||
String result = list.telnet(mockChannel, "");
|
||||
assertTrue(result.startsWith("Use default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\r\n" +
|
||||
"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService (as provider):\r\n"));
|
||||
"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0 (as provider):\r\n"));
|
||||
for (Method method : DemoService.class.getMethods()) {
|
||||
assertTrue(result.contains(method.getName()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
|
|||
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoService;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -71,7 +72,7 @@ public class SelectTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
|
||||
String result = select.telnet(mockChannel, "1");
|
||||
|
|
@ -86,7 +87,7 @@ public class SelectTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
|
||||
String result = select.telnet(mockChannel, "index");
|
||||
|
|
@ -107,7 +108,7 @@ public class SelectTelnetHandlerTest {
|
|||
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
|
||||
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
|
||||
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
|
||||
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
|
||||
|
||||
String result = select.telnet(mockChannel, null);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class DubboHessianURLConnectionFactory extends HessianURLConnectionFactor
|
|||
HessianConnection connection = super.open(url);
|
||||
RpcContext context = RpcContext.getContext();
|
||||
for (String key : context.getAttachments().keySet()) {
|
||||
connection.addHeader(Constants.DEFAULT_EXCHANGER + key, context.getAttachment(key));
|
||||
connection.addHeader(Constants.DEFAULT_EXCHANGER + key, (String) context.getAttachment(key));
|
||||
}
|
||||
|
||||
return connection;
|
||||
|
|
|
|||
|
|
@ -1,56 +1,55 @@
|
|||
/*
|
||||
* 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.hessian;
|
||||
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
|
||||
import com.caucho.hessian.client.HessianConnection;
|
||||
import com.caucho.hessian.client.HessianConnectionFactory;
|
||||
import com.caucho.hessian.client.HessianProxyFactory;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* HttpClientConnectionFactory
|
||||
*/
|
||||
public class HttpClientConnectionFactory implements HessianConnectionFactory {
|
||||
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public void setHessianProxyFactory(HessianProxyFactory factory) {
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectionRequestTimeout((int) factory.getConnectTimeout())
|
||||
.setSocketTimeout((int) factory.getReadTimeout())
|
||||
.build();
|
||||
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HessianConnection open(URL url) {
|
||||
HttpClientConnection httpClientConnection = new HttpClientConnection(httpClient, url);
|
||||
RpcContext context = RpcContext.getContext();
|
||||
for (String key : context.getAttachments().keySet()) {
|
||||
httpClientConnection.addHeader(Constants.DEFAULT_EXCHANGER + key, context.getAttachment(key));
|
||||
}
|
||||
return httpClientConnection;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.hessian;
|
||||
|
||||
import com.caucho.hessian.client.HessianConnection;
|
||||
import com.caucho.hessian.client.HessianConnectionFactory;
|
||||
import com.caucho.hessian.client.HessianProxyFactory;
|
||||
import org.apache.dubbo.common.Constants;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* HttpClientConnectionFactory
|
||||
*/
|
||||
public class HttpClientConnectionFactory implements HessianConnectionFactory {
|
||||
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public void setHessianProxyFactory(HessianProxyFactory factory) {
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectionRequestTimeout((int) factory.getConnectTimeout())
|
||||
.setSocketTimeout((int) factory.getReadTimeout())
|
||||
.build();
|
||||
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HessianConnection open(URL url) {
|
||||
HttpClientConnection httpClientConnection = new HttpClientConnection(httpClient, url);
|
||||
RpcContext context = RpcContext.getContext();
|
||||
for (String key : context.getAttachments().keySet()) {
|
||||
httpClientConnection.addHeader(Constants.DEFAULT_EXCHANGER + key, (String) context.getAttachment(key));
|
||||
}
|
||||
return httpClientConnection;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ public class HttpRemoteInvocation extends RemoteInvocation {
|
|||
|
||||
public HttpRemoteInvocation(MethodInvocation methodInvocation) {
|
||||
super(methodInvocation);
|
||||
addAttribute(DUBBO_ATTACHMENTS_ATTR_NAME, new HashMap<String, String>(RpcContext.getContext().getAttachments()));
|
||||
addAttribute(DUBBO_ATTACHMENTS_ATTR_NAME, new HashMap<String, Object>(RpcContext.getContext().getAttachments()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
RpcContext context = RpcContext.getContext();
|
||||
context.setAttachments((Map<String, String>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
|
||||
context.setAttachments((Map<String, Object>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
|
||||
|
||||
String generic = (String) getAttribute(GENERIC_KEY);
|
||||
if (StringUtils.isNotEmpty(generic)) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
<!--
|
||||
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>
|
||||
<artifactId>dubbo-rpc</artifactId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dubbo-rpc-jsonrpc</artifactId>
|
||||
|
||||
<description>The JSON-RPC module of dubbo project</description>
|
||||
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-http</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.briandilley.jsonrpc4j</groupId>
|
||||
<artifactId>jsonrpc4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.portlet</groupId>
|
||||
<artifactId>portlet-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
@ -137,7 +137,7 @@ public class RestProtocol extends AbstractProxyProtocol {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException {
|
||||
protected <T> T getFrameworkProxy(Class<T> serviceType, URL url) throws RpcException {
|
||||
|
||||
// TODO more configs to add
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
|
||||
|
|
|
|||
|
|
@ -69,16 +69,18 @@ public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFi
|
|||
@Override
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
int size = 0;
|
||||
for (Map.Entry<String, String> entry : RpcContext.getContext().getAttachments().entrySet()) {
|
||||
for (Map.Entry<String, Object> entry : RpcContext.getContext().getAttachments().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
Object value = entry.getValue();
|
||||
if (illegalForRest(key) || illegalForRest(value)) {
|
||||
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " must not contain ',' or '=' when using rest protocol");
|
||||
}
|
||||
|
||||
String stringValue = (String) value;
|
||||
|
||||
// TODO for now we don't consider the differences of encoding and server limit
|
||||
if (value != null) {
|
||||
size += value.getBytes(StandardCharsets.UTF_8).length;
|
||||
size += stringValue.getBytes(StandardCharsets.UTF_8).length;
|
||||
}
|
||||
if (size > MAX_HEADER_SIZE) {
|
||||
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " is too big");
|
||||
|
|
@ -95,9 +97,9 @@ public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFi
|
|||
* @param v string value
|
||||
* @return true for illegal
|
||||
*/
|
||||
private boolean illegalForRest(String v) {
|
||||
if (StringUtils.isNotEmpty(v)) {
|
||||
return v.contains(",") || v.contains("=");
|
||||
private boolean illegalForRest(Object v) {
|
||||
if (v instanceof String && StringUtils.isNotEmpty((String) v)) {
|
||||
return ((String) v).contains(",") || ((String) v).contains("=");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class RestProtocolTest {
|
|||
public void testRestProtocol() {
|
||||
URL url = URL.valueOf("rest://127.0.0.1:5342/rest/say?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.DemoService");
|
||||
DemoServiceImpl server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(url.getPathKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(url.getPathKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(url.getPathKey(), providerModel);
|
||||
|
||||
Exporter<DemoService> exporter = protocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
|
@ -76,7 +76,7 @@ public class RestProtocolTest {
|
|||
DemoServiceImpl server = new DemoServiceImpl();
|
||||
Assertions.assertFalse(server.isCalled());
|
||||
URL url = URL.valueOf("rest://127.0.0.1:5341/a/b/c?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.DemoService");
|
||||
ProviderModel providerModel = new ProviderModel(url.getPathKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(url.getPathKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(url.getPathKey(), providerModel);
|
||||
|
||||
Exporter<DemoService> exporter = protocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
|
@ -94,7 +94,7 @@ public class RestProtocolTest {
|
|||
@Test
|
||||
public void testExport() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
RpcContext.getContext().setAttachment("timeout", "200");
|
||||
|
|
@ -111,7 +111,7 @@ public class RestProtocolTest {
|
|||
@Test
|
||||
public void testNettyServer() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty");
|
||||
|
|
@ -129,7 +129,7 @@ public class RestProtocolTest {
|
|||
public void testServletWithoutWebConfig() {
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getPathKey(), providerModel);
|
||||
|
||||
URL servletUrl = exportUrl.addParameter(SERVER_KEY, "servlet");
|
||||
|
|
@ -142,7 +142,7 @@ public class RestProtocolTest {
|
|||
public void testErrorHandler() {
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty");
|
||||
|
|
@ -157,7 +157,7 @@ public class RestProtocolTest {
|
|||
@Test
|
||||
public void testInvoke() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ public class RestProtocolTest {
|
|||
@Test
|
||||
public void testFilter() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty")
|
||||
|
|
@ -191,7 +191,7 @@ public class RestProtocolTest {
|
|||
@Test
|
||||
public void testRpcContextFilter() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
// use RpcContextFilter
|
||||
|
|
@ -215,7 +215,7 @@ public class RestProtocolTest {
|
|||
public void testRegFail() {
|
||||
Assertions.assertThrows(RuntimeException.class, () -> {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
|
||||
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
|
||||
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
|
||||
|
||||
URL nettyUrl = exportUrl.addParameter(EXTENSION_KEY, "com.not.existing.Filter");
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class RmiProtocol extends AbstractProxyProtocol {
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {
|
||||
protected <T> T getFrameworkProxy(final Class<T> serviceType, final URL url) throws RpcException {
|
||||
final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
|
||||
final String generic = url.getParameter(GENERIC_KEY);
|
||||
final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class RmiRemoteInvocation extends RemoteInvocation {
|
|||
public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
RpcContext context = RpcContext.getContext();
|
||||
context.setAttachments((Map<String, String>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
|
||||
context.setAttachments((Map<String, Object>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
|
||||
String generic = (String) getAttribute(GENERIC_KEY);
|
||||
if (StringUtils.isNotEmpty(generic)) {
|
||||
context.setAttachment(GENERIC_KEY, generic);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
<!--
|
||||
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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>dubbo-rpc-rsocket</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The default rpc module of dubbo project</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>false</skip_maven_deploy>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.3.16.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-registry-multicast</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rsocket</groupId>
|
||||
<artifactId>rsocket-core</artifactId>
|
||||
<version>0.11.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rsocket</groupId>
|
||||
<artifactId>rsocket-transport-netty</artifactId>
|
||||
<version>0.11.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.54</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-config-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-config-spring</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-container-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-hessian2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-serialization-jdk</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>javax.validation</groupId>-->
|
||||
<!--<artifactId>validation-api</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.hibernate</groupId>-->
|
||||
<!--<artifactId>hibernate-validator</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.glassfish</groupId>-->
|
||||
<!--<artifactId>javax.el</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.rsocket;
|
||||
|
||||
import org.apache.dubbo.common.serialize.ObjectInput;
|
||||
import org.apache.dubbo.common.serialize.Serialization;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
|
||||
import io.rsocket.Payload;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class FutureSubscriber extends CompletableFuture<AppResponse> implements Subscriber<Payload> {
|
||||
|
||||
private final Serialization serialization;
|
||||
|
||||
private final Class<?> retType;
|
||||
|
||||
public FutureSubscriber(Serialization serialization, Class<?> retType) {
|
||||
this.serialization = serialization;
|
||||
this.retType = retType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Subscription subscription) {
|
||||
subscription.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(Payload payload) {
|
||||
try {
|
||||
AppResponse appResponse = new AppResponse();
|
||||
ByteBuffer dataBuffer = payload.getData();
|
||||
byte[] dataBytes = new byte[dataBuffer.remaining()];
|
||||
dataBuffer.get(dataBytes, dataBuffer.position(), dataBuffer.remaining());
|
||||
InputStream dataInputStream = new ByteArrayInputStream(dataBytes);
|
||||
ObjectInput in = serialization.deserialize(null, dataInputStream);
|
||||
|
||||
int flag = in.readByte();
|
||||
if ((flag & RSocketConstants.FLAG_ERROR) != 0) {
|
||||
Throwable t = (Throwable) in.readObject();
|
||||
appResponse.setException(t);
|
||||
} else {
|
||||
Object value = null;
|
||||
if ((flag & RSocketConstants.FLAG_NULL_VALUE) == 0) {
|
||||
if (retType == null) {
|
||||
value = in.readObject();
|
||||
} else {
|
||||
value = in.readObject(retType);
|
||||
}
|
||||
appResponse.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flag & RSocketConstants.FLAG_HAS_ATTACHMENT) != 0) {
|
||||
Map<String, Object> attachment = in.readObject(Map.class);
|
||||
appResponse.setAttachments(attachment);
|
||||
|
||||
}
|
||||
|
||||
this.complete(appResponse);
|
||||
|
||||
|
||||
} catch (Throwable t) {
|
||||
this.completeExceptionally(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
this.completeExceptionally(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.rsocket;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
public class MetadataCodec {
|
||||
|
||||
public static Map<String, Object> decodeMetadata(byte[] bytes) throws IOException {
|
||||
return JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), Map.class);
|
||||
}
|
||||
|
||||
public static byte[] encodeMetadata(Map<String, Object> metadata) throws IOException {
|
||||
String jsonStr = JSON.toJSONString(metadata);
|
||||
return jsonStr.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.rsocket;
|
||||
|
||||
public class RSocketConstants {
|
||||
|
||||
public static final String SERVICE_NAME_KEY = "_service_name";
|
||||
public static final String SERVICE_VERSION_KEY = "_service_version";
|
||||
public static final String METHOD_NAME_KEY = "_method_name";
|
||||
public static final String PARAM_TYPE_KEY = "_param_type";
|
||||
public static final String SERIALIZE_TYPE_KEY = "_serialize_type";
|
||||
public static final String TIMEOUT_KEY = "_timeout";
|
||||
|
||||
|
||||
public static final int FLAG_ERROR = 0x01;
|
||||
public static final int FLAG_NULL_VALUE = 0x02;
|
||||
public static final int FLAG_HAS_ATTACHMENT = 0x04;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue