Merge branch 'apache-3.1' into apache-3.2

# Conflicts:
#	dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java
This commit is contained in:
Albumen Kevin 2022-11-21 11:33:52 +08:00
commit 9d4cb1a59d
13 changed files with 28 additions and 375 deletions

View File

@ -534,7 +534,11 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
URL url = new ServiceConfigURL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName(), referenceParameters);
url = url.setScopeModel(getScopeModel());
url = url.setServiceModel(consumerModel);
invoker = protocolSPI.refer(interfaceClass, url);
Invoker<?> withFilter = protocolSPI.refer(interfaceClass, url);
// Local Invoke ( Support Cluster Filter / Filter )
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(withFilter);
invoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT).join(new StaticDirectory(url, invokers), true);
if (logger.isInfoEnabled()) {
logger.info("Using in jvm service " + interfaceClass.getName());

View File

@ -477,9 +477,10 @@ public class ReferenceConfigTest {
.initialize();
referenceConfig.init();
Invoker<?> withFilter = ((ListenerInvokerWrapper<?>) referenceConfig.getInvoker()).getInvoker();
withFilter = ((MockClusterInvoker<?>) withFilter).getDirectory().getAllInvokers().get(0);
Assertions.assertTrue(withFilter instanceof InjvmInvoker);
Assertions.assertTrue(referenceConfig.getInvoker() instanceof MockClusterInvoker);
Invoker<?> withFilter = ((MockClusterInvoker<?>) referenceConfig.getInvoker()).getDirectory().getAllInvokers().get(0);
Assertions.assertTrue(withFilter instanceof ListenerInvokerWrapper);
Assertions.assertTrue(((ListenerInvokerWrapper<?>) withFilter).getInvoker() instanceof InjvmInvoker);
URL url = withFilter.getUrl();
Assertions.assertEquals("application1", url.getParameter("application"));
Assertions.assertEquals("value1", url.getParameter("key1"));

View File

@ -263,7 +263,7 @@ public class MultipleRegistry extends AbstractRegistry {
protected static class MultipleNotifyListenerWrapper implements NotifyListener {
Map<URL, SingleNotifyListener> registryMap = new ConcurrentHashMap<>(4);
Map<URL, SingleNotifyListener> registryMap = new ConcurrentHashMap<URL, SingleNotifyListener>(4);
NotifyListener sourceNotifyListener;
public MultipleNotifyListenerWrapper(NotifyListener sourceNotifyListener) {

View File

@ -39,7 +39,11 @@ public class NacosAggregateListener {
public List<Instance> saveAndAggregateAllInstances(String serviceName, List<Instance> instances) {
serviceNames.add(serviceName);
serviceInstances.put(serviceName, instances);
if (instances == null) {
serviceInstances.remove(serviceName);
} else {
serviceInstances.put(serviceName, instances);
}
return serviceInstances.values().stream().flatMap(List::stream).collect(Collectors.toList());
}

View File

@ -28,7 +28,6 @@ import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryNotifier;
import org.apache.dubbo.registry.nacos.util.NacosInstanceManageUtil;
import org.apache.dubbo.registry.support.FailbackRegistry;
import org.apache.dubbo.rpc.RpcException;
@ -210,13 +209,6 @@ public class NacosRegistry extends FailbackRegistry {
Set<String> serviceNames = getServiceNames(url, nacosAggregateListener);
//Set corresponding serviceNames for easy search later
if (isServiceNamesWithCompatibleMode(url)) {
for (String serviceName : serviceNames) {
NacosInstanceManageUtil.setCorrespondingServiceNames(serviceName, serviceNames);
}
}
doSubscribe(url, nacosAggregateListener, serviceNames);
}
@ -236,7 +228,6 @@ public class NacosRegistry extends FailbackRegistry {
for (String serviceName : serviceNames) {
List<Instance> instances = namingService.getAllInstances(serviceName,
getUrl().getGroup(Constants.DEFAULT_GROUP));
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
notifySubscriber(url, serviceName, listener, instances);
}
for (String serviceName : serviceNames) {
@ -289,9 +280,6 @@ public class NacosRegistry extends FailbackRegistry {
Set<String> serviceNames = nacosAggregateListener.getServiceNames();
try {
doUnsubscribe(url, nacosAggregateListener, serviceNames);
for (String serviceName : serviceNames) {
NacosInstanceManageUtil.removeCorrespondingServiceNames(serviceName);
}
} catch (NacosException e) {
logger.error(REGISTRY_NACOS_EXCEPTION, "", "", "Failed to unsubscribe " + url + " to nacos " + getUrl() + ", cause: " + e.getMessage(), e);
}
@ -716,14 +704,6 @@ public class NacosRegistry extends FailbackRegistry {
@Override
protected void doNotify(Object rawAddresses) {
List<Instance> instances = (List<Instance>) rawAddresses;
if (isServiceNamesWithCompatibleMode(consumerUrl)) {
/**
* Get all instances with corresponding serviceNames to avoid instance overwrite and but with empty instance mentioned
* in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
*/
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instances);
instances = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
}
NacosRegistry.this.notifySubscriber(consumerUrl, serviceName, listener, instances);
}
};

View File

@ -1,73 +0,0 @@
/*
* 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.nacos.util;
import org.apache.dubbo.common.utils.CollectionUtils;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.alibaba.nacos.shaded.com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Instance manage util for multiple serviceNames
* To resolve bug with https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899
*
* @since 2.7.6
*/
public class NacosInstanceManageUtil {
/**
* serviceName -> refreshed instance list
*/
private static final Map<String, List<Instance>> SERVICE_INSTANCE_LIST_MAP = Maps.newConcurrentMap();
/**
* serviceName -> corresponding serviceName list
*/
private static final Map<String, Set<String>> CORRESPONDING_SERVICE_NAMES_MAP = Maps.newConcurrentMap();
public static void setCorrespondingServiceNames(String serviceName, Set<String> serviceNames) {
CORRESPONDING_SERVICE_NAMES_MAP.put(serviceName, serviceNames);
}
public static void initOrRefreshServiceInstanceList(String serviceName, List<Instance> instanceList) {
SERVICE_INSTANCE_LIST_MAP.put(serviceName, instanceList);
}
public static Set<String> removeCorrespondingServiceNames(String serviceName) {
return CORRESPONDING_SERVICE_NAMES_MAP.remove(serviceName);
}
public static List<Instance> getAllCorrespondingServiceInstanceList(String serviceName) {
if (!CORRESPONDING_SERVICE_NAMES_MAP.containsKey(serviceName)) {
return Lists.newArrayList();
}
List<Instance> allInstances = Lists.newArrayList();
for (String correspondingServiceName : CORRESPONDING_SERVICE_NAMES_MAP.get(serviceName)) {
if (SERVICE_INSTANCE_LIST_MAP.containsKey(correspondingServiceName)
&& CollectionUtils.isNotEmpty(SERVICE_INSTANCE_LIST_MAP.get(correspondingServiceName))) {
allInstances.addAll(SERVICE_INSTANCE_LIST_MAP.get(correspondingServiceName));
}
}
return allInstances;
}
}

View File

@ -1,100 +0,0 @@
/*
* 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.nacos.util;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Test for NacosInstanceManageUtil
*/
public class NacosInstanceManageUtilTest {
@Test
public void testSetCorrespondingServiceNames() {
String serviceName = "serviceName";
Set<String> serviceNames = new HashSet<String>() {{
add("serviceName1");
add("serviceName2");
add("serviceName3");
}};
NacosInstanceManageUtil.setCorrespondingServiceNames(serviceName, serviceNames);
List<Instance> allCorrespondingServiceInstanceList = NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
Assertions.assertEquals(0, allCorrespondingServiceInstanceList.size());
}
@Test
public void testInitOrRefreshServiceInstanceList() {
String serviceName = "serviceName";
Set<String> serviceNames = new HashSet<String>() {{
add("serviceName1");
add("serviceName2");
add("serviceName3");
}};
NacosInstanceManageUtil.setCorrespondingServiceNames(serviceName, serviceNames);
Instance instance1 = new Instance();
instance1.setInstanceId("1");
Instance instance2 = new Instance();
instance2.setInstanceId("2");
Instance instance3 = new Instance();
instance3.setInstanceId("3");
List<Instance> instanceList = new ArrayList<Instance>() {{
add(instance1);
add(instance2);
add(instance3);
}};
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instanceList);
List<Instance> allCorrespondingServiceInstanceList =
NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
Assertions.assertEquals(0, allCorrespondingServiceInstanceList.size());
}
@Test
public void testGetAllCorrespondingServiceInstanceList() {
String serviceName = "serviceName";
Set<String> serviceNames = new HashSet<String>() {{
add("serviceName");
add("serviceName1");
}};
NacosInstanceManageUtil.setCorrespondingServiceNames(serviceName, serviceNames);
Instance instance1 = new Instance();
instance1.setInstanceId("1");
Instance instance2 = new Instance();
instance2.setInstanceId("2");
Instance instance3 = new Instance();
instance3.setInstanceId("3");
List<Instance> instanceList = new ArrayList<Instance>() {{
add(instance1);
add(instance2);
add(instance3);
}};
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName, instanceList);
List<Instance> allCorrespondingServiceInstanceList =
NacosInstanceManageUtil.getAllCorrespondingServiceInstanceList(serviceName);
Assertions.assertEquals(3, allCorrespondingServiceInstanceList.size());
}
}

View File

@ -42,6 +42,7 @@ import org.apache.dubbo.rpc.support.RpcUtils;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
@ -62,7 +63,7 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
private final String key;
private final Exporter<?> exporter;
private final Map<String, Exporter<?>> exporterMap;
private final ExecutorRepository executorRepository;
@ -70,10 +71,10 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
private final boolean shouldIgnoreSameModule;
InjvmInvoker(Class<T> type, URL url, String key, Exporter<?> exporter) {
InjvmInvoker(Class<T> type, URL url, String key, Map<String, Exporter<?>> exporterMap) {
super(type, url);
this.key = key;
this.exporter = exporter;
this.exporterMap = exporterMap;
this.executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel());
this.paramDeepCopyUtil = url.getOrDefaultFrameworkModel().getExtensionLoader(ParamDeepCopyUtil.class)
.getExtension(url.getParameter(CommonConstants.INJVM_COPY_UTIL_KEY, DefaultParamDeepCopyUtil.NAME));
@ -82,6 +83,7 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
@Override
public boolean isAvailable() {
InjvmExporter<?> exporter = (InjvmExporter<?>) exporterMap.get(key);
if (exporter == null) {
return false;
} else {
@ -91,6 +93,7 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
@Override
public Result doInvoke(Invocation invocation) throws Throwable {
Exporter<?> exporter = InjvmProtocol.getExporter(exporterMap, getUrl());
if (exporter == null) {
throw new RpcException("Service [" + key + "] not found.");
}

View File

@ -18,29 +18,19 @@ package org.apache.dubbo.rpc.protocol.injvm;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.cluster.support.MergeableCluster;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.protocol.AbstractProtocol;
import org.apache.dubbo.rpc.support.ProtocolUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.BROADCAST_CLUSTER;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
@ -79,7 +69,7 @@ public class InjvmProtocol extends AbstractProtocol {
if (result == null) {
return null;
} else if (ProtocolUtils.isGeneric(
result.getInvoker().getUrl().getParameter(GENERIC_KEY))) {
result.getInvoker().getUrl().getParameter(GENERIC_KEY))) {
return null;
} else {
return result;
@ -98,15 +88,7 @@ public class InjvmProtocol extends AbstractProtocol {
@Override
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
// group="a,b" or group="*"
String group = url.getParameter(GROUP_KEY);
if (StringUtils.isNotEmpty(group)) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
return doCreateInvoker(url, Cluster.getCluster(url.getScopeModel(), MergeableCluster.NAME), serviceType);
}
}
Cluster cluster = Cluster.getCluster(url.getScopeModel(), url.getParameter(CLUSTER_KEY));
return doCreateInvoker(url, cluster, serviceType);
return new InjvmInvoker<T>(serviceType, url, url.getServiceKey(), exporterMap);
}
public boolean isInjvmRefer(URL url) {
@ -134,34 +116,4 @@ public class InjvmProtocol extends AbstractProtocol {
return false;
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected <T> ClusterInvoker<T> doCreateInvoker(URL url, Cluster cluster, Class<T> type) {
StaticDirectory directory = new StaticDirectory(url, getInvokers(exporterMap, url, type));
return (ClusterInvoker<T>) cluster.join(directory, true);
}
private <T> List<Invoker<T>> getInvokers(Map<String, Exporter<?>> map, URL url, Class<T> type) {
List<Invoker<T>> result = new ArrayList<>();
if (!url.getServiceKey().contains("*")) {
Exporter<?> exporter = map.get(url.getServiceKey());
InjvmInvoker<T> invoker = new InjvmInvoker<>(type, url, url.getServiceKey(), exporter);
result.add(invoker);
} else {
if (CollectionUtils.isNotEmptyMap(map)) {
for (Exporter<?> exporter : map.values()) {
if (UrlUtils.isServiceKeyMatch(url, exporter.getInvoker().getUrl())) {
URL providerUrl = exporter.getInvoker().getUrl();
URL consumerUrl = url.addParameter(GROUP_KEY, providerUrl.getGroup())
.addParameter(VERSION_KEY, providerUrl.getVersion());
InjvmInvoker<T> invoker = new InjvmInvoker<>(type, consumerUrl, consumerUrl.getServiceKey(), exporter);
result.add(invoker);
}
}
}
}
return result;
}
}

View File

@ -1,31 +0,0 @@
/*
* 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.injvm;
import java.util.ArrayList;
import java.util.List;
public class Hello1ServiceImpl implements HelloService {
@Override
public List<String> hellos() {
List<String> res = new ArrayList<>();
res.add("consumer-hello-1");
return res;
}
}

View File

@ -1,33 +0,0 @@
/*
* 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.injvm;
import java.util.ArrayList;
import java.util.List;
public class Hello2ServiceImpl implements HelloService {
@Override
public List<String> hellos() {
List<String> res = new ArrayList<>();
res.add("consumer-hello-2");
return res;
}
}

View File

@ -1,24 +0,0 @@
/*
* 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.injvm;
import java.util.List;
public interface HelloService {
List<String> hellos();
}

View File

@ -29,16 +29,18 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.*;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
import static org.apache.dubbo.rpc.Constants.MERGER_KEY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -74,7 +76,7 @@ public class InjvmProtocolTest {
assertEquals(service.getSize(new String[]{"", "", ""}), 3);
service.invoke("injvm://127.0.0.1/TestService", "invoke");
InjvmInvoker<?> injvmInvoker = new InjvmInvoker<>(DemoService.class, URL.valueOf("injvm://127.0.0.1/TestService"), null, null);
InjvmInvoker<?> injvmInvoker = new InjvmInvoker<>(DemoService.class, URL.valueOf("injvm://127.0.0.1/TestService"), null, new HashMap<>());
assertFalse(injvmInvoker.isAvailable());
}
@ -135,36 +137,4 @@ public class InjvmProtocolTest {
assertNull(service.getAsyncResult());
}
@Test
public void testLocalProtocolForMergeResult() throws Exception {
HelloService helloService1 = new Hello1ServiceImpl();
URL url = URL.valueOf("injvm://127.0.0.1/HelloService")
.addParameter(INTERFACE_KEY, HelloService.class.getName())
.addParameter(APPLICATION_KEY, "consumer")
.addParameter(GROUP_KEY, "g1");
Invoker<?> invoker1 = proxy.getInvoker(helloService1, HelloService.class, url);
assertTrue(invoker1.isAvailable());
Exporter<?> exporter1 = protocol.export(invoker1);
exporters.add(exporter1);
URL url2 = URL.valueOf("injvm://127.0.0.1/HelloService")
.addParameter(INTERFACE_KEY, HelloService.class.getName())
.addParameter(APPLICATION_KEY, "consumer")
.addParameter(GROUP_KEY, "g2");
HelloService helloService2 = new Hello2ServiceImpl();
Invoker<?> invoker2 = proxy.getInvoker(helloService2, HelloService.class, url2);
assertTrue(invoker2.isAvailable());
Exporter<?> exporter2 = protocol.export(invoker2);
exporters.add(exporter2);
URL referUrl = URL.valueOf("injvm://127.0.0.1/HelloService")
.addParameter(INTERFACE_KEY, HelloService.class.getName())
.addParameter(APPLICATION_KEY, "consumer")
.addParameter(GROUP_KEY, "*")
.addParameter(MERGER_KEY, "list");
List<String> list = proxy.getProxy(protocol.refer(HelloService.class, referUrl)).hellos();
assertEquals(2, list.size());
}
}