Merge remote-tracking branch 'apache/3.0.5-release' into apache-3.0
# Conflicts: # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java # dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java # dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ClassLoaderFilter.java
This commit is contained in:
commit
e554427a1a
|
|
@ -103,7 +103,7 @@
|
|||
<profile>
|
||||
<id>release</id>
|
||||
<properties>
|
||||
<log4j2_version>2.11.1</log4j2_version>
|
||||
<log4j2_version>2.17.0</log4j2_version>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
|||
|
|
@ -18,13 +18,21 @@ package org.apache.dubbo.rpc.cluster.filter;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.extension.ExtensionDirector;
|
||||
import org.apache.dubbo.common.extension.support.MultiInstanceActivateComparator;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@Activate
|
||||
public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
||||
|
|
@ -36,14 +44,32 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
|||
public <T> Invoker<T> buildInvokerChain(final Invoker<T> originalInvoker, String key, String group) {
|
||||
Invoker<T> last = originalInvoker;
|
||||
URL url = originalInvoker.getUrl();
|
||||
List<Filter> filters = ScopeModelUtil.getExtensionLoader(Filter.class, url.getScopeModel()).getActivateExtension(url, key, group);
|
||||
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
||||
List<Filter> filters;
|
||||
if (moduleModels != null && moduleModels.size() == 1) {
|
||||
filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
|
||||
} else if (moduleModels != null && moduleModels.size() > 1) {
|
||||
filters = new ArrayList<>();
|
||||
List<ExtensionDirector> directors = new ArrayList<>();
|
||||
for (ModuleModel moduleModel : moduleModels) {
|
||||
List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel).getActivateExtension(url, key, group);
|
||||
filters.addAll(tempFilters);
|
||||
directors.add(moduleModel.getExtensionDirector());
|
||||
}
|
||||
filters = sortingAndDeduplication(filters, directors);
|
||||
|
||||
} else {
|
||||
filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
|
||||
}
|
||||
|
||||
|
||||
if (!CollectionUtils.isEmpty(filters)) {
|
||||
for (int i = filters.size() - 1; i >= 0; i--) {
|
||||
final Filter filter = filters.get(i);
|
||||
final Invoker<T> next = last;
|
||||
last = new FilterChainNode<>(originalInvoker, next, filter);
|
||||
last = new CopyOfFilterChainNode<>(originalInvoker, next, filter);
|
||||
}
|
||||
return new CallbackRegistrationInvoker<>(last, filters);
|
||||
}
|
||||
|
||||
return last;
|
||||
|
|
@ -56,17 +82,64 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
|||
public <T> ClusterInvoker<T> buildClusterInvokerChain(final ClusterInvoker<T> originalInvoker, String key, String group) {
|
||||
ClusterInvoker<T> last = originalInvoker;
|
||||
URL url = originalInvoker.getUrl();
|
||||
List<ClusterFilter> filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, url.getScopeModel()).getActivateExtension(url, key, group);
|
||||
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
||||
List<ClusterFilter> filters;
|
||||
if (moduleModels != null && moduleModels.size() == 1) {
|
||||
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
|
||||
} else if (moduleModels != null && moduleModels.size() > 1) {
|
||||
filters = new ArrayList<>();
|
||||
List<ExtensionDirector> directors = new ArrayList<>();
|
||||
for (ModuleModel moduleModel : moduleModels) {
|
||||
List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel).getActivateExtension(url, key, group);
|
||||
filters.addAll(tempFilters);
|
||||
directors.add(moduleModel.getExtensionDirector());
|
||||
}
|
||||
filters = sortingAndDeduplication(filters, directors);
|
||||
|
||||
} else {
|
||||
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(filters)) {
|
||||
for (int i = filters.size() - 1; i >= 0; i--) {
|
||||
final ClusterFilter filter = filters.get(i);
|
||||
final Invoker<T> next = last;
|
||||
last = new ClusterFilterChainNode<>(originalInvoker, next, filter);
|
||||
last = new CopyOfClusterFilterChainNode<>(originalInvoker, next, filter);
|
||||
}
|
||||
return new ClusterCallbackRegistrationInvoker<>(originalInvoker, last, filters);
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
private <T> List<T> sortingAndDeduplication(List<T> filters, List<ExtensionDirector> directors) {
|
||||
Map<Class<?>, T> filtersSet = new TreeMap<>(new MultiInstanceActivateComparator(directors));
|
||||
for (T filter : filters) {
|
||||
filtersSet.putIfAbsent(filter.getClass(), filter);
|
||||
}
|
||||
return new ArrayList<>(filtersSet.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* When the application-level service registration and discovery strategy is adopted, the URL will be of type InstanceAddressURL,
|
||||
* and InstanceAddressURL belongs to the application layer and holds the ApplicationModel,
|
||||
* but the filter is at the module layer and holds the ModuleModel,
|
||||
* so it needs to be based on the url in the ScopeModel type to parse out all the moduleModels held by the url
|
||||
* to obtain the filter configuration.
|
||||
*
|
||||
* @param url URL
|
||||
* @return All ModuleModels in the url
|
||||
*/
|
||||
private List<ModuleModel> getModuleModelsFromUrl(URL url) {
|
||||
List<ModuleModel> moduleModels = null;
|
||||
ScopeModel scopeModel = url.getScopeModel();
|
||||
if (scopeModel instanceof ApplicationModel) {
|
||||
moduleModels = ((ApplicationModel) scopeModel).getPubModuleModels();
|
||||
} else if (scopeModel instanceof ModuleModel) {
|
||||
moduleModels = new ArrayList<>();
|
||||
moduleModels.add((ModuleModel) scopeModel);
|
||||
}
|
||||
return moduleModels;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.cluster.filter;
|
||||
|
||||
import org.apache.dubbo.common.Experimental;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.BaseFilter;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
|
@ -28,6 +31,9 @@ import org.apache.dubbo.rpc.RpcException;
|
|||
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;
|
||||
|
||||
@SPI(value = "default", scope = APPLICATION)
|
||||
|
|
@ -144,12 +150,208 @@ public interface FilterChainBuilder {
|
|||
* @param <TYPE>
|
||||
*/
|
||||
class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
||||
extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
||||
extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
||||
public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
||||
super(originalInvoker, nextNode, filter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public URL getRegistryUrl() {
|
||||
return getOriginalInvoker().getRegistryUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<T> getDirectory() {
|
||||
return getOriginalInvoker().getDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return getOriginalInvoker().isDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> {
|
||||
static final Logger LOGGER = LoggerFactory.getLogger(CallbackRegistrationInvoker.class);
|
||||
final Invoker<T> filterInvoker;
|
||||
final List<FILTER> filters;
|
||||
|
||||
public CallbackRegistrationInvoker(Invoker<T> filterInvoker, List<FILTER> filters) {
|
||||
this.filterInvoker = filterInvoker;
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
Result asyncResult = filterInvoker.invoke(invocation);
|
||||
asyncResult.whenCompleteWithContext((r, t) -> {
|
||||
for (int i = filters.size() - 1; i >= 0; i--) {
|
||||
FILTER filter = filters.get(i);
|
||||
try {
|
||||
if (filter instanceof ListenableFilter) {
|
||||
ListenableFilter listenableFilter = ((ListenableFilter) filter);
|
||||
Filter.Listener listener = listenableFilter.listener(invocation);
|
||||
try {
|
||||
if (listener != null) {
|
||||
if (t == null) {
|
||||
listener.onResponse(r, filterInvoker, invocation);
|
||||
} else {
|
||||
listener.onError(t, filterInvoker, invocation);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
listenableFilter.removeListener(invocation);
|
||||
}
|
||||
} else if (filter instanceof FILTER.Listener) {
|
||||
FILTER.Listener listener = (FILTER.Listener) filter;
|
||||
if (t == null) {
|
||||
listener.onResponse(r, filterInvoker, invocation);
|
||||
} else {
|
||||
listener.onError(t, filterInvoker, invocation);
|
||||
}
|
||||
}
|
||||
} catch (Throwable filterThrowable) {
|
||||
LOGGER.error(String.format("Exception occurred while executing the %s filter named %s.", i, filter.getClass().getSimpleName()));
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("Whole filter list is: %s", filters.stream().map(tmpFilter -> tmpFilter.getClass().getSimpleName()).collect(Collectors.toList())));
|
||||
}
|
||||
throw filterThrowable;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getInterface() {
|
||||
return filterInvoker.getInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return filterInvoker.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return filterInvoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
filterInvoker.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter> extends CallbackRegistrationInvoker<T, FILTER>
|
||||
implements ClusterInvoker<T> {
|
||||
private ClusterInvoker<T> originalInvoker;
|
||||
|
||||
public ClusterCallbackRegistrationInvoker(ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {
|
||||
super(filterInvoker, filters);
|
||||
this.originalInvoker = originalInvoker;
|
||||
}
|
||||
|
||||
public ClusterInvoker<T> getOriginalInvoker() {
|
||||
return originalInvoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getRegistryUrl() {
|
||||
return getOriginalInvoker().getRegistryUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<T> getDirectory() {
|
||||
return getOriginalInvoker().getDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return getOriginalInvoker().isDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Experimental("Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough")
|
||||
class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {
|
||||
TYPE originalInvoker;
|
||||
Invoker<T> nextNode;
|
||||
FILTER filter;
|
||||
|
||||
public CopyOfFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
||||
this.originalInvoker = originalInvoker;
|
||||
this.nextNode = nextNode;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public TYPE getOriginalInvoker() {
|
||||
return originalInvoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getInterface() {
|
||||
return originalInvoker.getInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return originalInvoker.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return originalInvoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
Result asyncResult;
|
||||
try {
|
||||
asyncResult = filter.invoke(nextNode, invocation);
|
||||
} catch (Exception e) {
|
||||
if (filter instanceof ListenableFilter) {
|
||||
ListenableFilter listenableFilter = ((ListenableFilter) filter);
|
||||
try {
|
||||
Filter.Listener listener = listenableFilter.listener(invocation);
|
||||
if (listener != null) {
|
||||
listener.onError(e, originalInvoker, invocation);
|
||||
}
|
||||
} finally {
|
||||
listenableFilter.removeListener(invocation);
|
||||
}
|
||||
} else if (filter instanceof FILTER.Listener) {
|
||||
FILTER.Listener listener = (FILTER.Listener) filter;
|
||||
listener.onError(e, originalInvoker, invocation);
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
|
||||
}
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
originalInvoker.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return originalInvoker.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Experimental("Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough")
|
||||
class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
||||
extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
||||
public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
||||
super(originalInvoker, nextNode, filter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public URL getRegistryUrl() {
|
||||
return getOriginalInvoker().getRegistryUrl();
|
||||
|
|
|
|||
|
|
@ -93,35 +93,40 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
|
|||
((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
|
||||
}
|
||||
|
||||
try {
|
||||
// pass default timeout set by end user (ReferenceConfig)
|
||||
Object countDown = context.getObjectAttachment(TIME_COUNTDOWN_KEY);
|
||||
if (countDown != null) {
|
||||
TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
|
||||
if (timeoutCountDown.isExpired()) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
|
||||
"No time left for making the following call: " + invocation.getServiceName() + "."
|
||||
+ invocation.getMethodName() + ", terminate directly."), invocation);
|
||||
}
|
||||
// pass default timeout set by end user (ReferenceConfig)
|
||||
Object countDown = context.getObjectAttachment(TIME_COUNTDOWN_KEY);
|
||||
if (countDown != null) {
|
||||
TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
|
||||
if (timeoutCountDown.isExpired()) {
|
||||
return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
|
||||
"No time left for making the following call: " + invocation.getServiceName() + "."
|
||||
+ invocation.getMethodName() + ", terminate directly."), invocation);
|
||||
}
|
||||
|
||||
RpcContext.removeServerContext();
|
||||
return invoker.invoke(invocation);
|
||||
} finally {
|
||||
RpcContext.removeServiceContext();
|
||||
RpcContext.removeClientAttachment();
|
||||
}
|
||||
|
||||
RpcContext.removeServerContext();
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
// pass attachments to result
|
||||
RpcContext.getServerContext().setObjectAttachments(appResponse.getObjectAttachments());
|
||||
|
||||
removeContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
removeContext();
|
||||
}
|
||||
|
||||
private void removeContext() {
|
||||
RpcContext.removeServiceContext();
|
||||
RpcContext.removeClientAttachment();
|
||||
// server context must not be removed because user might use it on callback.
|
||||
// So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in invoke() above
|
||||
// RpcContext.removeServerContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,17 @@ package org.apache.dubbo.rpc.cluster.filter;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.protocol.AbstractInvoker;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
|
||||
public class DefaultFilterChainBuilderTest {
|
||||
|
||||
|
|
@ -38,6 +40,7 @@ public class DefaultFilterChainBuilderTest {
|
|||
// verify that no filter is built by default
|
||||
URL urlWithoutFilter = URL.valueOf("injvm://127.0.0.1/DemoService")
|
||||
.addParameter(INTERFACE_KEY, DemoService.class.getName());
|
||||
urlWithoutFilter = urlWithoutFilter.setScopeModel(ApplicationModel.defaultModel());
|
||||
AbstractInvoker<DemoService> invokerWithoutFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithoutFilter) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
|
|
@ -52,6 +55,7 @@ public class DefaultFilterChainBuilderTest {
|
|||
URL urlWithFilter = URL.valueOf("injvm://127.0.0.1/DemoService")
|
||||
.addParameter(INTERFACE_KEY, DemoService.class.getName())
|
||||
.addParameter(REFERENCE_FILTER_KEY, "log");
|
||||
urlWithFilter = urlWithFilter.setScopeModel(ApplicationModel.defaultModel());
|
||||
AbstractInvoker<DemoService> invokerWithFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithFilter) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
|
|
@ -59,8 +63,8 @@ public class DefaultFilterChainBuilderTest {
|
|||
}
|
||||
};
|
||||
invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);
|
||||
Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.FilterChainNode);
|
||||
Assertions.assertTrue(((FilterChainBuilder.FilterChainNode<?, ?, ?>) invokerAfterBuild).filter instanceof LogFilter);
|
||||
Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.CallbackRegistrationInvoker);
|
||||
Assertions.assertEquals(1, ((FilterChainBuilder.CallbackRegistrationInvoker<?, ?>) invokerAfterBuild).filters.size());
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +75,7 @@ public class DefaultFilterChainBuilderTest {
|
|||
// verify that no filter is built by default
|
||||
URL urlWithoutFilter = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
|
||||
.addParameter(INTERFACE_KEY, DemoService.class.getName());
|
||||
urlWithoutFilter = urlWithoutFilter.setScopeModel(ApplicationModel.defaultModel());
|
||||
AbstractInvoker<DemoService> invokerWithoutFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithoutFilter) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
|
|
@ -85,6 +90,7 @@ public class DefaultFilterChainBuilderTest {
|
|||
URL urlWithFilter = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
|
||||
.addParameter(INTERFACE_KEY, DemoService.class.getName())
|
||||
.addParameter(REFERENCE_FILTER_KEY, "log");
|
||||
urlWithFilter = urlWithFilter.setScopeModel(ApplicationModel.defaultModel());
|
||||
AbstractInvoker<DemoService> invokerWithFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithFilter) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
|
|
@ -92,8 +98,7 @@ public class DefaultFilterChainBuilderTest {
|
|||
}
|
||||
};
|
||||
invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);
|
||||
Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.FilterChainNode);
|
||||
Assertions.assertTrue(((FilterChainBuilder.FilterChainNode<?, ?, ?>) invokerAfterBuild).filter instanceof LogFilter);
|
||||
Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.CallbackRegistrationInvoker);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ public class FailoverClusterInvokerTest {
|
|||
}
|
||||
invokers.clear();
|
||||
MockInvoker<Demo> invoker3 = new MockInvoker<>(Demo.class, url);
|
||||
invoker3.setResult(AsyncRpcResult.newDefaultAsyncResult(null));
|
||||
invoker3.setResult(AsyncRpcResult.newDefaultAsyncResult(mock(RpcInvocation.class)));
|
||||
invokers.add(invoker3);
|
||||
dic.notify(invokers);
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.dubbo.rpc.Invocation;
|
|||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||
|
|
@ -41,8 +42,6 @@ import java.util.Map;
|
|||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.MERGER_KEY;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
|
@ -55,7 +54,7 @@ public class MergeableClusterInvokerTest {
|
|||
private Directory directory = mock(Directory.class);
|
||||
private Invoker firstInvoker = mock(Invoker.class);
|
||||
private Invoker secondInvoker = mock(Invoker.class);
|
||||
private Invocation invocation = mock(Invocation.class);
|
||||
private Invocation invocation = mock(RpcInvocation.class);
|
||||
private ModuleModel moduleModel = mock(ModuleModel.class);
|
||||
|
||||
private MergeableClusterInvoker<MenuService> mergeableClusterInvoker;
|
||||
|
|
@ -98,7 +97,7 @@ public class MergeableClusterInvokerTest {
|
|||
directory = mock(Directory.class);
|
||||
firstInvoker = mock(Invoker.class);
|
||||
secondInvoker = mock(Invoker.class);
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import org.apache.dubbo.rpc.cluster.LoadBalance;
|
|||
import org.apache.dubbo.rpc.cluster.filter.DemoService;
|
||||
import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
|
||||
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -55,13 +56,12 @@ public class AbstractClusterTest {
|
|||
2181,
|
||||
"org.apache.dubbo.registry.RegistryService",
|
||||
parameters);
|
||||
|
||||
URL consumerUrl = new ServiceConfigURL("dubbo",
|
||||
"127.0.0.1",
|
||||
20881,
|
||||
DemoService.class.getName(),
|
||||
parameters);
|
||||
|
||||
consumerUrl = consumerUrl.setScopeModel(ApplicationModel.defaultModel().getInternalModule());
|
||||
Directory<?> directory = mock(Directory.class);
|
||||
when(directory.getUrl()).thenReturn(url);
|
||||
when(directory.getConsumerUrl()).thenReturn(consumerUrl);
|
||||
|
|
@ -69,7 +69,7 @@ public class AbstractClusterTest {
|
|||
Invoker<?> invoker = demoCluster.join(directory, true);
|
||||
Assertions.assertTrue(invoker instanceof AbstractCluster.ClusterFilterInvoker);
|
||||
Assertions.assertTrue(((AbstractCluster.ClusterFilterInvoker<?>) invoker).getFilterInvoker()
|
||||
instanceof FilterChainBuilder.ClusterFilterChainNode);
|
||||
instanceof FilterChainBuilder.ClusterCallbackRegistrationInvoker);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicating unstable API, may get removed or changed in the next release.
|
||||
* Indicating unstable API, may get removed or changed in future releases.
|
||||
*/
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ import org.apache.dubbo.common.logger.LoggerFactory;
|
|||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* This is an abstraction specially customized for the sequence Dubbo retrieves properties.
|
||||
*/
|
||||
public class CompositeConfiguration implements Configuration {
|
||||
private Logger logger = LoggerFactory.getLogger(CompositeConfiguration.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(CompositeConfiguration.class);
|
||||
|
||||
/**
|
||||
* List holding all the configuration
|
||||
*/
|
||||
private List<Configuration> configList = new LinkedList<>();
|
||||
private final List<Configuration> configList = new CopyOnWriteArrayList<>();
|
||||
|
||||
//FIXME, consider change configList to SortedMap to replace this boolean status.
|
||||
private boolean dynamicIncluded;
|
||||
|
|
@ -47,15 +47,15 @@ public class CompositeConfiguration implements Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
public void setDynamicIncluded(boolean dynamicIncluded) {
|
||||
this.dynamicIncluded = dynamicIncluded;
|
||||
}
|
||||
|
||||
//FIXME, consider change configList to SortedMap to replace this boolean status.
|
||||
public boolean isDynamicIncluded() {
|
||||
return dynamicIncluded;
|
||||
}
|
||||
|
||||
public void setDynamicIncluded(boolean dynamicIncluded) {
|
||||
this.dynamicIncluded = dynamicIncluded;
|
||||
}
|
||||
|
||||
public void addConfiguration(Configuration configuration) {
|
||||
if (configList.contains(configuration)) {
|
||||
return;
|
||||
|
|
@ -80,7 +80,8 @@ public class CompositeConfiguration implements Configuration {
|
|||
return value;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error when trying to get value for key " + key + " from " + config + ", will continue to try the next one.");
|
||||
logger.error("Error when trying to get value for key " + key + " from " + config + ", " +
|
||||
"will continue to try the next one.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.config;
|
||||
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -37,7 +38,7 @@ public class ConfigurationCache {
|
|||
*/
|
||||
public String computeIfAbsent(String key, Function<String, String> function) {
|
||||
String value = cache.get(key);
|
||||
if (value == null) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
// lock free, tolerate repeat apply, will return previous value
|
||||
cache.putIfAbsent(key, function.apply(key));
|
||||
value = cache.get(key);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.ExtensionAccessor;
|
|||
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.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
|
|
@ -35,6 +36,7 @@ import java.util.LinkedHashSet;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -228,7 +230,7 @@ public class ConfigurationUtils {
|
|||
resultMap = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
if (null != configMap) {
|
||||
if (CollectionUtils.isNotEmptyMap(configMap)) {
|
||||
for(Map.Entry<String, V> entry : configMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
V val = entry.getValue();
|
||||
|
|
@ -238,8 +240,11 @@ public class ConfigurationUtils {
|
|||
|
||||
String k = key.substring(prefix.length());
|
||||
// convert camelCase/snake_case to kebab-case
|
||||
k = StringUtils.convertToSplitName(k, "-");
|
||||
resultMap.putIfAbsent(k, val);
|
||||
String newK = StringUtils.convertToSplitName(k, "-");
|
||||
resultMap.putIfAbsent(newK, val);
|
||||
if (!Objects.equals(k, newK)) {
|
||||
resultMap.putIfAbsent(k, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.config;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ public class InmemoryConfiguration implements Configuration {
|
|||
* Add a set of properties into the store
|
||||
*/
|
||||
public void addProperties(Map<String, String> properties) {
|
||||
if (properties != null) {
|
||||
if (CollectionUtils.isNotEmptyMap(properties)) {
|
||||
this.store.putAll(properties);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +67,7 @@ public class InmemoryConfiguration implements Configuration {
|
|||
* set store
|
||||
*/
|
||||
public void setProperties(Map<String, String> properties) {
|
||||
if (properties != null) {
|
||||
if (CollectionUtils.isNotEmptyMap(properties)) {
|
||||
this.store = properties;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,7 +507,17 @@ public interface CommonConstants {
|
|||
String DUBBO_INTERNAL_APPLICATION = "DUBBO_INTERNAL_APPLICATION";
|
||||
|
||||
String RETRY_TIMES_KEY = "retry-times";
|
||||
|
||||
String RETRY_PERIOD_KEY = "retry-period";
|
||||
|
||||
String SYNC_REPORT_KEY = "sync-report";
|
||||
|
||||
String CYCLE_REPORT_KEY = "cycle-report";
|
||||
|
||||
String WORKING_CLASSLOADER_KEY = "WORKING_CLASSLOADER";
|
||||
|
||||
String STAGED_CLASSLOADER_KEY = "STAGED_CLASSLOADER";
|
||||
|
||||
String PROVIDER_ASYNC_KEY = "PROVIDER_ASYNC";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,10 +61,6 @@ public interface RegistryConstants {
|
|||
|
||||
String COMPATIBLE_CONFIG_KEY = "compatible_config";
|
||||
|
||||
String REGISTRY_PUBLISH_INTERFACE_KEY = "publish-interface";
|
||||
|
||||
String REGISTRY_PUBLISH_INSTANCE_KEY = "publish-instance";
|
||||
|
||||
String REGISTER_MODE_KEY = "register-mode";
|
||||
|
||||
String DUBBO_REGISTER_MODE_DEFAULT_KEY = "dubbo.application.register-mode";
|
||||
|
|
@ -132,4 +128,6 @@ public interface RegistryConstants {
|
|||
String INIT = "INIT";
|
||||
|
||||
float DEFAULT_HASHMAP_LOAD_FACTOR = 0.75f;
|
||||
|
||||
String ENABLE_EMPTY_PROTECTION_KEY = "enable-empty-protection";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ public class ExtensionDirector implements ExtensionAccessor {
|
|||
|
||||
private final ConcurrentMap<Class<?>, ExtensionLoader<?>> extensionLoadersMap = new ConcurrentHashMap<>(64);
|
||||
private final ConcurrentMap<Class<?>, ExtensionScope> extensionScopeMap = new ConcurrentHashMap<>(64);
|
||||
private ExtensionDirector parent;
|
||||
private final ExtensionDirector parent;
|
||||
private final ExtensionScope scope;
|
||||
private List<ExtensionPostProcessor> extensionPostProcessors = new ArrayList<>();
|
||||
private ScopeModel scopeModel;
|
||||
private AtomicBoolean destroyed = new AtomicBoolean();
|
||||
private final List<ExtensionPostProcessor> extensionPostProcessors = new ArrayList<>();
|
||||
private final ScopeModel scopeModel;
|
||||
private final AtomicBoolean destroyed = new AtomicBoolean();
|
||||
|
||||
public ExtensionDirector(ExtensionDirector parent, ExtensionScope scope, ScopeModel scopeModel) {
|
||||
this.parent = parent;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
*/
|
||||
public class ActivateComparator implements Comparator<Class<?>> {
|
||||
|
||||
private ExtensionDirector extensionDirector;
|
||||
private final ExtensionDirector extensionDirector;
|
||||
private final Map<Class<?>, ActivateInfo> activateInfoMap = new ConcurrentHashMap<>();
|
||||
|
||||
public ActivateComparator(ExtensionDirector extensionDirector) {
|
||||
|
|
@ -128,9 +128,9 @@ public class ActivateComparator implements Comparator<Class<?>> {
|
|||
info.before = activate.before();
|
||||
info.after = activate.after();
|
||||
info.order = activate.order();
|
||||
} else if (clazz.isAnnotationPresent(com.alibaba.dubbo.common.extension.Activate.class)){
|
||||
} else if (clazz.isAnnotationPresent(com.alibaba.dubbo.common.extension.Activate.class)) {
|
||||
com.alibaba.dubbo.common.extension.Activate activate = clazz.getAnnotation(
|
||||
com.alibaba.dubbo.common.extension.Activate.class);
|
||||
com.alibaba.dubbo.common.extension.Activate.class);
|
||||
info.before = activate.before();
|
||||
info.after = activate.after();
|
||||
info.order = activate.order();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* 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.extension.support;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.extension.ExtensionDirector;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MultiInstanceActivateComparator implements Comparator<Class<?>> {
|
||||
|
||||
private final List<ExtensionDirector> extensionDirectors;
|
||||
private final Map<Class<?>, ActivateInfo> activateInfoMap = new ConcurrentHashMap<>();
|
||||
|
||||
public MultiInstanceActivateComparator(List<ExtensionDirector> extensionDirectors) {
|
||||
this.extensionDirectors = extensionDirectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Class o1, Class o2) {
|
||||
if (o1 == null && o2 == null) {
|
||||
return 0;
|
||||
}
|
||||
if (o1 == null) {
|
||||
return -1;
|
||||
}
|
||||
if (o2 == null) {
|
||||
return 1;
|
||||
}
|
||||
if (o1.equals(o2)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Class<?> inf = findSpi(o1);
|
||||
|
||||
ActivateInfo a1 = parseActivate(o1);
|
||||
ActivateInfo a2 = parseActivate(o2);
|
||||
|
||||
if ((a1.applicableToCompare() || a2.applicableToCompare()) && inf != null) {
|
||||
|
||||
|
||||
if (a1.applicableToCompare()) {
|
||||
String n2 = null;
|
||||
for (ExtensionDirector director : extensionDirectors) {
|
||||
ExtensionLoader<?> extensionLoader = director.getExtensionLoader(inf);
|
||||
n2 = extensionLoader.getExtensionName(o2);
|
||||
if (n2 != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a1.isLess(n2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a1.isMore(n2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a2.applicableToCompare()) {
|
||||
String n1 = null;
|
||||
for (ExtensionDirector director : extensionDirectors) {
|
||||
ExtensionLoader<?> extensionLoader = director.getExtensionLoader(inf);
|
||||
n1 = extensionLoader.getExtensionName(o1);
|
||||
if (n1 != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a2.isLess(n1)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a2.isMore(n1)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return a1.order > a2.order ? 1 : -1;
|
||||
}
|
||||
|
||||
// In order to avoid the problem of inconsistency between the loading order of two filters
|
||||
// in different loading scenarios without specifying the order attribute of the filter,
|
||||
// when the order is the same, compare its filterName
|
||||
if (a1.order > a2.order) {
|
||||
return 1;
|
||||
} else if (a1.order == a2.order) {
|
||||
return o1.getSimpleName().compareTo(o2.getSimpleName()) > 0 ? 1 : -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> findSpi(Class<?> clazz) {
|
||||
if (clazz.getInterfaces().length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Class<?> intf : clazz.getInterfaces()) {
|
||||
if (intf.isAnnotationPresent(SPI.class)) {
|
||||
return intf;
|
||||
} else {
|
||||
Class<?> result = findSpi(intf);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ActivateInfo parseActivate(Class<?> clazz) {
|
||||
ActivateInfo info = activateInfoMap.get(clazz);
|
||||
if (info != null) {
|
||||
return info;
|
||||
}
|
||||
info = new ActivateInfo();
|
||||
if (clazz.isAnnotationPresent(Activate.class)) {
|
||||
Activate activate = clazz.getAnnotation(Activate.class);
|
||||
info.before = activate.before();
|
||||
info.after = activate.after();
|
||||
info.order = activate.order();
|
||||
} else if (clazz.isAnnotationPresent(com.alibaba.dubbo.common.extension.Activate.class)) {
|
||||
com.alibaba.dubbo.common.extension.Activate activate = clazz.getAnnotation(
|
||||
com.alibaba.dubbo.common.extension.Activate.class);
|
||||
info.before = activate.before();
|
||||
info.after = activate.after();
|
||||
info.order = activate.order();
|
||||
} else {
|
||||
info.order = 0;
|
||||
}
|
||||
activateInfoMap.put(clazz, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static class ActivateInfo {
|
||||
private String[] before;
|
||||
private String[] after;
|
||||
private int order;
|
||||
|
||||
private boolean applicableToCompare() {
|
||||
return ArrayUtils.isNotEmpty(before) || ArrayUtils.isNotEmpty(after);
|
||||
}
|
||||
|
||||
private boolean isLess(String name) {
|
||||
return Arrays.asList(before).contains(name);
|
||||
}
|
||||
|
||||
private boolean isMore(String name) {
|
||||
return Arrays.asList(after).contains(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,8 +51,8 @@ import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
|
|||
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
|
||||
import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
|
||||
import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INSTANCE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
|
||||
import static org.apache.dubbo.config.Constants.DEVELOPMENT_ENVIRONMENT;
|
||||
import static org.apache.dubbo.config.Constants.PRODUCTION_ENVIRONMENT;
|
||||
import static org.apache.dubbo.config.Constants.TEST_ENVIRONMENT;
|
||||
|
|
@ -167,10 +167,6 @@ public class ApplicationConfig extends AbstractConfig {
|
|||
|
||||
private Boolean enableFileCache;
|
||||
|
||||
private Boolean publishInterface;
|
||||
|
||||
private Boolean publishInstance;
|
||||
|
||||
/**
|
||||
* The preferred protocol(name) of this application
|
||||
* convenient for places where it's hard to determine which is the preferred protocol
|
||||
|
|
@ -196,6 +192,10 @@ public class ApplicationConfig extends AbstractConfig {
|
|||
|
||||
private String startupProbe;
|
||||
|
||||
private String registerMode;
|
||||
|
||||
private Boolean enableEmptyProtection;
|
||||
|
||||
public ApplicationConfig() {
|
||||
}
|
||||
|
||||
|
|
@ -497,22 +497,22 @@ public class ApplicationConfig extends AbstractConfig {
|
|||
this.enableFileCache = enableFileCache;
|
||||
}
|
||||
|
||||
@Parameter(key = REGISTRY_PUBLISH_INTERFACE_KEY)
|
||||
public Boolean getPublishInterface() {
|
||||
return publishInterface;
|
||||
@Parameter(key = REGISTER_MODE_KEY)
|
||||
public String getRegisterMode() {
|
||||
return registerMode;
|
||||
}
|
||||
|
||||
public void setPublishInterface(Boolean publishInterface) {
|
||||
this.publishInterface = publishInterface;
|
||||
public void setRegisterMode(String registerMode) {
|
||||
this.registerMode = registerMode;
|
||||
}
|
||||
|
||||
@Parameter(key = REGISTRY_PUBLISH_INSTANCE_KEY)
|
||||
public Boolean getPublishInstance() {
|
||||
return publishInstance;
|
||||
@Parameter(key = ENABLE_EMPTY_PROTECTION_KEY)
|
||||
public Boolean getEnableEmptyProtection() {
|
||||
return enableEmptyProtection;
|
||||
}
|
||||
|
||||
public void setPublishInstance(Boolean publishInstance) {
|
||||
this.publishInstance = publishInstance;
|
||||
public void setEnableEmptyProtection(Boolean enableEmptyProtection) {
|
||||
this.enableEmptyProtection = enableEmptyProtection;
|
||||
}
|
||||
|
||||
@Parameter(excluded = true, key = APPLICATION_PROTOCOL_KEY)
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ import java.util.Map;
|
|||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.EXTRA_KEYS_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INSTANCE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
|
||||
import static org.apache.dubbo.common.utils.PojoUtils.updatePropertyIfAbsent;
|
||||
|
||||
|
|
@ -180,9 +180,9 @@ public class RegistryConfig extends AbstractConfig {
|
|||
*/
|
||||
private Integer weight;
|
||||
|
||||
private Boolean publishInterface;
|
||||
private String registerMode;
|
||||
|
||||
private Boolean publishInstance;
|
||||
private Boolean enableEmptyProtection;
|
||||
|
||||
public RegistryConfig() {
|
||||
}
|
||||
|
|
@ -519,22 +519,22 @@ public class RegistryConfig extends AbstractConfig {
|
|||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Parameter(key = REGISTRY_PUBLISH_INTERFACE_KEY)
|
||||
public Boolean getPublishInterface() {
|
||||
return publishInterface;
|
||||
@Parameter(key = REGISTER_MODE_KEY)
|
||||
public String getRegisterMode() {
|
||||
return registerMode;
|
||||
}
|
||||
|
||||
public void setPublishInterface(Boolean publishInterface) {
|
||||
this.publishInterface = publishInterface;
|
||||
public void setRegisterMode(String registerMode) {
|
||||
this.registerMode = registerMode;
|
||||
}
|
||||
|
||||
@Parameter(key = REGISTRY_PUBLISH_INSTANCE_KEY)
|
||||
public Boolean getPublishInstance() {
|
||||
return publishInstance;
|
||||
@Parameter(key = ENABLE_EMPTY_PROTECTION_KEY)
|
||||
public Boolean getEnableEmptyProtection() {
|
||||
return enableEmptyProtection;
|
||||
}
|
||||
|
||||
public void setPublishInstance(Boolean publishInstance) {
|
||||
this.publishInstance = publishInstance;
|
||||
public void setEnableEmptyProtection(Boolean enableEmptyProtection) {
|
||||
this.enableEmptyProtection = enableEmptyProtection;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class ScopeModelUtil {
|
|||
return getDefaultScopeModel(type);
|
||||
}
|
||||
|
||||
private static <T>ScopeModel getDefaultScopeModel(Class<T> type) {
|
||||
private static <T> ScopeModel getDefaultScopeModel(Class<T> type) {
|
||||
SPI spi = type.getAnnotation(SPI.class);
|
||||
if (spi == null) {
|
||||
throw new IllegalArgumentException("SPI annotation not found for class: " + type.getName());
|
||||
|
|
@ -40,8 +40,9 @@ public class ScopeModelUtil {
|
|||
return ApplicationModel.defaultModel();
|
||||
case MODULE:
|
||||
return ApplicationModel.defaultModel().getDefaultModule();
|
||||
default:
|
||||
throw new IllegalStateException("Unable to get default scope model for type: " + type.getName());
|
||||
}
|
||||
throw new IllegalStateException("Unable to get default scope model for type: " + type.getName());
|
||||
}
|
||||
|
||||
public static ModuleModel getModuleModel(ScopeModel scopeModel) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
|
|||
public class FrameworkModelTest {
|
||||
@Test
|
||||
public void testInitialize() {
|
||||
FrameworkModel.destroyAll();
|
||||
FrameworkModel frameworkModel = new FrameworkModel();
|
||||
|
||||
Assertions.assertNull(frameworkModel.getParent());
|
||||
|
|
|
|||
|
|
@ -385,8 +385,9 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
|
|||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error(getIdentifier() + " refer catch error", t);
|
||||
logger.error(getIdentifier() + " refer catch error.");
|
||||
referenceCache.destroy(rc);
|
||||
throw t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,8 +110,6 @@ import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
|
|||
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
|
||||
import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
|
||||
import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INSTANCE_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PUBLISH_INTERFACE_KEY;
|
||||
import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.DEFAULT_STUB_EVENT;
|
||||
import static org.apache.dubbo.rpc.Constants.LOCAL_KEY;
|
||||
|
|
@ -177,8 +175,6 @@ public class ReferenceConfigTest {
|
|||
applicationConfig.setRegisterConsumer(false);
|
||||
applicationConfig.setRepository("repository1");
|
||||
applicationConfig.setEnableFileCache(false);
|
||||
applicationConfig.setPublishInstance(false);
|
||||
applicationConfig.setPublishInterface(false);
|
||||
applicationConfig.setProtocol("dubbo");
|
||||
applicationConfig.setMetadataServicePort(88888);
|
||||
applicationConfig.setMetadataServiceProtocol("tri");
|
||||
|
|
@ -315,11 +311,6 @@ public class ReferenceConfigTest {
|
|||
serviceMetadata.getAttachments().get("repository"));
|
||||
Assertions.assertEquals(applicationConfig.getEnableFileCache().toString(),
|
||||
serviceMetadata.getAttachments().get(REGISTRY_LOCAL_FILE_CACHE_ENABLED));
|
||||
Assertions.assertEquals(applicationConfig.getPublishInstance().toString(),
|
||||
serviceMetadata.getAttachments().get(REGISTRY_PUBLISH_INSTANCE_KEY));
|
||||
Assertions.assertEquals(applicationConfig.getPublishInterface().toString(),
|
||||
serviceMetadata.getAttachments().get(REGISTRY_PUBLISH_INTERFACE_KEY));
|
||||
Assertions.assertTrue(serviceMetadata.getAttachments().containsKey(REGISTRY_PUBLISH_INTERFACE_KEY));
|
||||
Assertions.assertEquals(applicationConfig.getMetadataServicePort().toString(),
|
||||
serviceMetadata.getAttachments().get(METADATA_SERVICE_PORT_KEY));
|
||||
Assertions.assertEquals(applicationConfig.getMetadataServiceProtocol().toString(),
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ import org.apache.dubbo.rpc.listener.ListenerExporterWrapper;
|
|||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* The abstraction of {@link ExporterListener} is to record exported exporters, which should be extended by different sub-classes.
|
||||
|
|
@ -56,12 +56,13 @@ public abstract class AbstractRegistryCenterExporterListener implements Exporter
|
|||
@Override
|
||||
public void exported(Exporter<?> exporter) throws RpcException {
|
||||
ListenerExporterWrapper listenerExporterWrapper = (ListenerExporterWrapper) exporter;
|
||||
FilterChainBuilder.FilterChainNode filterChainNode = (FilterChainBuilder.FilterChainNode) listenerExporterWrapper.getInvoker();
|
||||
if (filterChainNode == null ||
|
||||
filterChainNode.getInterface() != getInterface()) {
|
||||
FilterChainBuilder.CallbackRegistrationInvoker callbackRegistrationInvoker = (FilterChainBuilder.CallbackRegistrationInvoker) listenerExporterWrapper.getInvoker();
|
||||
if (callbackRegistrationInvoker == null ||
|
||||
callbackRegistrationInvoker.getInterface() != getInterface()) {
|
||||
return;
|
||||
}
|
||||
exportedExporters.add(exporter);
|
||||
FilterChainBuilder.CopyOfFilterChainNode filterChainNode = getFilterChainNode(callbackRegistrationInvoker);
|
||||
do {
|
||||
Filter filter = this.getFilter(filterChainNode);
|
||||
if (filter != null) {
|
||||
|
|
@ -96,7 +97,24 @@ public abstract class AbstractRegistryCenterExporterListener implements Exporter
|
|||
/**
|
||||
* Use reflection to obtain {@link Filter}
|
||||
*/
|
||||
private Filter getFilter(FilterChainBuilder.FilterChainNode filterChainNode) {
|
||||
private FilterChainBuilder.CopyOfFilterChainNode getFilterChainNode(FilterChainBuilder.CallbackRegistrationInvoker callbackRegistrationInvoker) {
|
||||
if (callbackRegistrationInvoker != null) {
|
||||
Field field = null;
|
||||
try {
|
||||
field = callbackRegistrationInvoker.getClass().getDeclaredField("filterInvoker");
|
||||
field.setAccessible(true);
|
||||
return (FilterChainBuilder.CopyOfFilterChainNode) field.get(callbackRegistrationInvoker);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use reflection to obtain {@link Filter}
|
||||
*/
|
||||
private Filter getFilter(FilterChainBuilder.CopyOfFilterChainNode filterChainNode) {
|
||||
if (filterChainNode != null) {
|
||||
Field field = null;
|
||||
try {
|
||||
|
|
@ -111,17 +129,17 @@ public abstract class AbstractRegistryCenterExporterListener implements Exporter
|
|||
}
|
||||
|
||||
/**
|
||||
* Use reflection to obtain {@link FilterChainBuilder.FilterChainNode}
|
||||
* Use reflection to obtain {@link FilterChainBuilder.CopyOfFilterChainNode}
|
||||
*/
|
||||
private FilterChainBuilder.FilterChainNode getNextNode(FilterChainBuilder.FilterChainNode filterChainNode) {
|
||||
private FilterChainBuilder.CopyOfFilterChainNode getNextNode(FilterChainBuilder.CopyOfFilterChainNode filterChainNode) {
|
||||
if (filterChainNode != null) {
|
||||
Field field = null;
|
||||
try {
|
||||
field = filterChainNode.getClass().getDeclaredField("nextNode");
|
||||
field.setAccessible(true);
|
||||
Object object = field.get(filterChainNode);
|
||||
if (object instanceof FilterChainBuilder.FilterChainNode) {
|
||||
return (FilterChainBuilder.FilterChainNode) object;
|
||||
if (object instanceof FilterChainBuilder.CopyOfFilterChainNode) {
|
||||
return (FilterChainBuilder.CopyOfFilterChainNode) object;
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
// ignore
|
||||
|
|
|
|||
|
|
@ -152,6 +152,11 @@
|
|||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
</exclusion>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
|
|
|||
|
|
@ -420,10 +420,16 @@
|
|||
<xsd:documentation><![CDATA[ Register consumer instance or not, default false. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="publish-interface" type="xsd:boolean">
|
||||
<xsd:attribute name="register-mode" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Publish interface level url to registry, default false. ]]></xsd:documentation>
|
||||
<![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="enable-empty-protection" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="protocol" type="xsd:string">
|
||||
|
|
@ -639,6 +645,18 @@
|
|||
<xsd:documentation><![CDATA[ weight of registry. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="register-mode" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="enable-empty-protection" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="metadataReportType">
|
||||
|
|
|
|||
|
|
@ -427,10 +427,16 @@
|
|||
<xsd:documentation><![CDATA[ Register consumer instance or not, default false. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="publish-interface" type="xsd:boolean">
|
||||
<xsd:attribute name="register-mode" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Publish interface level url to registry, default true. ]]></xsd:documentation>
|
||||
<![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="enable-empty-protection" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="protocol" type="xsd:string">
|
||||
|
|
@ -674,16 +680,16 @@
|
|||
<xsd:documentation><![CDATA[ weight of registry. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="publish-interface" type="xsd:boolean">
|
||||
<xsd:attribute name="register-mode" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Publish interface level url to registry, default true. ]]></xsd:documentation>
|
||||
<![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="publish-instance" type="xsd:boolean">
|
||||
<xsd:attribute name="enable-empty-protection" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ Publish instance level url to registry, default true. ]]></xsd:documentation>
|
||||
<![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
|
|
|||
|
|
@ -102,6 +102,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -102,6 +102,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@
|
|||
<jcl_version>1.2</jcl_version>
|
||||
<log4j_version>1.2.16</log4j_version>
|
||||
<logback_version>1.2.2</logback_version>
|
||||
<log4j2_version>2.11.1</log4j2_version>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<log4j2_version>2.17.0</log4j2_version>
|
||||
<commons_io_version>2.6</commons_io_version>
|
||||
|
||||
<embedded_redis_version>0.10.0</embedded_redis_version>
|
||||
|
|
@ -168,7 +169,7 @@
|
|||
<mortbay_jetty_version>6.1.26</mortbay_jetty_version>
|
||||
<portlet_version>2.0</portlet_version>
|
||||
<maven_flatten_version>1.1.0</maven_flatten_version>
|
||||
<revision>3.0.5-SNAPSHOT</revision>
|
||||
<revision>3.0.5</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.5-SNAPSHOT</revision>
|
||||
<revision>3.0.5</revision>
|
||||
<maven_flatten_version>1.1.0</maven_flatten_version>
|
||||
</properties>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ import org.apache.dubbo.common.constants.CommonConstants;
|
|||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
|
@ -43,7 +45,7 @@ class ProviderAuthFilterTest {
|
|||
void testAuthDisabled() {
|
||||
URL url = mock(URL.class);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(ApplicationModel.defaultModel());
|
||||
providerAuthFilter.invoke(invoker, invocation);
|
||||
|
|
@ -58,7 +60,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(CommonConstants.APPLICATION_KEY, "test")
|
||||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(ApplicationModel.defaultModel());
|
||||
providerAuthFilter.invoke(invoker, invocation);
|
||||
|
|
@ -74,7 +76,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(CommonConstants.APPLICATION_KEY, "test")
|
||||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(null);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
|
||||
|
|
@ -92,7 +94,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(CommonConstants.APPLICATION_KEY, "test")
|
||||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(null);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
|
||||
|
|
@ -107,7 +109,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(CommonConstants.APPLICATION_KEY, "test-provider")
|
||||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invocation.getObjectAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn("dubbo");
|
||||
when(invocation.getObjectAttachment(Constants.AK_KEY)).thenReturn("ak");
|
||||
when(invocation.getObjectAttachment(CommonConstants.CONSUMER)).thenReturn("test-consumer");
|
||||
|
|
@ -135,7 +137,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invocation.getObjectAttachment(Constants.AK_KEY)).thenReturn("ak");
|
||||
when(invocation.getObjectAttachment(CommonConstants.CONSUMER)).thenReturn("test-consumer");
|
||||
when(invocation.getObjectAttachment(Constants.REQUEST_TIMESTAMP_KEY)).thenReturn(currentTimeMillis);
|
||||
|
|
@ -168,7 +170,7 @@ class ProviderAuthFilterTest {
|
|||
.addParameter(CommonConstants.APPLICATION_KEY, "test-provider")
|
||||
.addParameter(Constants.SERVICE_AUTH, true);
|
||||
Invoker invoker = mock(Invoker.class);
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
when(invocation.getAttachment(Constants.AK_KEY)).thenReturn("ak");
|
||||
when(invocation.getAttachment(CommonConstants.CONSUMER)).thenReturn("test-consumer");
|
||||
when(invocation.getAttachment(Constants.REQUEST_TIMESTAMP_KEY)).thenReturn(String.valueOf(currentTimeMillis));
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import org.apache.dubbo.metadata.MetadataInfo;
|
|||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceModel;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
|
@ -496,11 +495,6 @@ public class InstanceAddressURL extends URL {
|
|||
return this.instance.getMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopeModel getScopeModel() {
|
||||
return RpcContext.getServiceContext().getConsumerUrl().getScopeModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameworkModel getOrDefaultFrameworkModel() {
|
||||
return instance.getOrDefaultApplicationModel().getFrameworkModel();
|
||||
|
|
|
|||
|
|
@ -198,17 +198,18 @@ public class ServiceDiscoveryRegistryDirectory<T> extends DynamicDirectory<T> {
|
|||
}
|
||||
|
||||
private void refreshInvoker(List<URL> invokerUrls) {
|
||||
Assert.notNull(invokerUrls, "invokerUrls should not be null, use empty url list to clear address.");
|
||||
Assert.notNull(invokerUrls, "invokerUrls should not be null, use EMPTY url to clear current addresses.");
|
||||
this.originalUrls = invokerUrls;
|
||||
|
||||
if (invokerUrls.size() == 0) {
|
||||
logger.info("Received empty url list...");
|
||||
if (invokerUrls.size() == 1 && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
|
||||
logger.warn("Received url with EMPTY protocol, will clear all available addresses.");
|
||||
this.forbidden = true; // Forbid to access
|
||||
routerChain.setInvokers(BitList.emptyList());
|
||||
destroyAllInvokers(); // Close all invokers
|
||||
} else {
|
||||
this.forbidden = false; // Allow accessing
|
||||
if (CollectionUtils.isEmpty(invokerUrls)) {
|
||||
logger.warn("Received empty url list, will ignore for protection purpose.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.dubbo.registry.client.event.listener;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.URLBuilder;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
|
|
@ -56,6 +57,8 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;
|
||||
import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision;
|
||||
|
||||
|
|
@ -418,7 +421,7 @@ public class ServiceInstancesChangedListener {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
urls.add(i.toURL());
|
||||
urls.add(i.toURL().setScopeModel(i.getApplicationModel()));
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
|
|
@ -443,6 +446,14 @@ public class ServiceInstancesChangedListener {
|
|||
if (urls == null) {
|
||||
urls = Collections.emptyList();
|
||||
}
|
||||
boolean emptyProtectionEnabled = serviceDiscovery.getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, true);
|
||||
if (CollectionUtils.isEmpty(urls) && !emptyProtectionEnabled) {
|
||||
// notice that the service of this.url may not be the same as notify listener.
|
||||
URL empty = URLBuilder.from(this.url)
|
||||
.setProtocol(EMPTY_PROTOCOL)
|
||||
.build();
|
||||
urls.add(empty);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> {
|
|||
// use local reference to avoid NPE as this.cachedInvokerUrls will be set null by destroyAllInvokers().
|
||||
Set<URL> localCachedInvokerUrls = this.cachedInvokerUrls;
|
||||
if (invokerUrls.isEmpty() && localCachedInvokerUrls != null) {
|
||||
logger.warn("Service" + serviceKey + " received empty address list with no EMPTY protocol set, trigger empty protection.");
|
||||
invokerUrls.addAll(localCachedInvokerUrls);
|
||||
} else {
|
||||
localCachedInvokerUrls = new HashSet<>();
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_SEPARATOR_ENCODED;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
|
||||
|
||||
/**
|
||||
|
|
@ -185,11 +186,16 @@ public abstract class CacheableFailbackRegistry extends FailbackRegistry {
|
|||
if (urls.isEmpty()) {
|
||||
int i = path.lastIndexOf(PATH_SEPARATOR);
|
||||
String category = i < 0 ? path : path.substring(i + 1);
|
||||
URL empty = URLBuilder.from(consumer)
|
||||
if (!PROVIDERS_CATEGORY.equals(category) || !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, true)) {
|
||||
if (PROVIDERS_CATEGORY.equals(category)) {
|
||||
logger.warn("Service " + consumer.getServiceKey() + " received empty address list and empty protection is disabled, will clear current available addresses");
|
||||
}
|
||||
URL empty = URLBuilder.from(consumer)
|
||||
.setProtocol(EMPTY_PROTOCOL)
|
||||
.addParameter(CATEGORY_KEY, category)
|
||||
.build();
|
||||
urls.add(empty);
|
||||
urls.add(empty);
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
|
|
|
|||
|
|
@ -18,14 +18,20 @@ package org.apache.dubbo.registry;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.URLStrParser;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class CacheableFailbackRegistryTest {
|
||||
|
|
@ -34,6 +40,9 @@ public class CacheableFailbackRegistryTest {
|
|||
static URL serviceUrl;
|
||||
static URL registryUrl;
|
||||
static String urlStr;
|
||||
static String urlStr2;
|
||||
static String urlStr3;
|
||||
|
||||
MockCacheableRegistryImpl registry;
|
||||
|
||||
@BeforeAll
|
||||
|
|
@ -49,6 +58,8 @@ public class CacheableFailbackRegistryTest {
|
|||
serviceUrl = URL.valueOf("dubbo://127.0.0.1/org.apache.dubbo.test.DemoService?category=providers");
|
||||
registryUrl = URL.valueOf("http://1.2.3.4:9090/registry?check=false&file=N/A");
|
||||
urlStr = "dubbo%3A%2F%2F172.19.4.113%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000";
|
||||
urlStr2 = "dubbo%3A%2F%2F172.19.4.114%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000";
|
||||
urlStr3 = "dubbo%3A%2F%2F172.19.4.115%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000";
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
@ -181,4 +192,53 @@ public class CacheableFailbackRegistryTest {
|
|||
assertEquals(0, registry.getStringParam().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyProtection() {
|
||||
final AtomicReference<Integer> resCount = new AtomicReference<>(0);
|
||||
final AtomicReference<List<URL>> currentUrls = new AtomicReference<>();
|
||||
final List<URL> EMPTY_LIST = new ArrayList<>();
|
||||
|
||||
registry = new MockCacheableRegistryImpl(registryUrl);
|
||||
URL url = URLStrParser.parseEncodedStr(urlStr);
|
||||
URL url2 = URLStrParser.parseEncodedStr(urlStr2);
|
||||
URL url3 = URLStrParser.parseEncodedStr(urlStr3);
|
||||
|
||||
NotifyListener listener = urls -> {
|
||||
if (CollectionUtils.isEmpty(urls)) {
|
||||
// do nothing
|
||||
} else if (urls.size() == 1 && urls.get(0).getProtocol().equals(EMPTY_PROTOCOL)) {
|
||||
resCount.set(0);
|
||||
currentUrls.set(EMPTY_LIST);
|
||||
} else {
|
||||
resCount.set(urls.size());
|
||||
currentUrls.set(urls);
|
||||
}
|
||||
};
|
||||
|
||||
registry.addChildren(url);
|
||||
registry.addChildren(url2);
|
||||
registry.addChildren(url3);
|
||||
|
||||
registry.subscribe(serviceUrl, listener);
|
||||
assertEquals(3, resCount.get());
|
||||
registry.removeChildren(url);
|
||||
assertEquals(2, resCount.get());
|
||||
registry.clearChildren();
|
||||
assertEquals(2, resCount.get());
|
||||
|
||||
URL emptyRegistryURL = registryUrl.addParameter(ENABLE_EMPTY_PROTECTION_KEY, false);
|
||||
MockCacheableRegistryImpl emptyRegistry = new MockCacheableRegistryImpl(emptyRegistryURL);
|
||||
|
||||
emptyRegistry.addChildren(url);
|
||||
emptyRegistry.addChildren(url2);
|
||||
|
||||
emptyRegistry.subscribe(serviceUrl, listener);
|
||||
assertEquals(2, resCount.get());
|
||||
emptyRegistry.clearChildren();
|
||||
assertEquals(0, currentUrls.get().size());
|
||||
assertEquals(EMPTY_LIST, currentUrls.get());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import java.util.concurrent.Semaphore;
|
|||
public class MockCacheableRegistryImpl extends CacheableFailbackRegistry {
|
||||
|
||||
private final List<String> children = new ArrayList<>();
|
||||
NotifyListener listener;
|
||||
|
||||
public MockCacheableRegistryImpl(URL url) {
|
||||
super(url);
|
||||
|
|
@ -71,6 +72,7 @@ public class MockCacheableRegistryImpl extends CacheableFailbackRegistry {
|
|||
}
|
||||
}
|
||||
listener.notify(res);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -87,12 +89,22 @@ public class MockCacheableRegistryImpl extends CacheableFailbackRegistry {
|
|||
children.add(URL.encode(url.toFullString()));
|
||||
}
|
||||
|
||||
public void removeChildren(URL url) {
|
||||
children.remove(URL.encode(url.toFullString()));
|
||||
if (listener != null) {
|
||||
listener.notify(toUrlsWithEmpty(getUrl(), "providers", children));
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void clearChildren() {
|
||||
children.clear();
|
||||
if (listener != null) {
|
||||
listener.notify(toUrlsWithEmpty(getUrl(), "providers", children));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<URL, Map<String, ServiceAddressURL>> getStringUrls() {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
|
|||
import org.apache.dubbo.registry.client.metadata.MetadataUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -99,6 +100,7 @@ public class ServiceInstancesChangedListenerTest {
|
|||
static String service3 = "org.apache.dubbo.demo.DemoService3";
|
||||
|
||||
static URL consumerURL = URL.valueOf("dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService?registry_cluster=default");
|
||||
static URL registryURL = URL.valueOf("dubbo://127.0.0.1:2181/org.apache.dubbo.demo.RegistryService");
|
||||
|
||||
static MetadataInfo metadataInfo_111;
|
||||
static MetadataInfo metadataInfo_222;
|
||||
|
|
@ -155,6 +157,7 @@ public class ServiceInstancesChangedListenerTest {
|
|||
Mockito.doThrow(IllegalStateException.class).when(metadataService).getMetadataInfo("444");
|
||||
|
||||
serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
|
||||
Mockito.doReturn(registryURL).when(serviceDiscovery).getUrl();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
@ -328,7 +331,7 @@ public class ServiceInstancesChangedListenerTest {
|
|||
Assertions.assertEquals(0, revisionToMetadata_app2.size());
|
||||
|
||||
assertTrue(isEmpty(listener.getAddresses(service1 + ":dubbo", consumerURL)));
|
||||
assertTrue(isEmpty(listener.getAddresses(service2+ ":dubbo", consumerURL)));
|
||||
assertTrue(isEmpty(listener.getAddresses(service2 + ":dubbo", consumerURL)));
|
||||
assertTrue(isEmpty(listener.getAddresses(service3 + ":dubbo", consumerURL)));
|
||||
}
|
||||
}
|
||||
|
|
@ -511,7 +514,7 @@ public class ServiceInstancesChangedListenerTest {
|
|||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
|
||||
for (Object obj : rawURls) {
|
||||
String rawURL = (String)obj;
|
||||
String rawURL = (String) obj;
|
||||
DefaultServiceInstance instance = new DefaultServiceInstance();
|
||||
final URL dubboUrl = URL.valueOf(rawURL);
|
||||
instance.setRawAddress(rawURL);
|
||||
|
|
@ -520,6 +523,7 @@ public class ServiceInstancesChangedListenerTest {
|
|||
instance.setHealthy(true);
|
||||
instance.setPort(dubboUrl.getPort());
|
||||
instance.setRegistryCluster("default");
|
||||
instance.setApplicationModel(ApplicationModel.defaultModel());
|
||||
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public class MultipleRegistry extends AbstractRegistry {
|
|||
serviceRegistries.put(tmpUrl, registryMap.get(tmpUrl));
|
||||
continue;
|
||||
}
|
||||
final URL registryUrl = URL.valueOf(tmpUrl).addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, "true"));
|
||||
final URL registryUrl = URL.valueOf(tmpUrl).addParametersIfAbsent(url.getParameters()).addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, "true"));
|
||||
Registry registry = registryFactory.getRegistry(registryUrl);
|
||||
registryMap.put(tmpUrl, registry);
|
||||
serviceRegistries.put(tmpUrl, registry);
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ import org.apache.dubbo.registry.Registry;
|
|||
import org.apache.dubbo.registry.zookeeper.ZookeeperRegistry;
|
||||
import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
|
||||
import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ public class MultipleRegistry2S2RTest {
|
|||
zookeeperConnectionAddress1 = System.getProperty("zookeeper.connection.address.1");
|
||||
zookeeperConnectionAddress2 = System.getProperty("zookeeper.connection.address.2");
|
||||
|
||||
URL url = URL.valueOf("multiple://127.0.0.1?application=vic&" +
|
||||
URL url = URL.valueOf("multiple://127.0.0.1?application=vic&enable-empty-protection=false&" +
|
||||
MultipleRegistry.REGISTRY_FOR_SERVICE + "=" + zookeeperConnectionAddress1 + "," + zookeeperConnectionAddress2 + "&"
|
||||
+ MultipleRegistry.REGISTRY_FOR_REFERENCE + "=" + zookeeperConnectionAddress1 + "," + zookeeperConnectionAddress2);
|
||||
multipleRegistry = (MultipleRegistry) new MultipleRegistryFactory().createRegistry(url);
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@ import java.util.LinkedHashSet;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
|
||||
|
|
@ -70,6 +70,7 @@ import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_
|
|||
import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
|
||||
import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
|
||||
|
|
@ -497,7 +498,9 @@ public class NacosRegistry extends FailbackRegistry {
|
|||
|
||||
private List<URL> toUrlWithEmpty(URL consumerURL, Collection<Instance> instances) {
|
||||
List<URL> urls = buildURLs(consumerURL, instances);
|
||||
if (urls.size() == 0) {
|
||||
// Nacos does not support configurators and routers from registry, so all notifications are of providers type.
|
||||
if (urls.size() == 0 && !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, true)) {
|
||||
logger.warn("Received empty url address list and empty protection is disabled, will clear current available addresses");
|
||||
URL empty = URLBuilder.from(consumerURL)
|
||||
.setProtocol(EMPTY_PROTOCOL)
|
||||
.addParameter(CATEGORY_KEY, DEFAULT_CATEGORY)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.apache.dubbo.common.Resetable;
|
|||
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.StringUtils;
|
||||
import org.apache.dubbo.remoting.ChannelHandler;
|
||||
import org.apache.dubbo.remoting.Codec;
|
||||
import org.apache.dubbo.remoting.Codec2;
|
||||
|
|
@ -47,13 +48,17 @@ public abstract class AbstractEndpoint extends AbstractPeer implements Resetable
|
|||
}
|
||||
|
||||
protected static Codec2 getChannelCodec(URL url) {
|
||||
String codecName = url.getProtocol(); // codec extension name must stay the same with protocol name
|
||||
String codecName = url.getParameter(Constants.CODEC_KEY);
|
||||
if (StringUtils.isEmpty(codecName)) {
|
||||
// codec extension name must stay the same with protocol name
|
||||
codecName = url.getProtocol();
|
||||
}
|
||||
FrameworkModel frameworkModel = getFrameworkModel(url.getScopeModel());
|
||||
if (frameworkModel.getExtensionLoader(Codec2.class).hasExtension(codecName)) {
|
||||
return frameworkModel.getExtensionLoader(Codec2.class).getExtension(codecName);
|
||||
} else {
|
||||
return new CodecAdapter(frameworkModel.getExtensionLoader(Codec.class)
|
||||
.getExtension(codecName));
|
||||
.getExtension(codecName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +66,7 @@ public abstract class AbstractEndpoint extends AbstractPeer implements Resetable
|
|||
public void reset(URL url) {
|
||||
if (isClosed()) {
|
||||
throw new IllegalStateException("Failed to reset parameters "
|
||||
+ url + ", cause: Channel closed. channel: " + getLocalAddress());
|
||||
+ url + ", cause: Channel closed. channel: " + getLocalAddress());
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ public class HeartbeatHandlerTest {
|
|||
public void testServerHeartbeat() throws Exception {
|
||||
FakeChannelHandlers.resetChannelHandlers();
|
||||
URL serverURL = URL.valueOf("telnet://localhost:" + NetUtils.getAvailablePort(56780))
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3")
|
||||
.addParameter(Constants.HEARTBEAT_KEY, 1000);
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3")
|
||||
.addParameter(Constants.HEARTBEAT_KEY, 1000);
|
||||
CountDownLatch connect = new CountDownLatch(1);
|
||||
CountDownLatch disconnect = new CountDownLatch(1);
|
||||
TestHeartbeatHandler handler = new TestHeartbeatHandler(connect, disconnect);
|
||||
|
|
@ -82,6 +82,7 @@ public class HeartbeatHandlerTest {
|
|||
// Let the client not reply to the heartbeat, and turn off automatic reconnect to simulate the client dropped.
|
||||
serverURL = serverURL.addParameter(Constants.HEARTBEAT_KEY, 600 * 1000);
|
||||
serverURL = serverURL.addParameter(Constants.RECONNECT_KEY, false);
|
||||
serverURL = serverURL.addParameter(Constants.CODEC_KEY, "telnet");
|
||||
|
||||
client = Exchangers.connect(serverURL);
|
||||
disconnect.await();
|
||||
|
|
@ -92,9 +93,10 @@ public class HeartbeatHandlerTest {
|
|||
@Test
|
||||
public void testHeartbeat() throws Exception {
|
||||
URL serverURL = URL.valueOf("telnet://localhost:" + NetUtils.getAvailablePort(56785))
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3")
|
||||
.addParameter(Constants.HEARTBEAT_KEY, 1000);
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3")
|
||||
.addParameter(Constants.HEARTBEAT_KEY, 1000)
|
||||
.addParameter(Constants.CODEC_KEY, "telnet");
|
||||
CountDownLatch connect = new CountDownLatch(1);
|
||||
CountDownLatch disconnect = new CountDownLatch(1);
|
||||
TestHeartbeatHandler handler = new TestHeartbeatHandler(connect, disconnect);
|
||||
|
|
@ -113,8 +115,9 @@ public class HeartbeatHandlerTest {
|
|||
public void testClientHeartbeat() throws Exception {
|
||||
FakeChannelHandlers.setTestingChannelHandlers();
|
||||
URL serverURL = URL.valueOf("telnet://localhost:" + NetUtils.getAvailablePort(56790))
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3");
|
||||
.addParameter(Constants.EXCHANGER_KEY, HeaderExchanger.NAME)
|
||||
.addParameter(Constants.TRANSPORTER_KEY, "netty3")
|
||||
.addParameter(Constants.CODEC_KEY, "telnet");
|
||||
CountDownLatch connect = new CountDownLatch(1);
|
||||
CountDownLatch disconnect = new CountDownLatch(1);
|
||||
TestHeartbeatHandler handler = new TestHeartbeatHandler(connect, disconnect);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class ClientReconnectTest {
|
|||
|
||||
|
||||
public Client startClient(int port, int heartbeat) throws RemotingException {
|
||||
final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&client=netty3&" +
|
||||
final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&codec=exchange&client=netty3&" +
|
||||
Constants.HEARTBEAT_KEY + "=" + heartbeat;
|
||||
return Exchangers.connect(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class NettyClientTest {
|
|||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
server = Exchangers.bind(URL.valueOf("exchange://localhost:" + port + "?server=netty3"), new TelnetServerHandler());
|
||||
server = Exchangers.bind(URL.valueOf("exchange://localhost:" + port + "?server=netty3&codec=exchange"), new TelnetServerHandler());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
|
@ -53,7 +53,7 @@ public class NettyClientTest {
|
|||
}
|
||||
|
||||
public static void main(String[] args) throws RemotingException, InterruptedException {
|
||||
ExchangeChannel client = Exchangers.connect(URL.valueOf("exchange://10.20.153.10:20880?client=netty3&heartbeat=1000"));
|
||||
ExchangeChannel client = Exchangers.connect(URL.valueOf("exchange://10.20.153.10:20880?client=netty3&heartbeat=1000&codec=exchange"));
|
||||
Thread.sleep(60 * 1000 * 50);
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ public class NettyClientTest {
|
|||
public void testClientClose() throws Exception {
|
||||
List<ExchangeChannel> clients = new ArrayList<ExchangeChannel>(100);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ExchangeChannel client = Exchangers.connect(URL.valueOf("exchange://localhost:" + port + "?client=netty3"));
|
||||
ExchangeChannel client = Exchangers.connect(URL.valueOf("exchange://localhost:" + port + "?client=netty3&codec=exchange"));
|
||||
Thread.sleep(5);
|
||||
clients.add(client);
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ public class NettyClientTest {
|
|||
@Test
|
||||
public void testServerClose() throws Exception {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
RemotingServer aServer = Exchangers.bind(URL.valueOf("exchange://localhost:" + NetUtils.getAvailablePort(6000) + "?server=netty3"), new TelnetServerHandler());
|
||||
RemotingServer aServer = Exchangers.bind(URL.valueOf("exchange://localhost:" + NetUtils.getAvailablePort(6000) + "?server=netty3&codec=exchange"), new TelnetServerHandler());
|
||||
aServer.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ public class NettyClientToServerTest extends ClientToServerTest {
|
|||
|
||||
protected ExchangeServer newServer(int port, Replier<?> receiver) throws RemotingException {
|
||||
// add heartbeat cycle to avoid unstable ut.
|
||||
URL url = URL.valueOf("exchange://localhost:" + port + "?server=netty3");
|
||||
URL url = URL.valueOf("exchange://localhost:" + port + "?server=netty3&codec=exchange");
|
||||
url = url.addParameter(Constants.HEARTBEAT_KEY, 600 * 1000);
|
||||
return Exchangers.bind(url, receiver);
|
||||
}
|
||||
|
||||
protected ExchangeChannel newClient(int port) throws RemotingException {
|
||||
// add heartbeat cycle to avoid unstable ut.
|
||||
URL url = URL.valueOf("exchange://localhost:" + port + "?client=netty3&timeout=3000");
|
||||
URL url = URL.valueOf("exchange://localhost:" + port + "?client=netty3&timeout=3000&codec=exchange");
|
||||
url = url.addParameter(Constants.HEARTBEAT_KEY, 600 * 1000);
|
||||
return Exchangers.connect(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ public class NettyStringTest {
|
|||
//int port = 10001;
|
||||
int port = NetUtils.getAvailablePort();
|
||||
System.out.println(port);
|
||||
server = Exchangers.bind(URL.valueOf("telnet://0.0.0.0:" + port + "?server=netty3"), new TelnetServerHandler());
|
||||
client = Exchangers.connect(URL.valueOf("telnet://127.0.0.1:" + port + "?client=netty3"), new TelnetClientHandler());
|
||||
server = Exchangers.bind(URL.valueOf("telnet://0.0.0.0:" + port + "?server=netty3&codec=telnet"), new TelnetServerHandler());
|
||||
client = Exchangers.connect(URL.valueOf("telnet://127.0.0.1:" + port + "?client=netty3&codec=telnet"), new TelnetClientHandler());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ public class ThreadNameTest {
|
|||
@BeforeEach
|
||||
public void before() throws Exception {
|
||||
int port = NetUtils.getAvailablePort(20880 + new Random().nextInt(10000));
|
||||
serverURL = URL.valueOf("telnet://localhost?side=provider")
|
||||
serverURL = URL.valueOf("telnet://localhost?side=provider&codec=telnet")
|
||||
.setPort(port)
|
||||
.setScopeModel(ApplicationModel.defaultModel());
|
||||
clientURL = URL.valueOf("telnet://localhost?side=consumer")
|
||||
clientURL = URL.valueOf("telnet://localhost?side=consumer&codec=telnet")
|
||||
.setPort(port)
|
||||
.setScopeModel(ApplicationModel.defaultModel());
|
||||
|
||||
|
|
|
|||
|
|
@ -74,4 +74,50 @@ public interface AsyncContext {
|
|||
* </code>
|
||||
*/
|
||||
void signalContextSwitch();
|
||||
|
||||
/**
|
||||
* Reset Context is not necessary. Only reset context after result was write back if it is necessary.
|
||||
*
|
||||
* <code>
|
||||
* public class AsyncServiceImpl implements AsyncService {
|
||||
* public String sayHello(String name) {
|
||||
* final AsyncContext asyncContext = RpcContext.startAsync();
|
||||
* new Thread(() -> {
|
||||
* <p>
|
||||
* // the right place to use this method
|
||||
* asyncContext.signalContextSwitch();
|
||||
* <p>
|
||||
* try {
|
||||
* Thread.sleep(500);
|
||||
* } catch (InterruptedException e) {
|
||||
* e.printStackTrace();
|
||||
* }
|
||||
* asyncContext.write("Hello " + name + ", response from provider.");
|
||||
* // only reset after asyncContext.write()
|
||||
* asyncContext.resetContext();
|
||||
* }).start();
|
||||
* return null;
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* <code>
|
||||
* public class AsyncServiceImpl implements AsyncService {
|
||||
* public CompletableFuture sayHello(String name) {
|
||||
* CompletableFuture future = new CompletableFuture();
|
||||
* final AsyncContext asyncContext = RpcContext.startAsync();
|
||||
* new Thread(() -> {
|
||||
* // the right place to use this method
|
||||
* asyncContext.signalContextSwitch();
|
||||
* // some operations...
|
||||
* future.complete();
|
||||
* // only reset after future.complete()
|
||||
* asyncContext.resetContext();
|
||||
* }).start();
|
||||
* return future;
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
void resetContext();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,13 @@ public class AsyncContextImpl implements AsyncContext {
|
|||
|
||||
private CompletableFuture<Object> future;
|
||||
|
||||
private RpcContextAttachment storedContext;
|
||||
private RpcContextAttachment storedServerContext;
|
||||
private final RpcContext.RestoreContext restoreContext;
|
||||
private final ClassLoader restoreClassLoader;
|
||||
private ClassLoader stagedClassLoader;
|
||||
|
||||
public AsyncContextImpl() {
|
||||
this.storedContext = RpcContext.getClientAttachment();
|
||||
this.storedServerContext = RpcContext.getServerContext();
|
||||
restoreContext = RpcContext.storeContext();
|
||||
restoreClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -67,9 +68,19 @@ public class AsyncContextImpl implements AsyncContext {
|
|||
|
||||
@Override
|
||||
public void signalContextSwitch() {
|
||||
RpcContext.restoreContext(storedContext);
|
||||
RpcContext.restoreServerContext(storedServerContext);
|
||||
// Restore any other contexts in here if necessary.
|
||||
RpcContext.restoreContext(restoreContext);
|
||||
if (restoreClassLoader != null) {
|
||||
stagedClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(restoreClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetContext() {
|
||||
RpcContext.removeContext();
|
||||
if (stagedClassLoader != null) {
|
||||
Thread.currentThread().setContextClassLoader(restoreClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Object> getInternalFuture() {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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.rpc.model.ConsumerMethodModel;
|
||||
import org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
|
@ -30,6 +31,7 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_ASYNC_KEY;
|
||||
import static org.apache.dubbo.common.utils.ReflectUtils.defaultReturn;
|
||||
|
||||
/**
|
||||
|
|
@ -51,21 +53,27 @@ public class AsyncRpcResult implements Result {
|
|||
|
||||
/**
|
||||
* RpcContext may already have been changed when callback happens, it happens when the same thread is used to execute another RPC call.
|
||||
* So we should keep the reference of current RpcContext instance and restore it before callback being executed.
|
||||
* So we should keep the copy of current RpcContext instance and restore it before callback being executed.
|
||||
*/
|
||||
private RpcContextAttachment storedContext;
|
||||
private RpcContextAttachment storedServerContext;
|
||||
private RpcContext.RestoreContext storedContext;
|
||||
|
||||
private Executor executor;
|
||||
|
||||
private Invocation invocation;
|
||||
private final boolean async;
|
||||
|
||||
private CompletableFuture<AppResponse> responseFuture;
|
||||
|
||||
public AsyncRpcResult(CompletableFuture<AppResponse> future, Invocation invocation) {
|
||||
this.responseFuture = future;
|
||||
this.invocation = invocation;
|
||||
this.storedContext = RpcContext.getClientAttachment();
|
||||
this.storedServerContext = RpcContext.getServerContext();
|
||||
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
|
||||
if ((rpcInvocation.get(PROVIDER_ASYNC_KEY) != null || InvokeMode.SYNC != rpcInvocation.getInvokeMode()) && !future.isDone()) {
|
||||
async = true;
|
||||
this.storedContext = RpcContext.clearAndStoreContext();
|
||||
} else {
|
||||
async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -193,10 +201,15 @@ public class AsyncRpcResult implements Result {
|
|||
|
||||
public Result whenCompleteWithContext(BiConsumer<Result, Throwable> fn) {
|
||||
this.responseFuture = this.responseFuture.whenComplete((v, t) -> {
|
||||
beforeContext.accept(v, t);
|
||||
if (async) {
|
||||
RpcContext.restoreContext(storedContext);
|
||||
}
|
||||
fn.accept(v, t);
|
||||
afterContext.accept(v, t);
|
||||
});
|
||||
|
||||
// Necessary! update future in context, see https://github.com/apache/dubbo/issues/9461
|
||||
RpcContext.getServiceContext().setFuture(new FutureAdapter<>(this.responseFuture));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -280,24 +293,6 @@ public class AsyncRpcResult implements Result {
|
|||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* tmp context to use when the thread switch to Dubbo thread.
|
||||
*/
|
||||
private RpcContextAttachment tmpContext;
|
||||
|
||||
private RpcContextAttachment tmpServerContext;
|
||||
private BiConsumer<Result, Throwable> beforeContext = (appResponse, t) -> {
|
||||
tmpContext = RpcContext.getClientAttachment();
|
||||
tmpServerContext = RpcContext.getServerContext();
|
||||
RpcContext.restoreContext(storedContext);
|
||||
RpcContext.restoreServerContext(storedServerContext);
|
||||
};
|
||||
|
||||
private BiConsumer<Result, Throwable> afterContext = (appResponse, t) -> {
|
||||
RpcContext.restoreContext(tmpContext);
|
||||
RpcContext.restoreServerContext(tmpServerContext);
|
||||
};
|
||||
|
||||
/**
|
||||
* Some utility methods used to quickly generate default AsyncRpcResult instance.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,10 +22,33 @@ public interface BaseFilter {
|
|||
*/
|
||||
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
|
||||
|
||||
/**
|
||||
* This callback listener applies to both synchronous and asynchronous calls, please put logics that need to be executed
|
||||
* on return of rpc result in onResponse or onError respectively based on it is normal return or exception return.
|
||||
* <p>
|
||||
* There's something that needs to pay attention on legacy synchronous style filer refactor, the thing is, try to move logics
|
||||
* previously defined in the 'finally block' to both onResponse and onError.
|
||||
*/
|
||||
interface Listener {
|
||||
|
||||
/**
|
||||
* This method will only be called on successful remote rpc execution, that means, the service in on remote received
|
||||
* the request and the result (normal or exceptional) returned successfully.
|
||||
*
|
||||
* @param appResponse, the rpc call result, it can represent both normal result and exceptional result
|
||||
* @param invoker, context
|
||||
* @param invocation, context
|
||||
*/
|
||||
void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);
|
||||
|
||||
/**
|
||||
* This method will be called on detection of framework exceptions, for example, TimeoutException, NetworkException
|
||||
* Exception raised in Filters, etc.
|
||||
*
|
||||
* @param t, framework exception
|
||||
* @param invoker, context
|
||||
* @param invocation, context
|
||||
*/
|
||||
void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ import java.util.concurrent.ConcurrentMap;
|
|||
* It's recommended to implement Filter.Listener directly for callback registration, check the default implementation,
|
||||
* see {@link org.apache.dubbo.rpc.filter.ExceptionFilter}, for example.
|
||||
* <p>
|
||||
* If you do not want to share Listener instance between RPC calls. You can use ListenableFilter
|
||||
* If you do not want to share Listener instance between RPC calls. ListenableFilter can be used
|
||||
* to keep a 'one Listener each RPC call' model.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class ListenableFilter implements Filter {
|
||||
|
||||
protected Listener listener = null;
|
||||
|
|
|
|||
|
|
@ -122,10 +122,6 @@ public class RpcContext {
|
|||
return SERVER_LOCAL.get();
|
||||
}
|
||||
|
||||
public static void restoreServerContext(RpcContextAttachment oldServerContext) {
|
||||
SERVER_LOCAL.set(oldServerContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove server side context.
|
||||
*
|
||||
|
|
@ -198,10 +194,6 @@ public class RpcContext {
|
|||
this.remove = remove;
|
||||
}
|
||||
|
||||
public static void restoreContext(RpcContextAttachment oldContext) {
|
||||
CLIENT_ATTACHMENT.set(oldContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove context.
|
||||
*
|
||||
|
|
@ -810,4 +802,60 @@ public class RpcContext {
|
|||
public static void setRpcContext(URL url) {
|
||||
RpcServiceContext.setRpcContext(url);
|
||||
}
|
||||
|
||||
protected static RestoreContext clearAndStoreContext() {
|
||||
RestoreContext restoreContext = new RestoreContext();
|
||||
RpcContext.removeContext();
|
||||
return restoreContext;
|
||||
}
|
||||
|
||||
protected static RestoreContext storeContext() {
|
||||
return new RestoreContext();
|
||||
}
|
||||
|
||||
protected static void restoreContext(RestoreContext restoreContext) {
|
||||
if (restoreContext != null) {
|
||||
restoreContext.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to temporarily store and restore all kinds of contexts of current thread.
|
||||
*/
|
||||
public static class RestoreContext {
|
||||
private final RpcServiceContext serviceContext;
|
||||
private final RpcContextAttachment clientAttachment;
|
||||
private final RpcContextAttachment serverAttachment;
|
||||
private final RpcContextAttachment serverLocal;
|
||||
|
||||
public RestoreContext() {
|
||||
serviceContext = getServiceContext().copyOf(false);
|
||||
clientAttachment = getClientAttachment().copyOf(false);
|
||||
serverAttachment = getServerAttachment().copyOf(false);
|
||||
serverLocal = getServerContext().copyOf(false);
|
||||
}
|
||||
|
||||
public void restore() {
|
||||
if (serviceContext != null) {
|
||||
SERVICE_CONTEXT.set(serviceContext);
|
||||
} else {
|
||||
removeServiceContext();
|
||||
}
|
||||
if (clientAttachment != null) {
|
||||
CLIENT_ATTACHMENT.set(clientAttachment);
|
||||
} else {
|
||||
removeClientAttachment();
|
||||
}
|
||||
if (serverAttachment != null) {
|
||||
SERVER_ATTACHMENT.set(serverAttachment);
|
||||
} else {
|
||||
removeServerAttachment();
|
||||
}
|
||||
if (serverLocal != null) {
|
||||
SERVER_LOCAL.set(serverLocal);
|
||||
} else {
|
||||
removeServerContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,4 +201,28 @@ public class RpcContextAttachment extends RpcContext{
|
|||
return getAttachment(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Also see {@link RpcServiceContext#copyOf(boolean)}
|
||||
*
|
||||
* @return a copy of RpcContextAttachment with deep copied attachments
|
||||
*/
|
||||
public RpcContextAttachment copyOf(boolean needCopy) {
|
||||
if (!isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (needCopy) {
|
||||
RpcContextAttachment copy = new RpcContextAttachment();
|
||||
if (CollectionUtils.isNotEmptyMap(attachments)) {
|
||||
copy.attachments.putAll(this.attachments);
|
||||
}
|
||||
return copy;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
return CollectionUtils.isNotEmptyMap(attachments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ public class RpcServiceContext extends RpcContext {
|
|||
protected RpcServiceContext() {
|
||||
}
|
||||
|
||||
// RPC service context updated before each service call.
|
||||
private URL consumerUrl;
|
||||
|
||||
private List<URL> urls;
|
||||
|
||||
private URL url;
|
||||
|
|
@ -584,9 +587,6 @@ public class RpcServiceContext extends RpcContext {
|
|||
return asyncContext;
|
||||
}
|
||||
|
||||
// RPC service context updated before each service call.
|
||||
private URL consumerUrl;
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
if (consumerUrl == null) {
|
||||
|
|
@ -649,4 +649,26 @@ public class RpcServiceContext extends RpcContext {
|
|||
RpcServiceContext rpcContext = RpcContext.getServiceContext();
|
||||
rpcContext.setConsumerUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only part of the properties are copied, the others are either not used currently or can be got from invocation.
|
||||
* Also see {@link RpcContextAttachment#copyOf(boolean)}
|
||||
*
|
||||
* @param needCopy
|
||||
* @return a shallow copy of RpcServiceContext
|
||||
*/
|
||||
public RpcServiceContext copyOf(boolean needCopy) {
|
||||
if (needCopy) {
|
||||
RpcServiceContext copy = new RpcServiceContext();
|
||||
copy.consumerUrl = this.consumerUrl;
|
||||
copy.localAddress = this.localAddress;
|
||||
copy.remoteAddress = this.remoteAddress;
|
||||
copy.invocation = this.invocation;
|
||||
copy.asyncContext = this.asyncContext;
|
||||
return copy;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.BaseFilter;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.WORKING_CLASSLOADER_KEY;
|
||||
|
||||
/**
|
||||
* Switch thread context class loader on filter callback.
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER, order = Integer.MAX_VALUE)
|
||||
public class ClassLoaderCallbackFilter implements Filter, BaseFilter.Listener {
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
setClassLoader(invoker, invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
setClassLoader(invoker, invocation);
|
||||
}
|
||||
|
||||
private void setClassLoader(Invoker<?> invoker, Invocation invocation) {
|
||||
ClassLoader workingClassLoader = (ClassLoader) invocation.get(WORKING_CLASSLOADER_KEY);
|
||||
if (workingClassLoader != null) {
|
||||
Thread.currentThread().setContextClassLoader(workingClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,35 +18,59 @@ package org.apache.dubbo.rpc.filter;
|
|||
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.BaseFilter;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.STAGED_CLASSLOADER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.WORKING_CLASSLOADER_KEY;
|
||||
|
||||
/**
|
||||
* Set the current execution thread class loader to service interface's class loader.
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER, order = -30000)
|
||||
public class ClassLoaderFilter implements Filter {
|
||||
public class ClassLoaderFilter implements Filter, BaseFilter.Listener {
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
ClassLoader ocl = Thread.currentThread().getContextClassLoader();
|
||||
ClassLoader newClassLoader;
|
||||
ClassLoader stagedClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
ClassLoader effectiveClassLoader;
|
||||
if (invocation.getServiceModel() != null) {
|
||||
newClassLoader = invocation.getServiceModel().getClassLoader();
|
||||
effectiveClassLoader = invocation.getServiceModel().getClassLoader();
|
||||
} else {
|
||||
newClassLoader = invoker.getClass().getClassLoader();
|
||||
effectiveClassLoader = invoker.getClass().getClassLoader();
|
||||
}
|
||||
if (newClassLoader != null) {
|
||||
Thread.currentThread().setContextClassLoader(newClassLoader);
|
||||
|
||||
if (effectiveClassLoader != null) {
|
||||
invocation.put(STAGED_CLASSLOADER_KEY, stagedClassLoader);
|
||||
invocation.put(WORKING_CLASSLOADER_KEY, effectiveClassLoader);
|
||||
|
||||
Thread.currentThread().setContextClassLoader(effectiveClassLoader);
|
||||
}
|
||||
try {
|
||||
return invoker.invoke(invocation);
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(ocl);
|
||||
Thread.currentThread().setContextClassLoader(stagedClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
resetClassLoader(invoker, invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
resetClassLoader(invoker, invocation);
|
||||
}
|
||||
|
||||
private void resetClassLoader(Invoker<?> invoker, Invocation invocation) {
|
||||
ClassLoader stagedClassLoader = (ClassLoader) invocation.get(STAGED_CLASSLOADER_KEY);
|
||||
if (stagedClassLoader != null) {
|
||||
Thread.currentThread().setContextClassLoader(stagedClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,27 +126,29 @@ public class ContextFilter implements Filter, Filter.Listener {
|
|||
((RpcInvocation) invocation).setInvoker(invoker);
|
||||
}
|
||||
|
||||
try {
|
||||
context.clearAfterEachInvoke(false);
|
||||
return invoker.invoke(invocation);
|
||||
} finally {
|
||||
context.clearAfterEachInvoke(true);
|
||||
RpcContext.removeServerAttachment();
|
||||
RpcContext.removeServiceContext();
|
||||
// IMPORTANT! For async scenario, we must remove context from current thread, so we always create a new RpcContext for the next invoke for the same thread.
|
||||
RpcContext.getClientAttachment().removeAttachment(TIME_COUNTDOWN_KEY);
|
||||
RpcContext.removeServerContext();
|
||||
}
|
||||
context.clearAfterEachInvoke(false);
|
||||
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
// pass attachments to result
|
||||
appResponse.addObjectAttachments(RpcContext.getServerContext().getObjectAttachments());
|
||||
removeContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
removeContext();
|
||||
}
|
||||
|
||||
private void removeContext() {
|
||||
RpcContext.getServerAttachment().clearAfterEachInvoke(true); // TODO, not necessary anymore
|
||||
|
||||
RpcContext.removeServerAttachment();
|
||||
RpcContext.removeClientAttachment();
|
||||
RpcContext.removeServiceContext();
|
||||
RpcContext.removeServerContext();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_ASYNC_KEY;
|
||||
|
||||
/**
|
||||
* This Invoker works on provider side, delegates RPC to interface implementation.
|
||||
*/
|
||||
|
|
@ -82,7 +84,7 @@ public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
|
|||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
try {
|
||||
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
|
||||
CompletableFuture<Object> future = wrapWithFuture(value);
|
||||
CompletableFuture<Object> future = wrapWithFuture(value, invocation);
|
||||
CompletableFuture<AppResponse> appResponseFuture = future.handle((obj, t) -> {
|
||||
AppResponse result = new AppResponse(invocation);
|
||||
if (t != null) {
|
||||
|
|
@ -107,11 +109,13 @@ public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
|
|||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Object> wrapWithFuture(Object value) {
|
||||
if (RpcContext.getServiceContext().isAsyncStarted()) {
|
||||
return ((AsyncContextImpl)(RpcContext.getServiceContext().getAsyncContext())).getInternalFuture();
|
||||
} else if (value instanceof CompletableFuture) {
|
||||
private CompletableFuture<Object> wrapWithFuture(Object value, Invocation invocation) {
|
||||
if (value instanceof CompletableFuture) {
|
||||
invocation.put(PROVIDER_ASYNC_KEY, Boolean.TRUE);
|
||||
return (CompletableFuture<Object>) value;
|
||||
} else if (RpcContext.getServiceContext().isAsyncStarted()) {
|
||||
invocation.put(PROVIDER_ASYNC_KEY, Boolean.TRUE);
|
||||
return ((AsyncContextImpl) (RpcContext.getServiceContext().getAsyncContext())).getInternalFuture();
|
||||
}
|
||||
return CompletableFuture.completedFuture(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ genericimpl=org.apache.dubbo.rpc.filter.GenericImplFilter
|
|||
token=org.apache.dubbo.rpc.filter.TokenFilter
|
||||
accesslog=org.apache.dubbo.rpc.filter.AccessLogFilter
|
||||
classloader=org.apache.dubbo.rpc.filter.ClassLoaderFilter
|
||||
classloader-callback=org.apache.dubbo.rpc.filter.ClassLoaderCallbackFilter
|
||||
context=org.apache.dubbo.rpc.filter.ContextFilter
|
||||
exception=org.apache.dubbo.rpc.filter.ExceptionFilter
|
||||
executelimit=org.apache.dubbo.rpc.filter.ExecuteLimitFilter
|
||||
deprecated=org.apache.dubbo.rpc.filter.DeprecatedFilter
|
||||
compatible=org.apache.dubbo.rpc.filter.CompatibleFilter
|
||||
timeout=org.apache.dubbo.rpc.filter.TimeoutFilter
|
||||
tps=org.apache.dubbo.rpc.filter.TpsLimitFilter
|
||||
tps=org.apache.dubbo.rpc.filter.TpsLimitFilter
|
||||
|
|
|
|||
|
|
@ -202,4 +202,9 @@ public class RpcContextTest {
|
|||
rpcContext.setObjectAttachments(map);
|
||||
Assertions.assertEquals(map, rpcContext.getObjectAttachments());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.AsyncRpcResult;
|
|||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.Type;
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokerGeneric() {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("$enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Enum.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
@ -69,7 +70,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testResultHasException() {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Enum.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
@ -90,7 +91,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokerJsonPojoSerialization() throws Exception {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Type[].class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
@ -100,7 +101,8 @@ public class CompatibleFilterFilterTest {
|
|||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(result, invocation));
|
||||
AsyncRpcResult defaultAsyncResult = AsyncRpcResult.newDefaultAsyncResult(result, invocation);
|
||||
given(invoker.invoke(invocation)).willReturn(defaultAsyncResult);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1&serialization=json");
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
|
|
@ -112,7 +114,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokerNonJsonEnumSerialization() throws Exception {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Type[].class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
@ -122,7 +124,8 @@ public class CompatibleFilterFilterTest {
|
|||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(result, invocation));
|
||||
AsyncRpcResult defaultAsyncResult = AsyncRpcResult.newDefaultAsyncResult(result, invocation);
|
||||
given(invoker.invoke(invocation)).willReturn(defaultAsyncResult);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
|
|
@ -134,7 +137,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokerNonJsonNonPojoSerialization() {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("echo");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
@ -154,7 +157,7 @@ public class CompatibleFilterFilterTest {
|
|||
|
||||
@Test
|
||||
public void testInvokerNonJsonPojoSerialization() {
|
||||
invocation = mock(Invocation.class);
|
||||
invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("echo");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import org.apache.dubbo.rpc.support.MyInvoker;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ public class ContextFilterTest {
|
|||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
contextFilter.invoke(invoker, invocation);
|
||||
assertNull(RpcContext.getServiceContext().getInvoker());
|
||||
assertNotNull(RpcContext.getServiceContext().getInvoker());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -71,6 +71,6 @@ public class ContextFilterTest {
|
|||
Invoker<DemoService> invoker = new MyInvoker<DemoService>(url);
|
||||
Invocation invocation = new MockInvocation();
|
||||
Result result = contextFilter.invoke(invoker, invocation);
|
||||
assertNull(RpcContext.getServiceContext().getInvoker());
|
||||
assertNotNull(RpcContext.getServiceContext().getInvoker());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.Filter;
|
|||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -37,7 +38,7 @@ public class EchoFilterTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testEcho() {
|
||||
Invocation invocation = mock(Invocation.class);
|
||||
Invocation invocation = mock(RpcInvocation.class);
|
||||
given(invocation.getMethodName()).willReturn("$echo");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Enum.class});
|
||||
given(invocation.getArguments()).willReturn(new Object[]{"hello"});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.rpc.AppResponse;
|
|||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.support.BlockMyInvoker;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -56,7 +57,7 @@ public class TimeoutFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&timeout=" + timeout);
|
||||
Invoker invoker = new BlockMyInvoker(url, (timeout + 100));
|
||||
|
||||
Invocation invocation = Mockito.mock(Invocation.class);
|
||||
Invocation invocation = Mockito.mock(RpcInvocation.class);
|
||||
when(invocation.getMethodName()).thenReturn("testInvokeWithTimeout");
|
||||
|
||||
Result result = timeoutFilter.invoke(invoker, invocation);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
package org.apache.dubbo.rpc.support;
|
||||
|
||||
import org.apache.dubbo.rpc.AttachmentsAdapter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ServiceModel;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
|
@ -34,7 +34,7 @@ import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
|||
/**
|
||||
* MockInvocation.java
|
||||
*/
|
||||
public class MockInvocation implements Invocation {
|
||||
public class MockInvocation extends RpcInvocation {
|
||||
|
||||
private Map<String, Object> attachments;
|
||||
|
||||
|
|
|
|||
|
|
@ -607,7 +607,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
*/
|
||||
private ReferenceCountExchangeClient buildReferenceCountExchangeClient(URL url) {
|
||||
ExchangeClient exchangeClient = initClient(url);
|
||||
ReferenceCountExchangeClient client = new ReferenceCountExchangeClient(exchangeClient);
|
||||
ReferenceCountExchangeClient client = new ReferenceCountExchangeClient(exchangeClient, DubboCodec.NAME);
|
||||
// read configs
|
||||
int shutdownTimeout = ConfigurationUtils.getServerShutdownTimeout(url.getScopeModel());
|
||||
client.setShutdownWaitTime(shutdownTimeout);
|
||||
|
|
@ -640,7 +640,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
try {
|
||||
// connection should be lazy
|
||||
if (url.getParameter(LAZY_CONNECT_KEY, false)) {
|
||||
client = new LazyConnectExchangeClient(url, requestHandler);
|
||||
client = new LazyConnectExchangeClient(url, requestHandler, DubboCodec.NAME, url.getParameters());
|
||||
|
||||
} else {
|
||||
client = Exchangers.connect(url, requestHandler);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
|||
import org.apache.dubbo.remoting.exchange.Exchangers;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
|
@ -60,9 +61,11 @@ final class LazyConnectExchangeClient implements ExchangeClient {
|
|||
private volatile ExchangeClient client;
|
||||
private final AtomicLong warningCount = new AtomicLong(0);
|
||||
|
||||
public LazyConnectExchangeClient(URL url, ExchangeHandler requestHandler) {
|
||||
public LazyConnectExchangeClient(URL url, ExchangeHandler requestHandler, String codec, Map<String, String> parameters) {
|
||||
// lazy connect, need set send.reconnect = true, to avoid channel bad status.
|
||||
this.url = new ServiceConfigURL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), url.getParameters())
|
||||
// Parameters like 'username', 'password' and 'path' are set but will not be used in following processes.
|
||||
// The most important parameters here are 'host', port', 'parameters' and 'codec', 'codec' can also be extracted from 'parameters'
|
||||
this.url = new ServiceConfigURL(codec, url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), parameters)
|
||||
.addParameter(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
|
||||
this.requestHandler = requestHandler;
|
||||
this.initialState = url.getParameter(LAZY_CONNECT_INITIAL_STATE_KEY, DEFAULT_LAZY_CONNECT_INITIAL_STATE);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeClient;
|
|||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
|
@ -43,16 +44,20 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
|
|||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ReferenceCountExchangeClient.class);
|
||||
private final URL url;
|
||||
private final String codec;
|
||||
private final Map<String, String> attributes;
|
||||
private final AtomicInteger referenceCount = new AtomicInteger(0);
|
||||
private final AtomicInteger disconnectCount = new AtomicInteger(0);
|
||||
private final Integer warningPeriod = 50;
|
||||
private ExchangeClient client;
|
||||
private int shutdownWaitTime = DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
|
||||
|
||||
public ReferenceCountExchangeClient(ExchangeClient client) {
|
||||
public ReferenceCountExchangeClient(ExchangeClient client, String codec) {
|
||||
this.client = client;
|
||||
referenceCount.incrementAndGet();
|
||||
this.referenceCount.incrementAndGet();
|
||||
this.url = client.getUrl();
|
||||
this.codec = codec;
|
||||
this.attributes = url.getParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -210,10 +215,16 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
|
|||
if (!(client instanceof LazyConnectExchangeClient)) {
|
||||
// this is a defensive operation to avoid client is closed by accident, the initial state of the client is false
|
||||
URL lazyUrl = url.addParameter(LAZY_CONNECT_INITIAL_STATE_KEY, Boolean.TRUE)
|
||||
//.addParameter(RECONNECT_KEY, Boolean.FALSE)
|
||||
.addParameter(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
|
||||
//.addParameter(RECONNECT_KEY, Boolean.FALSE)
|
||||
.addParameter(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
|
||||
//.addParameter(LazyConnectExchangeClient.REQUEST_WITH_WARNING_KEY, true);
|
||||
client = new LazyConnectExchangeClient(lazyUrl, client.getExchangeHandler());
|
||||
|
||||
// uncomment this snippet when replacing lazyUrl in the futrue
|
||||
// Map<String, String> lazyAttributes = new HashMap<>(attributes);
|
||||
// lazyAttributes.put(LAZY_CONNECT_INITIAL_STATE_KEY, Boolean.TRUE.toString());
|
||||
// lazyAttributes.put(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
|
||||
|
||||
client = new LazyConnectExchangeClient(lazyUrl, client.getExchangeHandler(), codec, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public class DubboProtocolTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
assertEquals(service.getSize(new String[]{"", "", ""}), 3);
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ public class DubboProtocolTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName())));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName()).addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
assertEquals(service.enumlength(new Type[]{}), Type.Lower);
|
||||
assertEquals(service.getSize(null), -1);
|
||||
assertEquals(service.getSize(new String[]{"", "", ""}), 3);
|
||||
|
|
@ -100,7 +100,7 @@ public class DubboProtocolTest {
|
|||
service.invoke("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "", "invoke");
|
||||
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?client=netty").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
// test netty client
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < 1024 * 32 + 32; i++)
|
||||
|
|
@ -109,7 +109,7 @@ public class DubboProtocolTest {
|
|||
|
||||
// cast to EchoService
|
||||
EchoService echo = proxy.getProxy(protocol.refer(EchoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?client=netty").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
assertEquals(echo.$echo(buf.toString()), buf.toString());
|
||||
assertEquals(echo.$echo("test"), "test");
|
||||
assertEquals(echo.$echo("abcdefg"), "abcdefg");
|
||||
|
|
@ -168,9 +168,11 @@ public class DubboProtocolTest {
|
|||
ApplicationModel.defaultModel().getDefaultModule().getServiceRepository().registerService(RemoteService.class);
|
||||
|
||||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(remote, RemoteService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + RemoteService.class.getName())));
|
||||
remote = proxy.getProxy(protocol.refer(RemoteService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + RemoteService.class.getName()).addParameter("timeout",
|
||||
3000L)));
|
||||
URL url = URL.valueOf("dubbo://127.0.0.1:" + port + "/" + RemoteService.class.getName()).addParameter("timeout",
|
||||
3000L);
|
||||
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
|
||||
protocol.export(proxy.getInvoker(remote, RemoteService.class, url));
|
||||
remote = proxy.getProxy(protocol.refer(RemoteService.class, url));
|
||||
|
||||
// service.sayHello("world");
|
||||
|
||||
|
|
@ -189,7 +191,7 @@ public class DubboProtocolTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100; i++)
|
||||
service.getSize(new String[]{"", "", ""});
|
||||
|
|
@ -202,7 +204,7 @@ public class DubboProtocolTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
try {
|
||||
service.nonSerializedParameter(new NonSerialized());
|
||||
Assertions.fail();
|
||||
|
|
@ -217,7 +219,7 @@ public class DubboProtocolTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
|
||||
3000L)));
|
||||
3000L)));
|
||||
try {
|
||||
service.returnNonSerialized();
|
||||
Assertions.fail();
|
||||
|
|
@ -231,7 +233,8 @@ public class DubboProtocolTest {
|
|||
DemoService service = new DemoServiceImpl();
|
||||
int port = NetUtils.getAvailablePort();
|
||||
URL url = URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
|
||||
3000L).addParameter("application", "consumer");
|
||||
3000L).addParameter("application", "consumer");
|
||||
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, url));
|
||||
Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);
|
||||
|
||||
|
|
@ -254,10 +257,10 @@ public class DubboProtocolTest {
|
|||
DemoService service = new DemoServiceImpl();
|
||||
int port = NetUtils.getAvailablePort();
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class,
|
||||
URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName()).addParameter("payload", 10 * 1024)));
|
||||
URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName()).addParameter("payload", 10 * 1024)));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class,
|
||||
URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName()).addParameter("timeout",
|
||||
6000L).addParameter("payload", 160)));
|
||||
URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName()).addParameter("timeout",
|
||||
6000L).addParameter("payload", 160)));
|
||||
try {
|
||||
service.download(300);
|
||||
Assertions.fail();
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public class RpcFilterTest {
|
|||
int port = NetUtils.getAvailablePort();
|
||||
URL url = URL.valueOf("dubbo://127.0.0.1:" + port + "/org.apache.dubbo.rpc.protocol.dubbo.support.DemoService?service.filter=echo");
|
||||
ApplicationModel.defaultModel().getDefaultModule().getServiceRepository().registerService(DemoService.class);
|
||||
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
|
||||
protocol.export(proxy.getInvoker(service, DemoService.class, url));
|
||||
service = proxy.getProxy(protocol.refer(DemoService.class, url));
|
||||
Assertions.assertEquals("123", service.echo("123"));
|
||||
|
|
|
|||
|
|
@ -43,6 +43,19 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2_version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
@ -111,6 +124,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo -->
|
||||
|
|
@ -79,6 +86,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -101,6 +101,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
|
||||
|
|
@ -82,6 +89,13 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,19 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2_version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
<properties>
|
||||
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
|
||||
<dubbo.version>${revision}</dubbo.version>
|
||||
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
|
||||
<log4j2_version>2.17.0</log4j2_version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
|
|||
4
pom.xml
4
pom.xml
|
|
@ -129,7 +129,7 @@
|
|||
<checkstyle_unix.skip>true</checkstyle_unix.skip>
|
||||
<rat.skip>true</rat.skip>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
<revision>3.0.5-SNAPSHOT</revision>
|
||||
<revision>3.0.5</revision>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
|
|
@ -379,7 +379,7 @@
|
|||
<profile>
|
||||
<id>release</id>
|
||||
<properties>
|
||||
<log4j2_version>2.11.1</log4j2_version>
|
||||
<log4j2_version>2.17.0</log4j2_version>
|
||||
<jacoco.skip>false</jacoco.skip>
|
||||
</properties>
|
||||
<build>
|
||||
|
|
|
|||
Loading…
Reference in New Issue