You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2018/07/31 07:04:22 UTC
[GitHub] carryxyh closed pull request #2109: Optimize init LoadBalance in
cluster invokers
carryxyh closed pull request #2109: Optimize init LoadBalance in cluster invokers
URL: https://github.com/apache/incubator-dubbo/pull/2109
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/.travis.yml b/.travis.yml
index 9a51c0d7ac..692285326d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ jdk:
- oraclejdk8
script:
- - travis_wait 30 ./mvnw clean package
+ - travis_wait 30 ./mvnw clean package -Dcheckstyle.skip=false -Drat.skip=false
after_success:
- bash <(curl -s https://codecov.io/bash)
diff --git a/README.md b/README.md
index 8a41ea5daf..ea2a6a6b74 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ We are now collecting dubbo user info in order to help us to improve dubbo bette
```java
package org.apache.dubbo.demo;
-public interface DemoService {
+public interface GreetingService {
String sayHello(String name);
}
```
@@ -50,9 +50,9 @@ public interface DemoService {
```java
package org.apache.dubbo.demo.provider;
-import org.apache.dubbo.demo.DemoService;
+import org.apache.dubbo.demo.GreetingService;
-public class DemoServiceImpl implements DemoService {
+public class GreetingServiceImpl implements GreetingService {
public String sayHello(String name) {
return "Hello " + name;
}
diff --git a/all/pom.xml b/all/pom.xml
index c4095a2e69..a9febb5921 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -349,8 +349,8 @@
<artifactId>javassist</artifactId>
</dependency>
<dependency>
- <groupId>org.jboss.netty</groupId>
- <artifactId>netty</artifactId>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
</dependency>
<!-- Temporarily add this part to exclude transitive dependency -->
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
index a4a1905cf2..d19bc9b1cd 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
@@ -22,9 +22,12 @@
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.NetUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory;
@@ -33,11 +36,11 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* AbstractClusterInvoker
- *
*/
public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
@@ -92,16 +95,17 @@ public void destroy() {
/**
* Select a invoker using loadbalance policy.</br>
- * a)Firstly, select an invoker using loadbalance. If this invoker is in previously selected list, or,
+ * a) Firstly, select an invoker using loadbalance. If this invoker is in previously selected list, or,
* if this invoker is unavailable, then continue step b (reselect), otherwise return the first selected invoker</br>
- * b)Reslection, the validation rule for reselection: selected > available. This rule guarantees that
- * the selected invoker has the minimum chance to be one in the previously selected list, and also
+ * <p>
+ * b) Reslection, the validation rule for reselection: selected > available. This rule guarantees that
+ * the selected invoker has the minimum chance to be one in the previously selected list, and also
* guarantees this invoker is available.
*
* @param loadbalance load balance policy
- * @param invocation
- * @param invokers invoker candidates
- * @param selected exclude selected invokers or not
+ * @param invocation invocation
+ * @param invokers invoker candidates
+ * @param selected exclude selected invokers or not
* @return
* @throws RpcException
*/
@@ -136,9 +140,6 @@ public void destroy() {
return null;
if (invokers.size() == 1)
return invokers.get(0);
- if (loadbalance == null) {
- loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
- }
Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);
//If the `invoker` is in the `selected` or invoker is unavailable && availablecheck is true, reselect.
@@ -224,12 +225,15 @@ public void destroy() {
@Override
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
- LoadBalance loadbalance = null;
- List<Invoker<T>> invokers = list(invocation);
- if (invokers != null && !invokers.isEmpty()) {
- loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
- .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
+
+ // binding attachments into invocation.
+ Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
+ if (contextAttachments != null && contextAttachments.size() != 0) {
+ ((RpcInvocation) invocation).addAttachments(contextAttachments);
}
+
+ List<Invoker<T>> invokers = list(invocation);
+ LoadBalance loadbalance = initLoadBalance(invokers, invocation);
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
return doInvoke(invocation, invokers, loadbalance);
}
@@ -263,8 +267,40 @@ protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {
protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException;
+ /**
+ * if true, init LoadBalance before doInvoke.
+ *
+ * @return true for default
+ */
+ protected boolean needInitLoadBalance() {
+ return true;
+ }
+
protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
List<Invoker<T>> invokers = directory.list(invocation);
return invokers;
}
+
+ /**
+ * Init LoadBalance if needed. If not return null directly.
+ * <p>
+ * if invokers is not empty, init from the first invoke's url and invocation
+ * if invokes is empty, init a default LoadBalance(RandomLoadBalance)
+ * </p>
+ *
+ * @param invokers invokers
+ * @param invocation invocation
+ * @return LoadBalance instance. if not need init, return null.
+ */
+ protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
+ if (needInitLoadBalance()) {
+ if (CollectionUtils.isNotEmpty(invokers)) {
+ return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
+ .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
+ } else {
+ return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
+ }
+ }
+ return null;
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
index 85e91e0527..36f32d0c37 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
@@ -47,6 +47,12 @@ public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBal
}
throw new RpcException("No provider available in " + invokers);
}
+
+ @Override
+ protected boolean needInitLoadBalance() {
+ // no need to init LoadBalance
+ return false;
+ }
};
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
index c75052c02e..468a350b20 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java
@@ -45,4 +45,8 @@ public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBal
throw new RpcException("No provider available in " + invokers);
}
+ @Override
+ protected boolean needInitLoadBalance() {
+ return false;
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
index ab0623ea4a..13d316172a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
@@ -64,4 +64,9 @@ public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, L
return result;
}
+ @Override
+ protected boolean needInitLoadBalance() {
+ // no need to init LoadBalance
+ return false;
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
index 4cbaa0221a..28b4471612 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java
@@ -39,7 +39,6 @@
* Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.
*
* <a href="http://en.wikipedia.org/wiki/Fork_(topology)">Fork</a>
- *
*/
public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> {
@@ -57,50 +56,55 @@ public ForkingClusterInvoker(Directory<T> directory) {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- checkInvokers(invokers, invocation);
- final List<Invoker<T>> selected;
- final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS);
- final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
- if (forks <= 0 || forks >= invokers.size()) {
- selected = invokers;
- } else {
- selected = new ArrayList<Invoker<T>>();
- for (int i = 0; i < forks; i++) {
- // TODO. Add some comment here, refer chinese version for more details.
- Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
- if (!selected.contains(invoker)) {//Avoid add the same invoker several times.
- selected.add(invoker);
+ try {
+ checkInvokers(invokers, invocation);
+ final List<Invoker<T>> selected;
+ final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS);
+ final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
+ if (forks <= 0 || forks >= invokers.size()) {
+ selected = invokers;
+ } else {
+ selected = new ArrayList<Invoker<T>>();
+ for (int i = 0; i < forks; i++) {
+ // TODO. Add some comment here, refer chinese version for more details.
+ Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
+ if (!selected.contains(invoker)) {//Avoid add the same invoker several times.
+ selected.add(invoker);
+ }
}
}
- }
- RpcContext.getContext().setInvokers((List) selected);
- final AtomicInteger count = new AtomicInteger();
- final BlockingQueue<Object> ref = new LinkedBlockingQueue<Object>();
- for (final Invoker<T> invoker : selected) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- Result result = invoker.invoke(invocation);
- ref.offer(result);
- } catch (Throwable e) {
- int value = count.incrementAndGet();
- if (value >= selected.size()) {
- ref.offer(e);
+ RpcContext.getContext().setInvokers((List) selected);
+ final AtomicInteger count = new AtomicInteger();
+ final BlockingQueue<Object> ref = new LinkedBlockingQueue<Object>();
+ for (final Invoker<T> invoker : selected) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Result result = invoker.invoke(invocation);
+ ref.offer(result);
+ } catch (Throwable e) {
+ int value = count.incrementAndGet();
+ if (value >= selected.size()) {
+ ref.offer(e);
+ }
}
}
+ });
+ }
+ try {
+ Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS);
+ if (ret instanceof Throwable) {
+ Throwable e = (Throwable) ret;
+ throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
}
- });
- }
- try {
- Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS);
- if (ret instanceof Throwable) {
- Throwable e = (Throwable) ret;
- throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
+ return (Result) ret;
+ } catch (InterruptedException e) {
+ throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e);
}
- return (Result) ret;
- } catch (InterruptedException e) {
- throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e);
+ } finally {
+ // clear attachments which is binding to current thread.
+ RpcContext.getContext().clearAttachments();
}
}
}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
index 37f2f27745..7e2d55f6ec 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
@@ -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.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
@@ -50,7 +51,6 @@
/**
* AbstractClusterInvokerTest
- *
*/
@SuppressWarnings("rawtypes")
public class AbstractClusterInvokerTest {
@@ -128,20 +128,51 @@ protected Result doInvoke(Invocation invocation, List invokers, LoadBalance load
throws RpcException {
return null;
}
+
+ @Override
+ protected boolean needInitLoadBalance() {
+ // no need to init LoadBalance
+ return false;
+ }
+ };
+ }
+
+ @Test
+ public void testBindingAttachment() {
+ final String attachKey = "attach";
+ final String attachValue = "value";
+
+ // setup attachment
+ RpcContext.getContext().setAttachment(attachKey, attachValue);
+ Map<String, String> attachments = RpcContext.getContext().getAttachments();
+ Assert.assertTrue("set attachment failed!", attachments != null && attachments.size() == 1);
+
+ cluster = new AbstractClusterInvoker(dic) {
+ @Override
+ protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
+ throws RpcException {
+ // attachment will be bind to invocation
+ String value = invocation.getAttachment(attachKey);
+ Assert.assertTrue("binding attachment failed!", value != null && value.equals(attachValue));
+ return null;
+ }
};
+ // invoke
+ cluster.invoke(invocation);
}
@Test
public void testSelect_Invokersize0() throws Exception {
+ LoadBalance loadBalance = cluster.initLoadBalance(invokers, invocation);
{
- Invoker invoker = cluster.select(null, null, null, null);
+ Invoker invoker = cluster.select(loadBalance, null, null, null);
Assert.assertEquals(null, invoker);
}
{
invokers.clear();
selectedInvokers.clear();
- Invoker invoker = cluster.select(null, null, invokers, null);
+ Invoker invoker = cluster.select(loadBalance, null, invokers, null);
Assert.assertEquals(null, invoker);
}
}
@@ -150,7 +181,8 @@ public void testSelect_Invokersize0() throws Exception {
public void testSelect_Invokersize1() throws Exception {
invokers.clear();
invokers.add(invoker1);
- Invoker invoker = cluster.select(null, null, invokers, null);
+ LoadBalance loadBalance = cluster.initLoadBalance(invokers, invocation);
+ Invoker invoker = cluster.select(loadBalance, null, invokers, null);
Assert.assertEquals(invoker1, invoker);
}
@@ -159,16 +191,17 @@ public void testSelect_Invokersize2AndselectNotNull() throws Exception {
invokers.clear();
invokers.add(invoker2);
invokers.add(invoker4);
+ LoadBalance loadBalance = cluster.initLoadBalance(invokers, invocation);
{
selectedInvokers.clear();
selectedInvokers.add(invoker4);
- Invoker invoker = cluster.select(null, invocation, invokers, selectedInvokers);
+ Invoker invoker = cluster.select(loadBalance, invocation, invokers, selectedInvokers);
Assert.assertEquals(invoker2, invoker);
}
{
selectedInvokers.clear();
selectedInvokers.add(invoker2);
- Invoker invoker = cluster.select(null, invocation, invokers, selectedInvokers);
+ Invoker invoker = cluster.select(loadBalance, invocation, invokers, selectedInvokers);
Assert.assertEquals(invoker4, invoker);
}
}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
index fa9ac1a868..0c3b9be2a3 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
@@ -89,7 +89,7 @@ public void testInvokeExceptoin() {
}
@Test()
- public void testInvokeNoExceptoin() {
+ public void testInvokeNoException() {
resetInvokerToNoException();
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
index 42a4ec6eba..61226c409f 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
@@ -85,7 +85,7 @@ public void testInvokeExceptoin() {
}
@Test()
- public void testInvokeNoExceptoin() {
+ public void testInvokeNoException() {
resetInvokerToNoException();
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java
index 41dc79ca2e..3ed33354c7 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java
@@ -82,7 +82,7 @@ private void resetInvoker1ToNoException() {
}
@Test(expected = RpcException.class)
- public void testInvokeExceptoin() {
+ public void testInvokeException() {
resetInvoker1ToException();
FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<FailfastClusterInvokerTest>(dic);
invoker.invoke(invocation);
@@ -90,7 +90,7 @@ public void testInvokeExceptoin() {
}
@Test()
- public void testInvokeNoExceptoin() {
+ public void testInvokeNoException() {
resetInvoker1ToNoException();
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
index 28ba182974..136ba2a349 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
@@ -166,7 +166,7 @@ public void testNoInvoke() {
* then we should reselect from the latest invokers before retry.
*/
@Test
- public void testInvokerDestoryAndReList() {
+ public void testInvokerDestroyAndReList() {
final URL url = URL.valueOf("test://localhost/" + Demo.class.getName() + "?loadbalance=roundrobin&retries=" + retries);
RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);
MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url);
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
index 97dcbcd764..b39a7ba71a 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
@@ -22,6 +22,7 @@
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.Directory;
import org.junit.Assert;
@@ -30,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import static org.junit.Assert.assertFalse;
import static org.mockito.BDDMockito.given;
@@ -37,7 +39,6 @@
/**
* ForkingClusterInvokerTest
- *
*/
@SuppressWarnings("unchecked")
public class ForkingClusterInvokerTest {
@@ -71,6 +72,7 @@ public void setUp() throws Exception {
invokers.add(invoker3);
}
+
private void resetInvokerToException() {
given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
given(invoker1.getUrl()).willReturn(url);
@@ -106,7 +108,7 @@ private void resetInvokerToNoException() {
}
@Test
- public void testInvokeExceptoin() {
+ public void testInvokeException() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
@@ -120,8 +122,32 @@ public void testInvokeExceptoin() {
}
}
+ @Test
+ public void testClearRpcContext() {
+ resetInvokerToException();
+ ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
+ dic);
+
+ String attachKey = "attach";
+ String attachValue = "value";
+
+ RpcContext.getContext().setAttachment(attachKey, attachValue);
+
+ Map<String, String> attachments = RpcContext.getContext().getAttachments();
+ Assert.assertTrue("set attachment failed!", attachments != null && attachments.size() == 1);
+ try {
+ invoker.invoke(invocation);
+ Assert.fail();
+ } catch (RpcException expected) {
+ Assert.assertTrue("Successed to forking invoke provider !", expected.getMessage().contains("Failed to forking invoke provider"));
+ assertFalse(expected.getCause() instanceof RpcException);
+ }
+ Map<String, String> afterInvoke = RpcContext.getContext().getAttachments();
+ Assert.assertTrue("clear attachment failed!", afterInvoke != null && afterInvoke.size() == 0);
+ }
+
@Test()
- public void testInvokeNoExceptoin() {
+ public void testInvokeNoException() {
resetInvokerToNoException();
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
index 4893dc7337..5062a2899f 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
@@ -653,6 +653,13 @@ public void testMockInvokerFromOverride_Invoke_mock_false() {
Directory<IHelloService> dic = new StaticDirectory<IHelloService>(durl, invokers, null);
AbstractClusterInvoker<IHelloService> cluster = new AbstractClusterInvoker(dic) {
+
+ @Override
+ protected boolean needInitLoadBalance() {
+ // no need to init LoadBalance
+ return false;
+ }
+
@Override
protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
throws RpcException {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java
index 5721859d25..c22242c817 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java
@@ -34,8 +34,8 @@
public final class Version {
private static final Logger logger = LoggerFactory.getLogger(Version.class);
- // Dubbo RPC protocol version
- public static final String DEFAULT_DUBBO_PROTOCOL_VERSION = "2.0.2";
+ // Dubbo RPC protocol version, for compatibility, it must not be between 2.0.10 ~ 2.6.2
+ public static final String DEFAULT_DUBBO_PROTOCOL_VERSION = "2.0.1";
// Dubbo implementation version, usually is jar version.
private static final String VERSION = getVersion(Version.class, "");
@@ -43,7 +43,7 @@
* For protocol compatibility purpose.
* Because {@link #isSupportResponseAttatchment} is checked for every call, int compare expect to has higher performance than string.
*/
- private static final int LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT = 202; // 2.0.2
+ private static final int LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT = 20001; // 2.0.1
private static final Map<String, Integer> VERSION2INT = new HashMap<String, Integer>();
static {
@@ -66,7 +66,13 @@ public static boolean isSupportResponseAttatchment(String version) {
if (version == null || version.length() == 0) {
return false;
}
- return getIntVersion(version) >= LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT;
+ // for previous dubbo version(2.0.10/020010~2.6.2/020602), this version is the jar's version, so they need to be ignore
+ int iVersion = getIntVersion(version);
+ if (iVersion >= 20010 && iVersion <= 20602) {
+ return false;
+ }
+
+ return iVersion >= LOWEST_VERSION_FOR_RESPONSE_ATTATCHMENT;
}
public static int getIntVersion(String version) {
@@ -82,12 +88,31 @@ private static int parseInt(String version) {
int v = 0;
String[] vArr = version.split("\\.");
int len = vArr.length;
- for (int i = 1; i <= len; i++) {
- v += Integer.parseInt(vArr[len - i]) * Math.pow(10, i - 1);
+ for (int i = 0; i < len; i++) {
+ v += Integer.parseInt(getDigital(vArr[i])) * Math.pow(10, (len - i - 1) * 2);
}
return v;
}
+ private static String getDigital(String v) {
+ int index = 0;
+ for (int i = 0; i < v.length(); i++) {
+ char c = v.charAt(i);
+ if (Character.isDigit(c)) {
+ if (i == v.length() - 1) {
+ index = i + 1;
+ } else {
+ index = i;
+ }
+ continue;
+ } else {
+ index = i;
+ break;
+ }
+ }
+ return v.substring(0, index);
+ }
+
private static boolean hasResource(String path) {
try {
return Version.class.getClassLoader().getResource(path) != null;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
index 424cead9b1..14a0a79b26 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java
@@ -91,6 +91,19 @@ public static Object compatibleTypeConvert(Object value, Class<?> type) {
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage(), e);
}
+ } else if (char[].class.equals(type)) {
+ // Process string to char array for generic invoke
+ // See
+ // - https://github.com/apache/incubator-dubbo/issues/2003
+ if (string == null) {
+ return null;
+ }
+ else {
+ int len = string.length();
+ char[] chars = new char[len];
+ string.getChars(0, len, chars, 0);
+ return chars;
+ }
}
} else if (value instanceof Number) {
Number number = (Number) value;
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
index 8c51e0214d..fc18ac77e1 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java
@@ -67,6 +67,17 @@ public void testCompatibleTypeConvert() throws Exception {
result = CompatibleTypeUtils.compatibleTypeConvert("2011-12-11 12:24:12", Date.class);
assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-11 12:24:12"), (Date) result);
+
+ result = CompatibleTypeUtils.compatibleTypeConvert("ab", char[].class);
+ assertEquals(2, ((char[]) result).length);
+ assertEquals('a', ((char[]) result)[0]);
+ assertEquals('b', ((char[]) result)[1]);
+
+ result = CompatibleTypeUtils.compatibleTypeConvert("", char[].class);
+ assertEquals(0, ((char[]) result).length);
+
+ result = CompatibleTypeUtils.compatibleTypeConvert(null, char[].class);
+ assertEquals(null, result);
}
{
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConsumerConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConsumerConfig.java
index 812d676f69..42d67f08e2 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConsumerConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConsumerConfig.java
@@ -31,6 +31,18 @@
// networking framework client uses: netty, mina, etc.
private String client;
+ // consumer thread pool type: cached, fixed, limit, eager
+ private String threadpool;
+
+ // consumer threadpool core thread size
+ private Integer corethreads;
+
+ // consumer threadpool thread size
+ private Integer threads;
+
+ // consumer threadpool queue size
+ private Integer queues;
+
@Override
public void setTimeout(Integer timeout) {
super.setTimeout(timeout);
@@ -56,4 +68,40 @@ public String getClient() {
public void setClient(String client) {
this.client = client;
}
+
+ public String getThreadpool() {
+ return threadpool;
+ }
+
+ public void setThreadpool(String threadpool) {
+ this.threadpool = threadpool;
+ }
+
+ public Boolean getDefault() {
+ return isDefault;
+ }
+
+ public Integer getCorethreads() {
+ return corethreads;
+ }
+
+ public void setCorethreads(Integer corethreads) {
+ this.corethreads = corethreads;
+ }
+
+ public Integer getThreads() {
+ return threads;
+ }
+
+ public void setThreads(Integer threads) {
+ this.threads = threads;
+ }
+
+ public Integer getQueues() {
+ return queues;
+ }
+
+ public void setQueues(Integer queues) {
+ this.queues = queues;
+ }
}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
index a0b8ed75d1..b9a1a9a882 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
@@ -50,4 +50,32 @@ public void testClient() throws Exception {
consumer.setClient("client");
assertThat(consumer.getClient(), equalTo("client"));
}
+
+ @Test
+ public void testThreadpool() throws Exception {
+ ConsumerConfig consumer = new ConsumerConfig();
+ consumer.setThreadpool("fixed");
+ assertThat(consumer.getThreadpool(), equalTo("fixed"));
+ }
+
+ @Test
+ public void testCorethreads() throws Exception {
+ ConsumerConfig consumer = new ConsumerConfig();
+ consumer.setCorethreads(10);
+ assertThat(consumer.getCorethreads(), equalTo(10));
+ }
+
+ @Test
+ public void testThreads() throws Exception {
+ ConsumerConfig consumer = new ConsumerConfig();
+ consumer.setThreads(20);
+ assertThat(consumer.getThreads(), equalTo(20));
+ }
+
+ @Test
+ public void testQueues() throws Exception {
+ ConsumerConfig consumer = new ConsumerConfig();
+ consumer.setQueues(5);
+ assertThat(consumer.getQueues(), equalTo(5));
+ }
}
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index dc333e7a8e..995209db45 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -112,18 +112,21 @@
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
-
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<scope>test</scope>
</dependency>
-
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-core</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java
new file mode 100644
index 0000000000..36727e669f
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializer.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.spring.initializer;
+
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * Automatically register {@link DubboApplicationListener} to Spring context
+ * A {@link org.springframework.web.context.ContextLoaderListener} class is defined in
+ * src/main/resources/META-INF/web-fragment.xml
+ * In the web-fragment.xml, {@link DubboApplicationContextInitializer} is defined in context params.
+ * This file will be discovered if running under a servlet 3.0+ container.
+ * Even if user specifies {@link org.springframework.web.context.ContextLoaderListener} in web.xml,
+ * it will be merged to web.xml.
+ * If user specifies <metadata-complete="true" /> in web.xml, this will no take effect,
+ * unless user configures {@link DubboApplicationContextInitializer} explicitly in web.xml.
+ */
+public class DubboApplicationContextInitializer implements ApplicationContextInitializer {
+
+ @Override
+ public void initialize(ConfigurableApplicationContext applicationContext) {
+ applicationContext.addApplicationListener(new DubboApplicationListener());
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java
deleted file mode 100644
index 582535bb8b..0000000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/initializer/DubboWebApplicationInitializer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.config.spring.initializer;
-
-import org.springframework.web.context.AbstractContextLoaderInitializer;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.context.support.XmlWebApplicationContext;
-
-/**
- * An initializer to register {@link DubboApplicationListener}
- * to the ApplicationContext seamlessly.
- */
-public class DubboWebApplicationInitializer extends AbstractContextLoaderInitializer {
-
- /**
- * This method won't be triggered if running on spring-boot.
- * It only works when running under a servlet container.
- * @return a WebApplicationContext with DubboApplicationListener registered.
- */
- @Override
- protected WebApplicationContext createRootApplicationContext() {
- XmlWebApplicationContext webApplicationContext = new XmlWebApplicationContext();
- webApplicationContext.addApplicationListener(new DubboApplicationListener());
- return webApplicationContext;
- }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
index 209a8d489e..30558cc7af 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
@@ -708,6 +708,26 @@
<xsd:documentation><![CDATA[ Transporter layer framework: netty mina.... ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="threadpool" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Consumer threadpool: cached, fixed, limited, eager]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="corethreads" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="threads" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="queues" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:extension>
</xsd:complexContent>
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
index 4213228221..adaa9369df 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
@@ -708,6 +708,26 @@
<xsd:documentation><![CDATA[ Transporter layer framework: netty mina.... ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="threadpool" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ Consumer threadpool: cached, fixed, limited, eager]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="corethreads" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="threads" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="queues" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:extension>
</xsd:complexContent>
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml
new file mode 100644
index 0000000000..220874ab78
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/web-fragment.xml
@@ -0,0 +1,22 @@
+<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">
+
+ <name>dubbo-fragment</name>
+
+ <ordering>
+ <before>
+ <others/>
+ </before>
+ </ordering>
+
+ <context-param>
+ <param-name>contextInitializerClasses</param-name>
+ <param-value>org.apache.dubbo.config.spring.initializer.DubboApplicationContextInitializer</param-value>
+ </context-param>
+
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+</web-fragment>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java
new file mode 100644
index 0000000000..2c84095f4e
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationContextInitializerTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.spring.initializer;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.ContextConfig;
+import org.apache.catalina.startup.Tomcat;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.web.context.ContextLoaderListener;
+
+
+public class DubboApplicationContextInitializerTest {
+
+ @Test
+ public void testSpringContextLoaderListenerInWebXml() throws Exception {
+ Tomcat tomcat = new Tomcat();
+ tomcat.setBaseDir("src/test/resources");
+ tomcat.setPort(12345);
+ StandardContext context = new StandardContext();
+ context.setName("test");
+ context.setDocBase("test");
+ context.setPath("/test");
+ context.addLifecycleListener(new ContextConfig());
+ tomcat.getHost().addChild(context);
+ tomcat.start();
+ // there should be 1 application listener
+ Assert.assertEquals(1, context.getApplicationLifecycleListeners().length);
+ // the first one should be Spring's built in ContextLoaderListener.
+ Assert.assertTrue(context.getApplicationLifecycleListeners()[0] instanceof ContextLoaderListener);
+ tomcat.stop();
+ tomcat.destroy();
+ }
+
+ @Test
+ public void testNoListenerInWebXml() throws Exception {
+ Tomcat tomcat = new Tomcat();
+ tomcat.setBaseDir("src/test/resources");
+ tomcat.setPort(12345);
+ StandardContext context = new StandardContext();
+ context.setName("test2");
+ context.setDocBase("test2");
+ context.setPath("/test2");
+ context.addLifecycleListener(new ContextConfig());
+ tomcat.getHost().addChild(context);
+ tomcat.start();
+ // there should be 1 application listener
+ Assert.assertEquals(1, context.getApplicationLifecycleListeners().length);
+ // the first one should be Spring's built in ContextLoaderListener.
+ Assert.assertTrue(context.getApplicationLifecycleListeners()[0] instanceof ContextLoaderListener);
+ tomcat.stop();
+ tomcat.destroy();
+ }
+
+ @Test
+ public void testMetadataComplete() throws Exception {
+ Tomcat tomcat = new Tomcat();
+ tomcat.setBaseDir("src/test/resources");
+ tomcat.setPort(12345);
+ StandardContext context = new StandardContext();
+ context.setName("test3");
+ context.setDocBase("test3");
+ context.setPath("/test3");
+ context.addLifecycleListener(new ContextConfig());
+ tomcat.getHost().addChild(context);
+ tomcat.start();
+ // there should be no application listeners
+ Assert.assertEquals(0, context.getApplicationLifecycleListeners().length);
+ tomcat.stop();
+ tomcat.destroy();
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/applicationContext.xml b/dubbo-config/dubbo-config-spring/src/test/resources/applicationContext.xml
new file mode 100644
index 0000000000..977a8a43d0
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/applicationContext.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+</beans>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test/WEB-INF/web.xml b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test/WEB-INF/web.xml
new file mode 100644
index 0000000000..25214e23e3
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test/WEB-INF/web.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="3.1">
+ <display-name>dubbo-demo</display-name>
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>classpath:applicationContext.xml</param-value>
+ </context-param>
+
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+</web-app>
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test2/WEB-INF/web.xml b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test2/WEB-INF/web.xml
new file mode 100644
index 0000000000..0da8d8a5db
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test2/WEB-INF/web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="3.1">
+ <display-name>dubbo-demo</display-name>
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>classpath:applicationContext.xml</param-value>
+ </context-param>
+
+</web-app>
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test3/WEB-INF/web.xml b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test3/WEB-INF/web.xml
new file mode 100644
index 0000000000..81a5a13f9e
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/webapps/test3/WEB-INF/web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="3.1" metadata-complete="true">
+ <display-name>dubbo-demo</display-name>
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>classpath:applicationContext.xml</param-value>
+ </context-param>
+
+</web-app>
diff --git a/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java b/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java
index 3c396bfbaf..98b9de176f 100644
--- a/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java
+++ b/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java
@@ -120,7 +120,6 @@ public RedisRegistry(URL url) {
addresses.addAll(Arrays.asList(backups));
}
- String password = url.getPassword();
for (String address : addresses) {
int i = address.indexOf(':');
String host;
@@ -132,15 +131,9 @@ public RedisRegistry(URL url) {
host = address;
port = DEFAULT_REDIS_PORT;
}
- if (StringUtils.isEmpty(password)) {
- this.jedisPools.put(address, new JedisPool(config, host, port,
- url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), null,
- url.getParameter("db.index", 0)));
- } else {
- this.jedisPools.put(address, new JedisPool(config, host, port,
- url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), password,
- url.getParameter("db.index", 0)));
- }
+ this.jedisPools.put(address, new JedisPool(config, host, port,
+ url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), StringUtils.isEmpty(url.getPassword()) ? null : url.getPassword(),
+ url.getParameter("db.index", 0)));
}
this.reconnectPeriod = url.getParameter(Constants.REGISTRY_RECONNECT_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RECONNECT_PERIOD);
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
index dd75e5b311..a945586a97 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java
@@ -321,8 +321,17 @@ public void disconnect() {
@Override
public void reconnect() throws RemotingException {
- disconnect();
- connect();
+ if (!isConnected()) {
+ connectLock.lock();
+ try {
+ if (!isConnected()) {
+ disconnect();
+ connect();
+ }
+ } finally {
+ connectLock.unlock();
+ }
+ }
}
@Override
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
index a00a993835..023635c61b 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java
@@ -135,7 +135,7 @@ public Result invoke(Invocation inv) throws RpcException {
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
- if (contextAttachments != null) {
+ if (contextAttachments != null && contextAttachments.size() != 0) {
/**
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
index f06b65b884..892a45d702 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java
@@ -29,6 +29,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Test;
import java.lang.reflect.Field;
@@ -77,7 +78,7 @@ public void test_Normal_ChannelReadOnly() throws Exception {
getClients(invoker)[0].removeAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY);
}
- @Test
+ @Ignore
public void test_normal_channel_close_wait_gracefully() throws Exception {
int testPort = NetUtils.getAvailablePort();
URL url = URL.valueOf("dubbo://127.0.0.1:" + testPort + "/org.apache.dubbo.rpc.protocol.dubbo.IDemoService?scope=true&lazy=false");
diff --git a/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java b/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
index 5c12a1037f..bd1ea8bcd2 100644
--- a/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-redis/src/main/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocol.java
@@ -22,6 +22,7 @@
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
+import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@@ -90,7 +91,9 @@ private Serialization getSerialization(URL url) {
if (url.getParameter("min.evictable.idle.time.millis", 0) > 0)
config.setMinEvictableIdleTimeMillis(url.getParameter("min.evictable.idle.time.millis", 0));
final JedisPool jedisPool = new JedisPool(config, url.getHost(), url.getPort(DEFAULT_PORT),
- url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
+ url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT),
+ StringUtils.isBlank(url.getPassword()) ? null : url.getPassword(),
+ url.getParameter("db.index", 0));
final int expiry = url.getParameter("expiry", 0);
final String get = url.getParameter("get", "get");
final String set = url.getParameter("set", Map.class.equals(type) ? "put" : "set");
diff --git a/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java b/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java
index 0ef53dda14..8c69c38767 100644
--- a/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java
@@ -16,18 +16,33 @@
*/
package org.apache.dubbo.rpc.protocol.redis;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.serialize.ObjectInput;
+import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcResult;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.exceptions.JedisDataException;
import redis.embedded.RedisServer;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
@@ -38,12 +53,21 @@
private RedisServer redisServer;
private URL registryUrl;
+ @Rule
+ public TestName name = new TestName();
+
@Before
public void setUp() throws Exception {
int redisPort = NetUtils.getAvailablePort();
- this.redisServer = new RedisServer(redisPort);
+ if (name.getMethodName().equals("testAuthRedis") || name.getMethodName().equals("testWrongAuthRedis")) {
+ String password = "123456";
+ this.redisServer = RedisServer.builder().port(redisPort).setting("requirepass " + password).build();
+ this.registryUrl = URL.valueOf("redis://username:"+password+"@localhost:"+redisPort+"?db.index=0");
+ } else {
+ this.redisServer = RedisServer.builder().port(redisPort).build();
+ this.registryUrl = URL.valueOf("redis://localhost:" + redisPort);
+ }
this.redisServer.start();
- this.registryUrl = URL.valueOf("redis://localhost:" + redisPort);
}
@After
@@ -109,4 +133,90 @@ public void testWrongRedis() {
public void testExport() {
protocol.export(protocol.refer(IDemoService.class, registryUrl));
}
+
+ @Test
+ public void testAuthRedis() {
+ // default db.index=0
+ Invoker<IDemoService> refer = protocol.refer(IDemoService.class,
+ registryUrl
+ .addParameter("max.idle", 10)
+ .addParameter("max.active", 20));
+ IDemoService demoService = this.proxy.getProxy(refer);
+
+ String value = demoService.get("key");
+ assertThat(value, is(nullValue()));
+
+ demoService.set("key", "newValue");
+ value = demoService.get("key");
+ assertThat(value, is("newValue"));
+
+ demoService.delete("key");
+ value = demoService.get("key");
+ assertThat(value, is(nullValue()));
+
+ refer.destroy();
+
+ //change db.index=1
+ String password = "123456";
+ int database = 1;
+ this.registryUrl = this.registryUrl.setPassword(password).addParameter("db.index", database);
+ refer = protocol.refer(IDemoService.class,
+ registryUrl
+ .addParameter("max.idle", 10)
+ .addParameter("max.active", 20));
+ demoService = this.proxy.getProxy(refer);
+
+ demoService.set("key", "newValue");
+ value = demoService.get("key");
+ assertThat(value, is("newValue"));
+
+ // jedis gets the result comparison
+ JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), "localhost", registryUrl.getPort(), 2000, password, database, (String)null);
+ Jedis jedis = null;
+ try {
+ jedis = pool.getResource();
+ byte[] valueByte = jedis.get("key".getBytes());
+ Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(this.registryUrl.getParameter(Constants.SERIALIZATION_KEY, "java"));
+ ObjectInput oin = serialization.deserialize(this.registryUrl, new ByteArrayInputStream(valueByte));
+ String actual = (String) oin.readObject();
+ assertThat(value, is(actual));
+ } catch(Exception e) {
+ Assert.fail("jedis gets the result comparison is error!");
+ } finally {
+ if (jedis != null) {
+ jedis.close();
+ }
+ pool.destroy();
+ }
+
+ demoService.delete("key");
+ value = demoService.get("key");
+ assertThat(value, is(nullValue()));
+
+ refer.destroy();
+ }
+
+ @Test
+ public void testWrongAuthRedis() {
+ String password = "1234567";
+ this.registryUrl = this.registryUrl.setPassword(password);
+ Invoker<IDemoService> refer = protocol.refer(IDemoService.class,
+ registryUrl
+ .addParameter("max.idle", 10)
+ .addParameter("max.active", 20));
+ IDemoService demoService = this.proxy.getProxy(refer);
+
+ try {
+ String value = demoService.get("key");
+ assertThat(value, is(nullValue()));
+ } catch (RpcException e) {
+ if (e.getCause() instanceof JedisConnectionException && e.getCause().getCause() instanceof JedisDataException) {
+ Assert.assertEquals("ERR invalid password" , e.getCause().getCause().getMessage());
+ } else {
+ Assert.fail("no invalid password exception!");
+ }
+ }
+
+ refer.destroy();
+ }
}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 044cdf3763..37d1f5e279 100644
--- a/pom.xml
+++ b/pom.xml
@@ -262,7 +262,6 @@
<configLocation>codestyle/checkstyle.xml</configLocation>
<suppressionsLocation>codestyle/checkstyle-suppressions.xml</suppressionsLocation>
<headerLocation>codestyle/checkstyle-header.txt</headerLocation>
- <linkXRef>false</linkXRef>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org