diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c92e4a115b..a1f163a36b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,18 +1,18 @@
-## Contributing to dubbo
-Dubbo is released under the non-restrictive Apache 2.0 license, and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below.
+## Contributing to Dubbo
+Dubbo is released under the non-restrictive Apache 2.0 licenses and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. Contributions of all form to this repository is acceptable, as long as it follows the prescribed community guidelines enumerated below.
### Sign the Contributor License Agreement
-Before we accept a non-trivial patch or pull request we will need you to sign the Contributor License Agreement. Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
+Before we accept a non-trivial patch or pull request (PRs), we will need you to sign the Contributor License Agreement. Signing the contributors' agreement does not grant anyone commits rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors may get invited to join the core team that will grant them privileges to merge existing PRs.
### Contact
#### Mailing list
-The mailing list is the recommended way for discussing almost anything that related to Dubbo. Please refer to this [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) for detailed documentation on how to subscribe.
+The mailing list is the recommended way of pursuing a discussion on almost anything related to Dubbo. Please refer to this [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) for detailed documentation on how to subscribe.
-- [dev@dubbo.apache.org](mailto:dev-subscribe@dubbo.apache.org): the develop mailing list, you can ask question here if you have encountered any problem when using or developing Dubbo.
-- [commits@dubbo.apache.org](mailto:commits-subscribe@dubbo.apache.org): all the commits will be sent to this mailing list. You can subscribe to it if you are interested in Dubbo's development.
+- [dev@dubbo.apache.org](mailto:dev-subscribe@dubbo.apache.org): the developer mailing list where you can ask questions about an issue you may have encountered while working with Dubbo.
+- [commits@dubbo.apache.org](mailto:commits-subscribe@dubbo.apache.org): the commit updates will get broadcasted on this mailing list. You can subscribe to it, should you be interested in following Dubbo's development.
- [notifications@dubbo.apache.org](mailto:notifications-subscribe@dubbo.apache.org): all the Github [issue](https://github.com/apache/dubbo/issues) updates and [pull request](https://github.com/apache/dubbo/pulls) updates will be sent to this mailing list.
### Reporting issue
@@ -21,33 +21,33 @@ Please follow the [template](https://github.com/apache/dubbo/issues/new?templat
### Code Conventions
Our code style is almost in line with the standard java conventions (Popular IDE's default setting satisfy this), with the following additional restricts:
-* If there are more than 120 characters in current line, start a new line.
+* If there are more than 120 characters in the current line, begin a new line.
-* Make sure all new .java files to have a simple Javadoc class comment with at least a @date tag identifying birth, and preferably at least a paragraph on what the class is for.
+* Make sure all new .java files to have a simple Javadoc class comment with at least a @date tag identifying birth, and preferably at least a paragraph on the intended purpose of the class.
* Add the ASF license header comment to all new .java files (copy from existing files in the project)
-* Make sure no @author tag added to the file you contribute since @author tag is not used at Apache, other ways such as cvs will record all your contributions fairly.
+* Make sure no @author tag gets appended to the file you contribute to as the @author tag is incompatible with Apache. Rest assured, other ways, including CVS, will ensure transparency, fairness in recording your contributions.
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
-* A few unit tests should be added for a new feature or an important bugfix.
+* Sufficient unit-tests should accompany new feature development or non-trivial bug fixes.
-* If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project).
+* If no-one else is using your branch, please rebase it against the current master (or another target branch in the main project).
-* When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes #XXX at the end of the commit message (where XXX is the issue number).
+* When writing a commit message, please follow the following conventions: should your commit address an open issue, please add Fixes #XXX at the end of the commit message (where XXX is the issue number).
### Contribution flow
-This is a rough outline of what a contributor's workflow looks like:
+A rough outline of an ideal contributors' workflow is as follows:
* Fork the current repository
-* Create a topic branch from where to base the contribution. This is usually master.
+* Create a topic branch from where to base the contribution. Mostly, it's the master branch.
* Make commits of logical units.
-* Make sure commit messages are in the proper format (see below).
+* Make sure the commit messages are in the proper format (see below).
* Push changes in a topic branch to your forked repository.
* Follow the checklist in the [pull request template](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md)
-* Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below:
+* Before sending out the pull request, please sync your forked repository with the remote repository to ensure that your PR is elegant, concise. Reference the guide below:
```
git remote add upstream git@github.com:apache/dubbo.git
git fetch upstream
@@ -62,15 +62,15 @@ Thanks for contributing!
### Code style
-We provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/apache/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea, you can import it to you IDE.
-If you use Eclipse you can config manually by referencing the same file.
+We provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/apache/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea that you can import it to your workplace.
+If you use Eclipse, you can use the IntelliJ Idea template for manually configuring your file.
**NOTICE**
-It is very important to set the dubbo_codestyle_for_idea.xml, otherwise you will fail to pass the Travis CI. Steps to set the code style are as below:
+It's critical to set the dubbo_codestyle_for_idea.xml to avoid the failure of your Travis CI builds. Steps to configure the code styles are as follows:
1. Enter `Editor > Code Style`
-2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click .
-From the drop-down list, select `Import Scheme`, then select this option `IntelliJ IDEA code style XML` to import scheme
+2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click on .
+From the drop-down list, select `Import Scheme`, then choose the option `IntelliJ IDEA code style XML` to import the scheme.
3. In the Scheme field, type the name of the new scheme and press ⏎ to save the changes.
diff --git a/NOTICE b/NOTICE
index 9664603fdd..e414ebfbe5 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
Apache Dubbo
-Copyright 2018-2020 The Apache Software Foundation
+Copyright 2018-2021 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
index 20c5854a2f..a1384f243a 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -1,18 +1,16 @@
## What is the purpose of the change
-XXXXX
+
## Brief changelog
-XXXXX
## Verifying this change
-XXXXX
-Follow this checklist to help us incorporate your contribution quickly and easily:
+
-- [x] Make sure there is a [GITHUB_issue](https://github.com/apache/dubbo/issues) field for the change (usually before you start working on it). Trivial changes like typos do not require a GITHUB issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
+- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change (usually before you start working on it). Trivial changes like typos do not require a GitHub issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
- [ ] Format the pull request title like `[Dubbo-XXX] Fix UnknownException when host config not exist #XXX`. Each commit in the pull request should have a meaningful subject line and body.
- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
- [ ] Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project.
diff --git a/README.md b/README.md
index 153121d2fc..d84a5ecdf8 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,22 @@
# Apache Dubbo Project
-[](https://travis-ci.org/apache/dubbo)
-[](https://codecov.io/gh/apache/dubbo)
-
-
+[](https://travis-ci.com/apache/dubbo)
+[](https://codecov.io/gh/apache/dubbo)
+
+
[](http://isitmaintained.com/project/apache/dubbo "Average time to resolve an issue")
[](http://isitmaintained.com/project/apache/dubbo "Percentage of issues still open")
[](https://twitter.com/intent/tweet?text=Apache%20Dubbo%20is%20a%20high-performance%2C%20java%20based%2C%20open%20source%20RPC%20framework.&url=http://dubbo.apache.org/&via=ApacheDubbo&hashtags=rpc,java,dubbo,micro-service)
-[](https://twitter.com/intent/follow?screen_name=ApacheDubbo)
+[](https://twitter.com/intent/follow?screen_name=ApacheDubbo)
[](https://gitter.im/alibaba/dubbo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
-Apache Dubbo is a high-performance, Java based open source RPC framework. Please visit [official site](http://dubbo.apache.org) for quick start and documentations, as well as [Wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes.
+Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the [official site](http://dubbo.apache.org) for the quick start guide and documentation, as well as the [wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes.
-We are now collecting dubbo user info in order to help us to improve Dubbo better, pls. kindly help us by providing yours on [issue#1012: Wanted: who's using dubbo](https://github.com/apache/dubbo/issues/1012), thanks :)
+We are now collecting Dubbo user info to help us to improve Dubbo further. Kindly support us by providing your usage information on [issue#1012: Wanted: who's using dubbo](https://github.com/apache/dubbo/issues/1012), thanks :)
## Architecture
-
+
## Features
@@ -29,14 +29,14 @@ We are now collecting dubbo user info in order to help us to improve Dubbo bette
## Getting started
-The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples/tree/master/java/dubbo-samples-api). You may clone the sample project and step into `dubbo-samples-api` sub directory before read on.
+The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api). You may clone the sample project and step into the `dubbo-samples-api` subdirectory before proceeding.
```bash
# git clone https://github.com/apache/dubbo-samples.git
-# cd dubbo-samples/java/dubbo-samples-api
+# cd dubbo-samples/dubbo-samples-api
```
-There's a [README](https://github.com/apache/dubbo-samples/tree/master/java/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. Read it and try this sample out by following the instructions.
+There's a [README](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions:
### Maven dependency
@@ -44,7 +44,7 @@ There's a [README](https://github.com/apache/dubbo-samples/tree/master/java/dubb
2.7.8
-
+
org.apache.dubbo
@@ -70,7 +70,7 @@ public interface GreetingsService {
}
```
-*See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/master/java/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.*
+*See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.*
### Implement service interface for the provider
@@ -87,7 +87,7 @@ public class GreetingsServiceImpl implements GreetingsService {
}
```
-*See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/master/java/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.*
+*See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.*
### Start service provider
@@ -119,7 +119,7 @@ public class Application {
}
```
-*See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/master/java/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.*
+*See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.*
### Build and run the provider
@@ -128,7 +128,7 @@ public class Application {
# mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java
```
-### Call remote service in consumer
+### Call remote service in the consumer
```java
package org.apache.dubbo.samples.client;
@@ -153,7 +153,7 @@ public class Application {
}
}
```
-*See [consumer/Application.java](https://github.com/apache/dubbo-samples/blob/master/java/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.*
+*See [consumer/Application.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.*
### Build and run the consumer
@@ -167,14 +167,14 @@ The consumer will print out `hi, dubbo` on the screen.
### Next steps
-* [Your first Dubbo application](http://dubbo.apache.org/en-us/blog/dubbo-101.html) - A 101 tutorial to reveal more details, with the same code above.
-* [Dubbo user manual](http://dubbo.apache.org/en-us/docs/user/preface/background.html) - How to use Dubbo and all its features.
-* [Dubbo developer guide](http://dubbo.apache.org/en-us/docs/dev/build.html) - How to involve in Dubbo development.
-* [Dubbo admin manual](http://dubbo.apache.org/en-us/docs/admin/install/provider-demo.html) - How to admin and manage Dubbo services.
+* [Your first Dubbo application](http://dubbo.apache.org/blog/2018/08/07/dubbo-101/) - A 101 tutorial to reveal more details, with the same code above.
+* [Dubbo user manual](http://dubbo.apache.org/docs/v2.7/user/preface/background/) - How to use Dubbo and all its features.
+* [Dubbo developer guide](http://dubbo.apache.org/docs/v2.7/dev/build/) - How to involve in Dubbo development.
+* [Dubbo admin manual](http://dubbo.apache.org/docs/v2.7/admin/install/provider-demo/) - How to admin and manage Dubbo services.
## Building
-If you want to try out the cutting-edge features, you can build with the following commands. (Java 1.8 is required to build the master branch)
+If you want to try out the cutting-edge features, you can build with the following commands. (Java 1.8 is needed to build the master branch)
```
mvn clean install
@@ -182,11 +182,11 @@ If you want to try out the cutting-edge features, you can build with the followi
## Contact
-* Mailing list:
+* Mailing list:
* dev list: for dev/user discussion. [subscribe](mailto:dev-subscribe@dubbo.apache.org), [unsubscribe](mailto:dev-unsubscribe@dubbo.apache.org), [archive](https://lists.apache.org/list.html?dev@dubbo.apache.org), [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)
-
+
* Bugs: [Issues](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md)
-* Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo)
+* Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo)
* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo)
## Contributing
@@ -195,18 +195,18 @@ See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md)
### How can I contribute?
-* Take a look at issues with tag called [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
-* Join the discussion on mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide).
+* Take a look at issues with tags marked [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
+* Join the discussion on the mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide).
* Answer questions on [issues](https://github.com/apache/dubbo/issues).
-* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us pull request.
+* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us a pull request.
* Review the existing [pull request](https://github.com/apache/dubbo/pulls).
* Improve the [website](https://github.com/apache/dubbo-website), typically we need
* blog post
* translation on documentation
- * use cases about how Dubbo is being used in enterprise system.
+ * use cases around the integration of Dubbo in enterprise systems.
* Improve the [dubbo-admin/dubbo-monitor](https://github.com/apache/dubbo-admin).
* Contribute to the projects listed in [ecosystem](https://github.com/dubbo).
-* Any form of contribution that is not mentioned above.
+* Other forms of contribution not explicitly enumerated above.
* If you would like to contribute, please send an email to dev@dubbo.apache.org to let us know!
## Reporting bugs
@@ -215,7 +215,7 @@ Please follow the [template](https://github.com/apache/dubbo/issues/new?template
## Reporting a security vulnerability
-Please report security vulnerability to [us](mailto:security@dubbo.apache.org) privately.
+Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org) privately.
## Dubbo ecosystem
@@ -228,12 +228,12 @@ Please report security vulnerability to [us](mailto:security@dubbo.apache.org) p
#### Language
+* [Go](https://github.com/dubbo/dubbo-go) (recommended)
* [Node.js](https://github.com/apache/dubbo-js)
* [Python](https://github.com/dubbo/py-client-for-apache-dubbo)
* [PHP](https://github.com/apache/dubbo-php-framework)
-* [Go](https://github.com/dubbo/dubbo-go)
* [Erlang](https://github.com/apache/dubbo-erlang)
## License
-Apache Dubbo is under the Apache 2.0 license. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details.
+Apache Dubbo software is licenced under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details.
diff --git a/SECURITY.md b/SECURITY.md
index ac0c2ad225..b8b2a2cae8 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,7 +2,7 @@
## Supported Versions
-Below is a table that shows versions that accept security fix.
+Below is a table that shows versions that we accept security fixes.
| Version | Supported |
| ------- | ------------------ |
@@ -15,11 +15,11 @@ Below is a table that shows versions that accept security fix.
The Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality.
-If you have apprehensions regarding Dubbo's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Apache Dubbo Security Team by dropping a mail at security@dubbo.apache.org. In the mail, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Dubbo community will get back to you after assessing and analysing the findings.
+If you have apprehensions regarding Dubbo's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Apache Dubbo Security Team by dropping a mail at security@dubbo.apache.org. In the email, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Dubbo community will get back to you after assessing and analysing the findings.
PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on public domain.
-## VULNERABILITY HANDLING
+## Vulnerability Handling
An overview of the vulnerability handling process is:
diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml
index 3055454d9e..26b1295ffb 100644
--- a/dubbo-cluster/pom.xml
+++ b/dubbo-cluster/pom.xml
@@ -54,5 +54,11 @@
zookeepertest
+
+ org.apache.dubbo
+ dubbo-serialization-hessian2
+ ${project.parent.version}
+ test
+
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
index 948827a172..1fdadf8b21 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
@@ -22,7 +22,6 @@ import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.support.FailoverCluster;
/**
* Cluster. (SPI, Singleton, ThreadSafe)
@@ -33,7 +32,8 @@ import org.apache.dubbo.rpc.cluster.support.FailoverCluster;
*/
@SPI(Cluster.DEFAULT)
public interface Cluster {
- String DEFAULT = FailoverCluster.NAME;
+
+ String DEFAULT = "failover";
/**
* Merge the directory invokers to a virtual invoker.
@@ -56,4 +56,4 @@ public interface Cluster {
}
return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap);
}
-}
\ No newline at end of file
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
index 03211133b9..b9935fc530 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
@@ -106,4 +106,10 @@ public interface Constants {
String PEER_KEY = "peer";
String CONSUMER_URL_KEY = "CONSUMER_URL";
+
+ /**
+ * prefix of arguments router key
+ */
+ String ARGUMENTS = "arguments";
+
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
index a895677e33..f2310365d1 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
@@ -16,16 +16,6 @@
*/
package org.apache.dubbo.rpc.cluster;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
-
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.extension.ExtensionLoader;
@@ -44,6 +34,18 @@ import org.apache.dubbo.rpc.cluster.router.state.RouterCache;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
+
/**
* Router chain
*/
@@ -85,7 +87,7 @@ public class RouterChain {
private RouterChain(URL url) {
loopPool = executorRepository.nextExecutorExecutor();
List extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
- .getActivateExtension(url, "router");
+ .getActivateExtension(url, ROUTER_KEY);
List routers = extensionFactories.stream()
.map(factory -> factory.getRouter(url))
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
index 4f27b084e4..751d284142 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
@@ -47,6 +47,8 @@ import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
*/
public abstract class AbstractConfigurator implements Configurator {
+ private static final String TILDE = "~";
+
private final URL configuratorUrl;
public AbstractConfigurator(URL url) {
@@ -76,7 +78,8 @@ public abstract class AbstractConfigurator implements Configurator {
String configuratorSide = configuratorUrl.getSide();
if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
url = configureIfMatch(NetUtils.getLocalHost(), url);
- } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) && url.getPort() == configuratorUrl.getPort()) {
+ } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) &&
+ url.getPort() == configuratorUrl.getPort()) {
url = configureIfMatch(url.getHost(), url);
}
}
@@ -137,10 +140,13 @@ public abstract class AbstractConfigurator implements Configurator {
for (Map.Entry entry : configuratorUrl.getParameters().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
- if (key.startsWith("~") || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
- conditionKeys.add(key);
+ boolean startWithTilde = startWithTilde(key);
+ if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
+ if (startWithTilde) {
+ conditionKeys.add(key);
+ }
if (value != null && !ANY_VALUE.equals(value)
- && !value.equals(url.getParameter(key.startsWith("~") ? key.substring(1) : key))) {
+ && !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
return url;
}
}
@@ -152,6 +158,13 @@ public abstract class AbstractConfigurator implements Configurator {
return url;
}
+ private boolean startWithTilde(String key) {
+ if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) {
+ return true;
+ }
+ return false;
+ }
+
protected abstract URL doConfigure(URL currentUrl, URL configUrl);
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParser.java
index 26b907dcd2..76aaf396da 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParser.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParser.java
@@ -90,12 +90,14 @@ public class ConfigParser {
parseEnabled(item, config, urlBuilder);
- urlBuilder.append("&category=").append(DYNAMIC_CONFIGURATORS_CATEGORY);
urlBuilder.append("&configVersion=").append(config.getConfigVersion());
List apps = item.getApplications();
if (CollectionUtils.isNotEmpty(apps)) {
- apps.forEach(app -> urls.add(URL.valueOf(urlBuilder.append("&application=").append(app).toString())));
+ apps.forEach(app -> {
+ StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);
+ urls.add(URL.valueOf(tmpUrlBuilder.append("&application=").append(app).toString()));
+ });
} else {
urls.add(URL.valueOf(urlBuilder.toString()));
}
@@ -118,17 +120,18 @@ public class ConfigParser {
services.add("*");
}
for (String s : services) {
- urlBuilder.append(appendService(s));
- urlBuilder.append(toParameterString(item));
+ StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);
+ tmpUrlBuilder.append(appendService(s));
+ tmpUrlBuilder.append(toParameterString(item));
- urlBuilder.append("&application=").append(config.getKey());
+ tmpUrlBuilder.append("&application=").append(config.getKey());
- parseEnabled(item, config, urlBuilder);
+ parseEnabled(item, config, tmpUrlBuilder);
- urlBuilder.append("&category=").append(APP_DYNAMIC_CONFIGURATORS_CATEGORY);
- urlBuilder.append("&configVersion=").append(config.getConfigVersion());
+ tmpUrlBuilder.append("&category=").append(APP_DYNAMIC_CONFIGURATORS_CATEGORY);
+ tmpUrlBuilder.append("&configVersion=").append(config.getConfigVersion());
- urls.add(URL.valueOf(urlBuilder.toString()));
+ urls.add(URL.valueOf(tmpUrlBuilder.toString()));
}
}
return urls;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/GovernanceRuleRepository.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/GovernanceRuleRepository.java
index a8e5e18ac4..aaa604f2ff 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/GovernanceRuleRepository.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/GovernanceRuleRepository.java
@@ -35,7 +35,7 @@ public interface GovernanceRuleRepository {
}
- /*
+ /**
* {@link #removeListener(String, String, ConfigurationListener)}
*
* @param key the key to represent a configuration
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
index 855521f2b3..4f5859de2d 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
@@ -17,13 +17,11 @@
package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.io.Bytes;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.support.RpcUtils;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -88,7 +86,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
for (Invoker invoker : invokers) {
String address = invoker.getUrl().getAddress();
for (int i = 0; i < replicaNumber / 4; i++) {
- byte[] digest = md5(address + i);
+ byte[] digest = Bytes.getMD5(address + i);
for (int h = 0; h < 4; h++) {
long m = hash(digest, h);
virtualInvokers.put(m, invoker);
@@ -99,7 +97,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
public Invoker select(Invocation invocation) {
String key = toKey(invocation.getArguments());
- byte[] digest = md5(key);
+ byte[] digest = Bytes.getMD5(key);
return selectForKey(hash(digest, 0));
}
@@ -128,20 +126,6 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
| (digest[number * 4] & 0xFF))
& 0xFFFFFFFFL;
}
-
- private byte[] md5(String value) {
- MessageDigest md5;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- md5.reset();
- byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
- md5.update(bytes);
- return md5.digest();
- }
-
}
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java
index adfd04b316..50215d699b 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java
@@ -49,20 +49,17 @@ public class RandomLoadBalance extends AbstractLoadBalance {
int length = invokers.size();
// Every invoker has the same weight?
boolean sameWeight = true;
- // the weight of every invokers
+ // the maxWeight of every invokers, the minWeight = 0 or the maxWeight of the last invoker
int[] weights = new int[length];
- // the first invoker's weight
- int firstWeight = getWeight(invokers.get(0), invocation);
- weights[0] = firstWeight;
// The sum of weights
- int totalWeight = firstWeight;
- for (int i = 1; i < length; i++) {
+ int totalWeight = 0;
+ for (int i = 0; i < length; i++) {
int weight = getWeight(invokers.get(i), invocation);
- // save for later use
- weights[i] = weight;
// Sum
totalWeight += weight;
- if (sameWeight && weight != firstWeight) {
+ // save for later use
+ weights[i] = totalWeight;
+ if (sameWeight && totalWeight != weight * (i + 1)) {
sameWeight = false;
}
}
@@ -71,8 +68,7 @@ public class RandomLoadBalance extends AbstractLoadBalance {
int offset = ThreadLocalRandom.current().nextInt(totalWeight);
// Return a invoker based on the random value.
for (int i = 0; i < length; i++) {
- offset -= weights[i];
- if (offset < 0) {
+ if (offset < weights[i]) {
return invokers.get(i);
}
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
index dbf32fde8d..f6cfec2993 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
@@ -26,6 +26,7 @@ import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Constants;
import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
import java.text.ParseException;
@@ -50,13 +51,18 @@ import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
/**
* ConditionRouter
- *
+ * It supports the conditional routing configured by "override://", in 2.6.x,
+ * refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ .
+ * For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter}
+ * and {@link org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter}
+ * refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ .
*/
public class ConditionRouter extends AbstractRouter {
public static final String NAME = "condition";
private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
+ protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
protected Map whenCondition;
protected Map thenCondition;
@@ -65,7 +71,9 @@ public class ConditionRouter extends AbstractRouter {
public ConditionRouter(String rule, boolean force, boolean enabled) {
this.force = force;
this.enabled = enabled;
- this.init(rule);
+ if (enabled) {
+ this.init(rule);
+ }
}
public ConditionRouter(URL url) {
@@ -73,7 +81,9 @@ public class ConditionRouter extends AbstractRouter {
this.priority = url.getParameter(PRIORITY_KEY, 0);
this.force = url.getParameter(FORCE_KEY, false);
this.enabled = url.getParameter(ENABLED_KEY, true);
- init(url.getParameterAndDecoded(RULE_KEY));
+ if (enabled) {
+ init(url.getParameterAndDecoded(RULE_KEY));
+ }
}
public void init(String rule) {
@@ -226,6 +236,16 @@ public class ConditionRouter extends AbstractRouter {
boolean result = false;
for (Map.Entry matchPair : condition.entrySet()) {
String key = matchPair.getKey();
+
+ if (key.startsWith(Constants.ARGUMENTS)) {
+ if (!matchArguments(matchPair, invocation)) {
+ return false;
+ } else {
+ result = true;
+ continue;
+ }
+ }
+
String sampleValue;
//get real invoked method name from invocation
if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) {
@@ -258,6 +278,45 @@ public class ConditionRouter extends AbstractRouter {
return result;
}
+ /**
+ * analysis the arguments in the rule.
+ * Examples would be like this:
+ * "arguments[0]=1", whenCondition is that the first argument is equal to '1'.
+ * "arguments[1]=a", whenCondition is that the second argument is equal to 'a'.
+ * @param matchPair
+ * @param invocation
+ * @return
+ */
+ public boolean matchArguments(Map.Entry matchPair, Invocation invocation) {
+ try {
+ // split the rule
+ String key = matchPair.getKey();
+ String[] expressArray = key.split("\\.");
+ String argumentExpress = expressArray[0];
+ final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);
+ if (!matcher.find()) {
+ return false;
+ }
+
+ //extract the argument index
+ int index = Integer.parseInt(matcher.group(1));
+ if (index < 0 || index > invocation.getArguments().length) {
+ return false;
+ }
+
+ //extract the argument value
+ Object object = invocation.getArguments()[index];
+
+ if (matchPair.getValue().isMatch(String.valueOf(object), null)) {
+ return true;
+ }
+ } catch (Exception e) {
+ logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e);
+ }
+
+ return false;
+ }
+
protected static final class MatchPair {
final Set matches = new HashSet();
final Set mismatches = new HashSet();
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
index a616d8d015..7701c4c62e 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
@@ -22,7 +22,7 @@ import org.apache.dubbo.rpc.cluster.RouterFactory;
/**
* ConditionRouterFactory
- *
+ * Load when "override://" is configured {@link ConditionRouter}
*/
public class ConditionRouterFactory implements RouterFactory {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
index 690ebf9bcb..b0bfdc6959 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
@@ -33,7 +33,6 @@ import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
-import java.net.UnknownHostException;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -160,7 +159,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
* @return
*/
private List> filterUsingStaticTag(List> invokers, URL url, Invocation invocation) {
- List> result = invokers;
+ List> result;
// Dynamic param
String tag = StringUtils.isEmpty(invocation.getAttachment(TAG_KEY)) ? url.getParameter(TAG_KEY) :
invocation.getAttachment(TAG_KEY);
@@ -188,19 +187,11 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
}
private boolean isForceUseTag(Invocation invocation) {
- return Boolean.valueOf(invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
+ return Boolean.parseBoolean(invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
}
private List> filterInvoker(List> invokers, Predicate> predicate) {
- boolean filter = false;
- for (int i = 0; i < invokers.size(); ++i) {
- Invoker invoker = invokers.get(i);
- if (!predicate.test(invoker)) {
- filter = true;
- break;
- }
- }
- if (!filter) {
+ if (invokers.stream().allMatch(predicate)) {
return invokers;
}
@@ -226,8 +217,6 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
if ((ANYHOST_VALUE + ":" + port).equals(address)) {
return true;
}
- } catch (UnknownHostException e) {
- logger.error("The format of ip address is invalid in tag route. Address :" + address, e);
} catch (Exception e) {
logger.error("The format of ip address is invalid in tag route. Address :" + address, e);
}
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 450fa9197b..268140a19b 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
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.rpc.cluster.support;
+import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.Invocation;
@@ -30,11 +31,13 @@ import java.util.List;
/**
* BroadcastClusterInvoker
- *
*/
public class BroadcastClusterInvoker extends AbstractClusterInvoker {
private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
+ private static final String BROADCAST_FAIL_PERCENT_KEY = "broadcast.fail.percent";
+ private static final int MAX_BROADCAST_FAIL_PERCENT = 100;
+ private static final int MIN_BROADCAST_FAIL_PERCENT = 0;
public BroadcastClusterInvoker(Directory directory) {
super(directory);
@@ -47,21 +50,67 @@ public class BroadcastClusterInvoker extends AbstractClusterInvoker {
RpcContext.getServiceContext().setInvokers((List) invokers);
RpcException exception = null;
Result result = null;
+ URL url = getUrl();
+ // The value range of broadcast.fail.threshold must be 0~100.
+ // 100 means that an exception will be thrown last, and 0 means that as long as an exception occurs, it will be thrown.
+ // see https://github.com/apache/dubbo/pull/7174
+ int broadcastFailPercent = url.getParameter(BROADCAST_FAIL_PERCENT_KEY, MAX_BROADCAST_FAIL_PERCENT);
+
+ if (broadcastFailPercent < MIN_BROADCAST_FAIL_PERCENT || broadcastFailPercent > MAX_BROADCAST_FAIL_PERCENT) {
+ logger.info(String.format("The value corresponding to the broadcast.fail.percent parameter must be between 0 and 100. " +
+ "The current setting is %s, which is reset to 100.", broadcastFailPercent));
+ broadcastFailPercent = MAX_BROADCAST_FAIL_PERCENT;
+ }
+
+ int failThresholdIndex = invokers.size() * broadcastFailPercent / MAX_BROADCAST_FAIL_PERCENT;
+ int failIndex = 0;
for (Invoker invoker : invokers) {
try {
result = invokeWithContext(invoker, invocation);
- } catch (RpcException e) {
- exception = e;
- logger.warn(e.getMessage(), e);
+ if (null != result && result.hasException()) {
+ Throwable resultException = result.getException();
+ if (null != resultException) {
+ exception = getRpcException(result.getException());
+ logger.warn(exception.getMessage(), exception);
+ if (failIndex == failThresholdIndex) {
+ break;
+ } else {
+ failIndex++;
+ }
+ }
+ }
} catch (Throwable e) {
- exception = new RpcException(e.getMessage(), e);
- logger.warn(e.getMessage(), e);
+ exception = getRpcException(e);
+ logger.warn(exception.getMessage(), exception);
+ if (failIndex == failThresholdIndex) {
+ break;
+ } else {
+ failIndex++;
+ }
}
}
+
if (exception != null) {
+ if (failIndex == failThresholdIndex) {
+ logger.debug(
+ String.format("The number of BroadcastCluster call failures has reached the threshold %s", failThresholdIndex));
+ } else {
+ logger.debug(String.format("The number of BroadcastCluster call failures has not reached the threshold %s, fail size is %s",
+ failIndex));
+ }
throw exception;
}
+
return result;
}
+ private RpcException getRpcException(Throwable throwable) {
+ RpcException rpcException = null;
+ if (throwable instanceof RpcException) {
+ rpcException = (RpcException) throwable;
+ } else {
+ rpcException = new RpcException(throwable.getMessage(), throwable);
+ }
+ return rpcException;
+ }
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index b7a30ed372..72def111ab 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -29,6 +29,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
@@ -90,6 +91,9 @@ public class ClusterUtils {
if(map.containsKey(VERSION_KEY)){
copyOfLocalMap.remove(VERSION_KEY);
}
+ if (map.containsKey(GENERIC_KEY)) {
+ copyOfLocalMap.remove(GENERIC_KEY);
+ }
copyOfLocalMap.remove(RELEASE_KEY);
copyOfLocalMap.remove(DUBBO_VERSION_KEY);
@@ -99,20 +103,22 @@ public class ClusterUtils {
map.putAll(copyOfLocalMap);
- map.put(REMOTE_APPLICATION_KEY, remoteMap.get(APPLICATION_KEY));
+ if (remoteMap != null) {
+ map.put(REMOTE_APPLICATION_KEY, remoteMap.get(APPLICATION_KEY));
- // Combine filters and listeners on Provider and Consumer
- String remoteFilter = remoteMap.get(REFERENCE_FILTER_KEY);
- String localFilter = copyOfLocalMap.get(REFERENCE_FILTER_KEY);
- if (remoteFilter != null && remoteFilter.length() > 0
- && localFilter != null && localFilter.length() > 0) {
- map.put(REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter);
- }
- String remoteListener = remoteMap.get(INVOKER_LISTENER_KEY);
- String localListener = copyOfLocalMap.get(INVOKER_LISTENER_KEY);
- if (remoteListener != null && remoteListener.length() > 0
- && localListener != null && localListener.length() > 0) {
- map.put(INVOKER_LISTENER_KEY, remoteListener + "," + localListener);
+ // Combine filters and listeners on Provider and Consumer
+ String remoteFilter = remoteMap.get(REFERENCE_FILTER_KEY);
+ String localFilter = copyOfLocalMap.get(REFERENCE_FILTER_KEY);
+ if (remoteFilter != null && remoteFilter.length() > 0
+ && localFilter != null && localFilter.length() > 0) {
+ map.put(REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter);
+ }
+ String remoteListener = remoteMap.get(INVOKER_LISTENER_KEY);
+ String localListener = copyOfLocalMap.get(INVOKER_LISTENER_KEY);
+ if (remoteListener != null && remoteListener.length() > 0
+ && localListener != null && localListener.length() > 0) {
+ map.put(INVOKER_LISTENER_KEY, remoteListener + "," + localListener);
+ }
}
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
index 414deaa0fc..a445d366b5 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
@@ -58,10 +58,7 @@ public class FailoverClusterInvoker extends AbstractClusterInvoker {
List> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation);
String methodName = RpcUtils.getMethodName(invocation);
- int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
- if (len <= 0) {
- len = 1;
- }
+ int len = calculateInvokeTimes(methodName);
// retry loop.
RpcException le = null; // last exception.
List> invoked = new ArrayList>(copyInvokers.size()); // invoked invokers.
@@ -113,4 +110,19 @@ public class FailoverClusterInvoker extends AbstractClusterInvoker {
+ le.getMessage(), le.getCause() != null ? le.getCause() : le);
}
+ private int calculateInvokeTimes(String methodName) {
+ int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
+ RpcContext rpcContext = RpcContext.getClientAttachment();
+ Object retry = rpcContext.getObjectAttachment(RETRIES_KEY);
+ if (retry instanceof Number) {
+ len = ((Number) retry).intValue() + 1;
+ rpcContext.removeAttachment(RETRIES_KEY);
+ }
+ if (len <= 0) {
+ len = 1;
+ }
+
+ return len;
+ }
+
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
index 7bc1f9429d..95a7bd2a7d 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
@@ -113,7 +113,7 @@ public class MergeableClusterInvoker extends AbstractClusterInvoker {
if (resultList.isEmpty()) {
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else if (resultList.size() == 1) {
- return resultList.iterator().next();
+ return AsyncRpcResult.newDefaultAsyncResult(resultList.get(0).getValue(), invocation);
}
if (returnType == void.class) {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
index f5043e33f6..97b7a0b544 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
@@ -33,7 +33,6 @@ import java.util.List;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;
import static org.apache.dubbo.common.constants.RegistryConstants.ZONE_KEY;
@@ -62,7 +61,7 @@ public class ZoneAwareClusterInvoker extends AbstractClusterInvoker {
for (Invoker invoker : invokers) {
ClusterInvoker clusterInvoker = (ClusterInvoker) invoker;
if (clusterInvoker.isAvailable() && clusterInvoker.getRegistryUrl()
- .getParameter(REGISTRY_KEY + "." + PREFERRED_KEY, false)) {
+ .getParameter(PREFERRED_KEY, false)) {
return clusterInvoker.invoke(invocation);
}
}
@@ -72,7 +71,7 @@ public class ZoneAwareClusterInvoker extends AbstractClusterInvoker {
if (StringUtils.isNotEmpty(zone)) {
for (Invoker invoker : invokers) {
ClusterInvoker clusterInvoker = (ClusterInvoker) invoker;
- if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(REGISTRY_KEY + "." + ZONE_KEY))) {
+ if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(ZONE_KEY))) {
return clusterInvoker.invoke(invocation);
}
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
index 1c2d047f78..684f372fb2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
@@ -256,7 +256,7 @@ public abstract class AbstractCluster implements Cluster {
@Override
protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException {
- // The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.
+ // The only purpose is to build an interceptor chain, so the cluster related logic doesn't matter.
return null;
}
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
index a682297cdc..51d0a49755 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
@@ -162,7 +162,7 @@ public class MockClusterInvoker implements ClusterInvoker {
/**
* Return MockInvoker
* Contract:
- * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
+ * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
* if directory.list() returns more than one mock invoker, only one of them will be used.
*
* @param invocation
@@ -174,7 +174,7 @@ public class MockClusterInvoker implements ClusterInvoker {
if (invocation instanceof RpcInvocation) {
//Note the implicit contract (although the description is added to the interface declaration, but extensibility is a problem. The practice placed in the attachment needs to be improved)
((RpcInvocation) invocation).setAttachment(INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
- //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
+ //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
try {
invokers = directory.list(invocation);
} catch (RpcException e) {
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
index 8d77aa4ad1..bb6260c967 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java
@@ -131,13 +131,7 @@ public class RoundRobinLoadBalanceTest extends LoadBalanceBaseTest {
recycleTimeField = RoundRobinLoadBalance.class.getDeclaredField("RECYCLE_PERIOD");
recycleTimeField.setAccessible(true);
recycleTimeField.setInt(RoundRobinLoadBalance.class, 10);
- } catch (NoSuchFieldException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (SecurityException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (IllegalArgumentException e) {
- Assertions.assertTrue(true, "getField failed");
- } catch (IllegalAccessException e) {
+ } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException | SecurityException e) {
Assertions.assertTrue(true, "getField failed");
}
}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
index 204ce9adbf..4637976309 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
@@ -311,4 +311,38 @@ public class ConditionRouterTest {
Assertions.assertEquals(0, filteredInvokers.size());
}
+ @Test
+ public void testRoute_Arguments() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0] = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
+ List> invokers = new ArrayList<>();
+ Invoker invoker1 = new MockInvoker<>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
+ Invoker invoker2 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
+ Invoker invoker3 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ RpcInvocation invocation = new RpcInvocation();
+ String p = "a";
+ invocation.setArguments(new Object[]{null});
+ List> fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
+ Assertions.assertEquals(3, fileredInvokers.size());
+
+ invocation.setArguments(new Object[]{p});
+ fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
+ Assertions.assertEquals(0, fileredInvokers.size());
+
+ router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments = b " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
+ fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
+ Assertions.assertEquals(3, fileredInvokers.size());
+
+ router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[10].inner = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
+ fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
+ Assertions.assertEquals(3, fileredInvokers.size());
+
+ int integer = 1;
+ invocation.setArguments(new Object[]{integer});
+ router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0].inner = 1 " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
+ fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
+ Assertions.assertEquals(0, fileredInvokers.size());
+ }
}
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 613a527f34..a162526292 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
@@ -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.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
@@ -142,6 +143,33 @@ public class FailoverClusterInvokerTest {
}
}
+ @Test()
+ public void testInvoke_retryTimes2() {
+ int finalRetries = 1;
+ given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));
+ given(invoker1.isAvailable()).willReturn(false);
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willThrow(new RpcException());
+ given(invoker2.isAvailable()).willReturn(false);
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ RpcContext rpcContext = RpcContext.getContext();
+ rpcContext.setAttachment("retries", finalRetries);
+
+ FailoverClusterInvoker invoker = new FailoverClusterInvoker(dic);
+ try {
+ Result ret = invoker.invoke(invocation);
+ assertSame(result, ret);
+ fail();
+ } catch (RpcException expected) {
+ assertTrue((expected.isTimeout() || expected.getCode() == 0));
+ assertTrue(expected.getMessage().indexOf((finalRetries+1) + " times") > 0);
+ }
+ }
+
@Test()
public void testNoInvoke() {
dic = mock(Directory.class);
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java b/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
index f8a6516f27..9c04f9ad39 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java
@@ -18,11 +18,13 @@ package org.apache.dubbo.common;
import org.apache.dubbo.common.utils.StringUtils;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_VERSION;
+
/**
* 2019-10-10
*/
public class BaseServiceMetadata {
- public static final char COLON_SEPERATOR = ':';
+ public static final char COLON_SEPARATOR = ':';
protected String serviceKey;
protected String serviceInterfaceName;
@@ -48,7 +50,7 @@ public class BaseServiceMetadata {
public static String versionFromServiceKey(String serviceKey) {
int index = serviceKey.indexOf(":");
if (index == -1) {
- return null;
+ return DEFAULT_VERSION;
}
return serviceKey.substring(index + 1);
}
@@ -77,7 +79,7 @@ public class BaseServiceMetadata {
public String getDisplayServiceKey() {
StringBuilder serviceNameBuilder = new StringBuilder();
serviceNameBuilder.append(serviceInterfaceName);
- serviceNameBuilder.append(COLON_SEPERATOR).append(version);
+ serviceNameBuilder.append(COLON_SEPARATOR).append(version);
return serviceNameBuilder.toString();
}
@@ -88,7 +90,7 @@ public class BaseServiceMetadata {
* @return
*/
public static BaseServiceMetadata revertDisplayServiceKey(String displayKey) {
- String[] eles = StringUtils.split(displayKey, COLON_SEPERATOR);
+ String[] eles = StringUtils.split(displayKey, COLON_SEPARATOR);
if (eles == null || eles.length < 1 || eles.length > 2) {
return new BaseServiceMetadata();
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
index 90e3415ed1..790c476234 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
@@ -244,6 +244,9 @@ public class Parameters {
@Override
public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
return parameters.equals(o);
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index 96383df57a..404fd725af 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -48,7 +48,7 @@ import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
-import static org.apache.dubbo.common.BaseServiceMetadata.COLON_SEPERATOR;
+import static org.apache.dubbo.common.BaseServiceMetadata.COLON_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
@@ -1281,7 +1281,7 @@ class URL implements Serializable {
return getServiceInterface();
}
return getServiceInterface() +
- COLON_SEPERATOR + getVersion();
+ COLON_SEPARATOR + getVersion();
}
/**
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
index 3ca12467ff..1b45b1f534 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java
@@ -221,7 +221,7 @@ public final class URLStrParser {
*/
public static URL parseEncodedStr(String encodedURLStr, boolean modifiable) {
Map parameters = null;
- int pathEndIdx = encodedURLStr.indexOf("%3F");// '?'
+ int pathEndIdx = encodedURLStr.toUpperCase().indexOf("%3F");// '?'
if (pathEndIdx >= 0) {
parameters = parseEncodedParams(encodedURLStr, pathEndIdx + 3);
} else {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
index c6610cb23a..0b3da94c9a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
@@ -349,7 +349,7 @@ public final class JavaBeanSerializeUtil {
}
}
- return cl.newInstance();
+ return cl.getDeclaredConstructor().newInstance();
}
public static Object getConstructorArg(Class> cl) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
index b81b7a395b..252c3aa719 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
@@ -340,9 +340,7 @@ public final class ClassGenerator {
return mCtc.toClass(loader, pd);
} catch (RuntimeException e) {
throw e;
- } catch (NotFoundException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (CannotCompileException e) {
+ } catch (NotFoundException | CannotCompileException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
index 4afc8867e2..e5f639dd9e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/CustomizedLoaderClassPath.java
@@ -49,8 +49,9 @@ public class CustomizedLoaderClassPath implements ClassPath {
public String toString() {
Object cl = null;
- if (clref != null)
+ if (clref != null) {
cl = clref.get();
+ }
return cl == null ? "" : cl.toString();
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
index f7a8423638..cd16d381ad 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
@@ -174,7 +174,7 @@ public abstract class Mixin {
ccm.setSuperClass(Mixin.class.getName());
ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
Class> mixin = ccm.toClass();
- return (Mixin) mixin.newInstance();
+ return (Mixin) mixin.getDeclaredConstructor().newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
index c7fc5b2775..4c435a8f77 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
@@ -187,9 +187,6 @@ public abstract class Proxy {
if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
continue;
}
- if (ics[i].isInterface() && Modifier.isStatic(method.getModifiers())) {
- continue;
- }
worked.add(desc);
int ix = methods.size();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
index 8f52a34fc4..11257e9cc1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
@@ -19,11 +19,15 @@ package org.apache.dubbo.common.bytecode;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
+import javassist.ClassPool;
+import javassist.CtMethod;
+
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -31,6 +35,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
+import java.util.stream.Collectors;
/**
* Wrapper.
@@ -113,7 +118,7 @@ public abstract class Wrapper {
return OBJECT_WRAPPER;
}
- return WRAPPER_MAP.computeIfAbsent(c, key -> makeWrapper(key));
+ return WRAPPER_MAP.computeIfAbsent(c, Wrapper::makeWrapper);
}
private static Wrapper makeWrapper(Class> c) {
@@ -150,10 +155,32 @@ public abstract class Wrapper {
pts.put(fn, ft);
}
- Method[] methods = c.getMethods();
+ final ClassPool classPool = new ClassPool(ClassPool.getDefault());
+ classPool.appendClassPath(new CustomizedLoaderClassPath(cl));
+
+ List allMethod = new ArrayList<>();
+ try {
+ final CtMethod[] ctMethods = classPool.get(c.getName()).getMethods();
+ for (CtMethod method : ctMethods) {
+ allMethod.add(ReflectUtils.getDesc(method));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ Method[] methods = Arrays.stream(c.getMethods())
+ .filter(method -> allMethod.contains(ReflectUtils.getDesc(method)))
+ .collect(Collectors.toList())
+ .toArray(new Method[] {});
// get all public method.
boolean hasMethod = hasMethods(methods);
if (hasMethod) {
+ Map sameNameMethodCount = new HashMap<>((int) (methods.length / 0.75f) + 1);
+ for (Method m : methods) {
+ sameNameMethodCount.compute(m.getName(),
+ (key, oldValue) -> oldValue == null ? 1 : oldValue + 1);
+ }
+
c3.append(" try{");
for (Method m : methods) {
//ignore Object's method.
@@ -166,14 +193,8 @@ public abstract class Wrapper {
int len = m.getParameterTypes().length;
c3.append(" && ").append(" $3.length == ").append(len);
- boolean override = false;
- for (Method m2 : methods) {
- if (m != m2 && m.getName().equals(m2.getName())) {
- override = true;
- break;
- }
- }
- if (override) {
+ boolean overload = sameNameMethodCount.get(m.getName()) > 1;
+ if (overload) {
if (len > 0) {
for (int l = 0; l < len; l++) {
c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
@@ -226,7 +247,7 @@ public abstract class Wrapper {
}
}
c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");
- c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");
+ c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or getter method in class " + c.getName() + ".\"); }");
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
@@ -263,7 +284,7 @@ public abstract class Wrapper {
for (Method m : ms.values()) {
wc.getField("mts" + ix++).set(null, m.getParameterTypes());
}
- return (Wrapper) wc.newInstance();
+ return (Wrapper) wc.getDeclaredConstructor().newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
index 365cb7f36d..d09afadcce 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
@@ -22,6 +22,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
@@ -48,10 +49,8 @@ public class ClassUtils {
public static Object newInstance(String name) {
try {
- return forName(name).newInstance();
- } catch (InstantiationException e) {
- throw new IllegalStateException(e.getMessage(), e);
- } catch (IllegalAccessException e) {
+ return forName(name).getDeclaredConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
@@ -64,7 +63,7 @@ public class ClassUtils {
for (String pkg : packages) {
try {
return classForName(pkg + "." + className);
- } catch (ClassNotFoundException e2) {
+ } catch (ClassNotFoundException ignore) {
}
}
}
@@ -123,7 +122,7 @@ public class ClassUtils {
if (className.indexOf('.') == -1) {
try {
return arrayForName("java.lang." + className);
- } catch (ClassNotFoundException e2) {
+ } catch (ClassNotFoundException ignore) {
// ignore, let the original exception be thrown
}
}
@@ -431,7 +430,7 @@ public class ClassUtils {
}
return map;
}
-
+
/**
* get simple class name from qualified class name
*/
@@ -439,7 +438,6 @@ public class ClassUtils {
if (null == qualifiedName) {
return null;
}
-
int i = qualifiedName.lastIndexOf('.');
return i < 0 ? qualifiedName : qualifiedName.substring(i + 1);
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
index 0dc8f88138..7e01df30be 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
@@ -16,11 +16,6 @@
*/
package org.apache.dubbo.common.compiler.support;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
@@ -30,6 +25,11 @@ import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* CtClassBuilder is builder for CtClass
*
@@ -43,17 +43,17 @@ public class CtClassBuilder {
private String superClassName = "java.lang.Object";
- private List imports = new ArrayList<>();
+ private final List imports = new ArrayList<>();
- private Map fullNames = new HashMap<>();
+ private final Map fullNames = new HashMap<>();
- private List ifaces = new ArrayList<>();
+ private final List ifaces = new ArrayList<>();
- private List constructors = new ArrayList<>();
+ private final List constructors = new ArrayList<>();
- private List fields = new ArrayList<>();
+ private final List fields = new ArrayList<>();
- private List methods = new ArrayList<>();
+ private final List methods = new ArrayList<>();
public String getClassName() {
return className;
@@ -146,7 +146,7 @@ public class CtClassBuilder {
CtClass ctClass = pool.makeClass(className, pool.get(superClassName));
// add imported packages
- imports.stream().forEach(pool::importPackage);
+ imports.forEach(pool::importPackage);
// add implemented interfaces
for (String iface : ifaces) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
index 59a764fd43..c82e48dd4c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
@@ -61,14 +61,22 @@ public class JdkCompiler extends AbstractCompiler {
private final JavaFileManagerImpl javaFileManager;
- private volatile List options;
+ private final List options;
- public JdkCompiler() {
- options = new ArrayList();
- options.add("-source");
- options.add("1.6");
- options.add("-target");
- options.add("1.6");
+ private static final String DEFAULT_JAVA_VERSION = "1.8";
+
+ private static List buildDefaultOptions(String javaVersion) {
+ return Arrays.asList(
+ "-source", javaVersion, "-target", javaVersion
+ );
+ }
+
+ private static List buildDefaultOptions() {
+ return buildDefaultOptions(DEFAULT_JAVA_VERSION);
+ }
+
+ public JdkCompiler(List options) {
+ this.options = new ArrayList<>(options);
StandardJavaFileManager manager = compiler.getStandardFileManager(diagnosticCollector, null, null);
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader instanceof URLClassLoader
@@ -93,6 +101,14 @@ public class JdkCompiler extends AbstractCompiler {
javaFileManager = new JavaFileManagerImpl(manager, classLoader);
}
+ public JdkCompiler() {
+ this(buildDefaultOptions());
+ }
+
+ public JdkCompiler(String javaVersion) {
+ this(buildDefaultOptions(javaVersion));
+ }
+
@Override
public Class> doCompile(String name, String sourceCode) throws Throwable {
int i = name.lastIndexOf('.');
@@ -102,7 +118,7 @@ public class JdkCompiler extends AbstractCompiler {
javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName,
className + ClassUtils.JAVA_EXTENSION, javaFileObject);
Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options,
- null, Arrays.asList(javaFileObject)).call();
+ null, Collections.singletonList(javaFileObject)).call();
if (result == null || !result) {
throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector);
}
@@ -234,7 +250,7 @@ public class JdkCompiler extends AbstractCompiler {
}
}
- private final class ClassLoaderImpl extends ClassLoader {
+ private static final class ClassLoaderImpl extends ClassLoader {
private final Map classes = new HashMap();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java
index 31c3684fa3..0cc6af29d8 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java
@@ -130,7 +130,7 @@ public abstract class AbstractDynamicConfiguration implements DynamicConfigurati
@Override
public boolean removeConfig(String key, String group) {
- return execute(() -> doRemoveConfig(key, group), -1L);
+ return Boolean.TRUE.equals(execute(() -> doRemoveConfig(key, group), -1L));
}
/**
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
index 8195558cd8..f7c2ec71ba 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java
@@ -74,8 +74,12 @@ public class ConfigChangedEvent extends EventObject {
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ConfigChangedEvent)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ConfigChangedEvent)) {
+ return false;
+ }
ConfigChangedEvent that = (ConfigChangedEvent) o;
return Objects.equals(getKey(), that.getKey()) &&
Objects.equals(getGroup(), that.getGroup()) &&
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/Constants.java
index d85f86b11c..c0a5d9e408 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/Constants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/Constants.java
@@ -16,6 +16,7 @@
*/
package org.apache.dubbo.common.config.configcenter;
+@Deprecated
public interface Constants {
String CONFIG_CLUSTER_KEY = "config.cluster";
String CONFIG_NAMESPACE_KEY = "config.namespace";
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java
index 6ac9dd0d14..09296b6700 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java
@@ -26,7 +26,7 @@ import java.util.TreeSet;
import static java.util.Collections.emptySortedSet;
import static java.util.Collections.unmodifiableSortedSet;
-import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
import static org.apache.dubbo.common.utils.PathUtils.buildPath;
@@ -87,7 +87,7 @@ public abstract class TreePathDynamicConfiguration extends AbstractDynamicConfig
@Override
public final boolean publishConfig(String key, String group, String content) {
String pathKey = buildPathKey(group, key);
- return execute(() -> doPublishConfig(pathKey, content), getDefaultTimeout());
+ return Boolean.TRUE.equals(execute(() -> doPublishConfig(pathKey, content), getDefaultTimeout()));
}
@Override
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/ClusterRules.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/ClusterRules.java
new file mode 100644
index 0000000000..f5f87299c4
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/ClusterRules.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.constants;
+
+/**
+ * constant for Cluster fault-tolerant mode
+ */
+public interface ClusterRules {
+
+ /**
+ * When invoke fails, log the initial error and retry other invokers
+ * (retry n times, which means at most n different invokers will be invoked)
+ **/
+ String FAIL_OVER = "failover";
+
+ /**
+ * Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error.
+ **/
+ String FAIL_FAST = "failfast";
+
+ /**
+ * When invoke fails, log the error message and ignore this error by returning an empty Result.
+ **/
+ String FAIL_SAFE = "failsafe";
+
+ /**
+ * When fails, record failure requests and schedule for retry on a regular interval.
+ **/
+ String FAIL_BACK = "failback";
+
+ /**
+ * Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.
+ **/
+ String FORKING = "forking";
+
+ /**
+ * Call all providers by broadcast, call them one by one, and report an error if any one reports an error
+ **/
+ String BROADCAST = "broadcast";
+
+
+ String AVAILABLE = "available";
+
+ String MERGEABLE = "mergeable";
+
+ String EMPTY = "";
+
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index 9119f323e5..245dd1d55c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@ -114,6 +114,8 @@ public interface CommonConstants {
String IO_THREADS_KEY = "iothreads";
+ String KEEP_ALIVE_KEY = "keep.alive";
+
int DEFAULT_QUEUES = 0;
int DEFAULT_ALIVE = 60 * 1000;
@@ -207,6 +209,8 @@ public interface CommonConstants {
String REMOTE_METADATA_STORAGE_TYPE = "remote";
+ String GENERIC_KEY = "generic";
+
/**
* The composite metadata storage type includes {@link #DEFAULT_METADATA_STORAGE_TYPE "local"} and
* {@link #REMOTE_METADATA_STORAGE_TYPE "remote"}.
@@ -248,6 +252,11 @@ public interface CommonConstants {
String PORT_KEY = "port";
String DUBBO_IP_TO_BIND = "DUBBO_IP_TO_BIND";
+ /**
+ * broadcast cluster.
+ */
+ String BROADCAST_CLUSTER = "broadcast";
+
/**
* The property name for {@link NetworkInterface#getDisplayName() the name of network interface} that
* the Dubbo application prefers
@@ -311,6 +320,8 @@ public interface CommonConstants {
String GENERIC_SERIALIZATION_NATIVE_JAVA = "nativejava";
+ String GENERIC_SERIALIZATION_GSON = "gson";
+
String GENERIC_SERIALIZATION_DEFAULT = "true";
String GENERIC_SERIALIZATION_BEAN = "bean";
@@ -401,4 +412,9 @@ public interface CommonConstants {
String CLUSTER_INTERCEPTOR_COMPATIBLE_KEY = "dubbo.application.cluster.interceptor.compatible";
String UTF8ENCODE = "UTF-8";
+
+ /** Pseudo URL prefix for loading from the class path: "classpath:". */
+ String CLASSPATH_URL_PREFIX = "classpath:";
+
+ String DEFAULT_VERSION = "0.0.0";
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoadbalanceRules.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoadbalanceRules.java
new file mode 100644
index 0000000000..c0e9285d0e
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoadbalanceRules.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.constants;
+
+/**
+ * constant for Loadbalance strategy
+ */
+public interface LoadbalanceRules {
+
+ /**
+ * This class select one provider from multiple providers randomly.
+ **/
+ String RANDOM = "random";
+
+ /**
+ * Round robin load balance.
+ **/
+ String ROUND_ROBIN = "roundrobin";
+
+ /**
+ * Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.
+ **/
+ String LEAST_ACTIVE = "leastactive";
+
+ /**
+ * Consistent Hash, requests with the same parameters are always sent to the same provider.
+ **/
+ String CONSISTENT_HASH = "consistenthash";
+
+ /**
+ * Filter the number of invokers with the shortest response time of success calls and count the weights and quantities of these invokers.
+ **/
+ String SHORTEST_RESPONSE = "shortestresponse";
+
+ String EMPTY = "";
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index 629eaef77b..a7bf66fb66 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -114,6 +114,11 @@ public class ExtensionLoader {
private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
+ /**
+ * Record all unacceptable exceptions when using SPI
+ */
+ private Set unacceptableExceptions = new ConcurrentHashSet<>();
+
public static void setLoadingStrategies(LoadingStrategy... strategies) {
if (ArrayUtils.isNotEmpty(strategies)) {
ExtensionLoader.strategies = strategies;
@@ -624,26 +629,25 @@ public class ExtensionLoader {
}
private IllegalStateException findException(String name) {
- for (Map.Entry entry : exceptions.entrySet()) {
- if (entry.getKey().toLowerCase().contains(name.toLowerCase())) {
- return entry.getValue();
- }
- }
StringBuilder buf = new StringBuilder("No such extension " + type.getName() + " by name " + name);
-
int i = 1;
for (Map.Entry entry : exceptions.entrySet()) {
- if (i == 1) {
- buf.append(", possible causes: ");
+ if (entry.getKey().toLowerCase().startsWith(name.toLowerCase())) {
+ if (i == 1) {
+ buf.append(", possible causes: ");
+ }
+ buf.append("\r\n(");
+ buf.append(i++);
+ buf.append(") ");
+ buf.append(entry.getKey());
+ buf.append(":\r\n");
+ buf.append(StringUtils.toString(entry.getValue()));
}
+ }
- buf.append("\r\n(");
- buf.append(i++);
- buf.append(") ");
- buf.append(entry.getKey());
- buf.append(":\r\n");
- buf.append(StringUtils.toString(entry.getValue()));
+ if (i == 1) {
+ buf.append(", no related exception was found, please check whether related SPI module is missing.");
}
return new IllegalStateException(buf.toString());
}
@@ -651,13 +655,13 @@ public class ExtensionLoader {
@SuppressWarnings("unchecked")
private T createExtension(String name, boolean wrap) {
Class> clazz = getExtensionClasses().get(name);
- if (clazz == null) {
+ if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
- EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
+ EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
@@ -872,6 +876,7 @@ public class ExtensionLoader {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
+ String clazz = null;
while ((line = reader.readLine()) != null) {
final int ci = line.indexOf('#');
if (ci >= 0) {
@@ -884,10 +889,12 @@ public class ExtensionLoader {
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
- line = line.substring(i + 1).trim();
+ clazz = line.substring(i + 1).trim();
+ } else {
+ clazz = line;
}
- if (line.length() > 0 && !isExcluded(line, excludedPackages)) {
- loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden);
+ if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
+ loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
@@ -961,6 +968,8 @@ public class ExtensionLoader {
if (c == null || overridden) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
+ // duplicate implementation is unacceptable
+ unacceptableExceptions.add(name);
String duplicateMsg = "Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
logger.error(duplicateMsg);
throw new IllegalStateException(duplicateMsg);
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Wrapper.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Wrapper.java
index 670aae6de0..2d5780d8f1 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Wrapper.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Wrapper.java
@@ -16,9 +16,13 @@
*/
package org.apache.dubbo.common.extension;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* The annotated class will only work as a wrapper when the condition matches.
*/
+@Retention(RetentionPolicy.RUNTIME)
public @interface Wrapper {
/**
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
index 3aa3fd9ed1..bc6e4e39bb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/json/J2oVisitor.java
@@ -259,9 +259,7 @@ class J2oVisitor implements JSONVisitor {
try {
mValue = mType.newInstance();
mWrapper = Wrapper.getWrapper(mType);
- } catch (IllegalAccessException e) {
- throw new ParseException(StringUtils.toString(e));
- } catch (InstantiationException e) {
+ } catch (IllegalAccessException | InstantiationException e) {
throw new ParseException(StringUtils.toString(e));
}
}
@@ -304,9 +302,7 @@ class J2oVisitor implements JSONVisitor {
field.setAccessible(true);
}
field.set(mValue, obj);
- } catch (NoSuchFieldException e) {
- throw new ParseException(StringUtils.toString(e));
- } catch (IllegalAccessException e) {
+ } catch (NoSuchFieldException | IllegalAccessException e) {
throw new ParseException(StringUtils.toString(e));
}
} else if (!CLASS_PROPERTY.equals(name)) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
index babb3ed3c9..76a6a0b8af 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java
@@ -63,7 +63,7 @@ public interface Prioritized extends Comparable {
/**
* Get the priority
*
- * @return the default is {@link #MIN_PRIORITY minimum one}
+ * @return the default is {@link #NORMAL_PRIORITY}
*/
default int getPriority() {
return NORMAL_PRIORITY;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java
new file mode 100644
index 0000000000..6cc8db8fee
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java
@@ -0,0 +1,53 @@
+/*
+ * 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.threadlocal;
+
+
+/**
+ * InternalRunnable
+ * There is a risk of memory leak when using {@link InternalThreadLocal} without calling
+ * {@link InternalThreadLocal#removeAll()}.
+ * This design is learning from {@see io.netty.util.concurrent.FastThreadLocalRunnable} which is in Netty.
+ */
+public class InternalRunnable implements Runnable{
+ private final Runnable runnable;
+
+ public InternalRunnable(Runnable runnable){
+ this.runnable=runnable;
+ }
+
+ /**
+ * After the task execution is completed, it will call {@link InternalThreadLocal#removeAll()} to clear
+ * unnecessary variables in the thread.
+ */
+ @Override
+ public void run() {
+ try{
+ runnable.run();
+ }finally {
+ InternalThreadLocal.removeAll();
+ }
+ }
+
+ /**
+ * Wrap ordinary Runnable into {@link InternalThreadLocal}.
+ */
+ static Runnable Wrap(Runnable runnable){
+ return runnable instanceof InternalRunnable?runnable:new InternalRunnable(runnable);
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java
index 8820f12cc2..13c7463db8 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java
@@ -58,7 +58,7 @@ public class InternalThreadLocal {
if (v != null && v != InternalThreadLocalMap.UNSET) {
Set> variablesToRemove = (Set>) v;
InternalThreadLocal>[] variablesToRemoveArray =
- variablesToRemove.toArray(new InternalThreadLocal[variablesToRemove.size()]);
+ variablesToRemove.toArray(new InternalThreadLocal[0]);
for (InternalThreadLocal> tlv : variablesToRemoveArray) {
tlv.remove(threadLocalMap);
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
index 52b8d562c0..0bb305f03f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java
@@ -40,7 +40,7 @@ public class NamedInternalThreadFactory extends NamedThreadFactory {
@Override
public Thread newThread(Runnable runnable) {
String name = mPrefix + mThreadNum.getAndIncrement();
- InternalThread ret = new InternalThread(mGroup, runnable, name, 0);
+ InternalThread ret = new InternalThread(mGroup, InternalRunnable.Wrap(runnable), name, 0);
ret.setDaemon(mDaemon);
return ret;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
index 0225132e72..bc9042c8e4 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java
@@ -32,7 +32,7 @@ import java.util.concurrent.TimeoutException;
/**
* The most important difference between this Executor and other normal Executor is that this one doesn't manage
* any thread.
- *
+ *
* Tasks submitted to this executor through {@link #execute(Runnable)} will not get scheduled to a specific thread, though normal executors always do the schedule.
* Those tasks are stored in a blocking queue and will only be executed when a thread calls {@link #waitAndDrain()}, the thread executing the task
* is exactly the same as the one calling waitAndDrain.
@@ -86,7 +86,13 @@ public class ThreadlessExecutor extends AbstractExecutorService {
return;
}
- Runnable runnable = queue.take();
+ Runnable runnable;
+ try {
+ runnable = queue.take();
+ }catch (InterruptedException e){
+ waiting = false;
+ throw e;
+ }
synchronized (lock) {
waiting = false;
@@ -95,12 +101,7 @@ public class ThreadlessExecutor extends AbstractExecutorService {
runnable = queue.poll();
while (runnable != null) {
- try {
- runnable.run();
- } catch (Throwable t) {
- logger.info(t);
-
- }
+ runnable.run();
runnable = queue.poll();
}
// mark the status of ThreadlessExecutor as finished.
@@ -131,6 +132,7 @@ public class ThreadlessExecutor extends AbstractExecutorService {
*/
@Override
public void execute(Runnable runnable) {
+ runnable = new RunnableWrapper(runnable);
synchronized (lock) {
if (!waiting) {
sharedExecutor.execute(runnable);
@@ -180,4 +182,21 @@ public class ThreadlessExecutor extends AbstractExecutorService {
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return false;
}
+
+ private static class RunnableWrapper implements Runnable {
+ private Runnable runnable;
+
+ public RunnableWrapper(Runnable runnable) {
+ this.runnable = runnable;
+ }
+
+ @Override
+ public void run() {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ logger.info(t);
+ }
+ }
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
index c6865eb225..49fdd89379 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java
@@ -16,6 +16,14 @@
*/
package org.apache.dubbo.common.threadpool.support;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedEvent;
+import org.apache.dubbo.common.utils.JVMUtil;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.event.EventDispatcher;
+
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
@@ -26,13 +34,7 @@ import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
-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.threadpool.event.ThreadPoolExhaustedEvent;
-import org.apache.dubbo.common.utils.JVMUtil;
-import org.apache.dubbo.event.EventDispatcher;
-
+import static java.lang.String.format;
import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
/**
@@ -61,6 +63,8 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
private static Semaphore guard = new Semaphore(1);
+ private static final String USER_HOME = System.getProperty("user.home");
+
public AbortPolicyWithReport(String threadName, URL url) {
this.threadName = threadName;
this.url = url;
@@ -104,7 +108,7 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(() -> {
- String dumpPath = url.getParameter(DUMP_DIRECTORY, System.getProperty("user.home"));
+ String dumpPath = getDumpPath();
SimpleDateFormat sdf;
@@ -134,4 +138,21 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
}
+ private String getDumpPath() {
+ final String dumpPath = url.getParameter(DUMP_DIRECTORY);
+ if (StringUtils.isEmpty(dumpPath)) {
+ return USER_HOME;
+ }
+ final File dumpDirectory = new File(dumpPath);
+ if (!dumpDirectory.exists()) {
+ if (dumpDirectory.mkdirs()) {
+ logger.info(format("Dubbo dump directory[%s] created", dumpDirectory.getAbsolutePath()));
+ } else {
+ logger.warn(format("Dubbo dump directory[%s] can't be created, use the 'user.home'[%s]",
+ dumpDirectory.getAbsolutePath(), USER_HOME));
+ return USER_HOME;
+ }
+ }
+ return dumpPath;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java
index d695b46d16..487cc74ba5 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java
@@ -805,8 +805,10 @@ public class HashedWheelTimer implements Timer {
return head;
}
}
-
+
+ private static final boolean IS_OS_WINDOWS = System.getProperty("os.name", "").toLowerCase(Locale.US).contains("win");
+
private boolean isWindows() {
- return System.getProperty("os.name", "").toLowerCase(Locale.US).contains("win");
+ return IS_OS_WINDOWS;
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
index 4c333eabe6..6110639376 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
@@ -37,6 +37,7 @@ import java.util.StringJoiner;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
/**
* A class which store parameters for {@link URL}
@@ -178,7 +179,7 @@ public class URLParam implements Serializable {
* Specially, in some situation like `method1.1.callback=true`, key is `1.callback`.
*
* @param method method name
- * @param key key
+ * @param key key
* @return value
*/
public String getMethodParameter(String method, String key) {
@@ -191,7 +192,7 @@ public class URLParam implements Serializable {
* Specially, in some situation like `method1.1.callback=true`, key is `1.callback`.
*
* @param method method name
- * @param key key
+ * @param key key
* @return value
*/
public String getMethodParameterStrict(String method, String key) {
@@ -853,10 +854,27 @@ public class URLParam implements Serializable {
return false;
}
URLParam urlParam = (URLParam) o;
- return Objects.equals(KEY, urlParam.KEY)
+
+ if (Objects.equals(KEY, urlParam.KEY)
&& Objects.equals(DEFAULT_KEY, urlParam.DEFAULT_KEY)
- && Arrays.equals(VALUE, urlParam.VALUE)
- && Objects.equals(EXTRA_PARAMS, urlParam.EXTRA_PARAMS);
+ && Arrays.equals(VALUE, urlParam.VALUE)) {
+ if (CollectionUtils.isNotEmptyMap(EXTRA_PARAMS)) {
+ if (CollectionUtils.isEmptyMap(urlParam.EXTRA_PARAMS) || EXTRA_PARAMS.size() != urlParam.EXTRA_PARAMS.size()) {
+ return false;
+ }
+ for (Map.Entry entry : EXTRA_PARAMS.entrySet()) {
+ if (TIMESTAMP_KEY.equals(entry.getKey())) {
+ continue;
+ }
+ if (!entry.getValue().equals(urlParam.EXTRA_PARAMS.get(entry.getKey()))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return CollectionUtils.isEmptyMap(urlParam.EXTRA_PARAMS);
+ }
+ return false;
}
private int hashCodeCache = -1;
@@ -864,7 +882,11 @@ public class URLParam implements Serializable {
@Override
public int hashCode() {
if (hashCodeCache == -1) {
- hashCodeCache = EXTRA_PARAMS.hashCode();
+ for (Map.Entry entry : EXTRA_PARAMS.entrySet()) {
+ if (!TIMESTAMP_KEY.equals(entry.getKey())) {
+ hashCodeCache = hashCodeCache * 31 + Objects.hashCode(entry);
+ }
+ }
for (Integer value : VALUE) {
hashCodeCache = hashCodeCache * 31 + value;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
index 600c8aaef9..8da5f1d05d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
@@ -22,6 +22,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -40,6 +41,7 @@ import static org.apache.dubbo.common.function.Streams.filterFirst;
import static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes;
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
import static org.apache.dubbo.common.utils.CollectionUtils.first;
+import static org.apache.dubbo.common.utils.MethodUtils.findMethod;
import static org.apache.dubbo.common.utils.MethodUtils.invokeMethod;
/**
@@ -449,4 +451,32 @@ public interface AnnotationUtils {
Class extends Annotation>... annotationTypes) {
return isAnnotationPresent(type, false, annotationTypes);
}
+
+
+ /**
+ * Get the default value of attribute on the specified annotation
+ *
+ * @param annotation {@link Annotation} object
+ * @param attributeName the name of attribute
+ * @param the type of value
+ * @return null if not found
+ * @since 2.7.9
+ */
+ static T getDefaultValue(Annotation annotation, String attributeName) {
+ return getDefaultValue(annotation.annotationType(), attributeName);
+ }
+
+ /**
+ * Get the default value of attribute on the specified annotation
+ *
+ * @param annotationType the type of {@link Annotation}
+ * @param attributeName the name of attribute
+ * @param the type of value
+ * @return null if not found
+ * @since 2.7.9
+ */
+ static T getDefaultValue(Class extends Annotation> annotationType, String attributeName) {
+ Method method = findMethod(annotationType, attributeName);
+ return (T) (method == null ? null : method.getDefaultValue());
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
index 5be000d78f..e648598867 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java
@@ -66,4 +66,16 @@ public final class ArrayUtils {
return -1;
}
}
+
+ /**
+ * Convert from variable arguments to array
+ *
+ * @param values variable arguments
+ * @param The class
+ * @return array
+ * @since 2.7.9
+ */
+ public static T[] of(T... values) {
+ return values;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java
index 2fb515c9fc..a437a7d6a7 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java
@@ -43,21 +43,6 @@ public class ClassUtils {
* Suffix for array class names: "[]"
*/
public static final String ARRAY_SUFFIX = "[]";
- /**
- * Prefix for internal array class names: "[L"
- */
- private static final String INTERNAL_ARRAY_PREFIX = "[L";
- /**
- * Map with primitive type name as key and corresponding primitive type as
- * value, for example: "int" -> "int.class".
- */
- private static final Map> PRIMITIVE_TYPE_NAME_MAP = new HashMap>(32);
- /**
- * Map with primitive wrapper type as key and corresponding primitive type
- * as value, for example: Integer.class -> int.class.
- */
- private static final Map, Class>> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap, Class>>(16);
-
/**
* Simple Types including:
*
@@ -94,7 +79,20 @@ public class ClassUtils {
Date.class,
Object.class
);
-
+ /**
+ * Prefix for internal array class names: "[L"
+ */
+ private static final String INTERNAL_ARRAY_PREFIX = "[L";
+ /**
+ * Map with primitive type name as key and corresponding primitive type as
+ * value, for example: "int" -> "int.class".
+ */
+ private static final Map> PRIMITIVE_TYPE_NAME_MAP = new HashMap>(32);
+ /**
+ * Map with primitive wrapper type as key and corresponding primitive type
+ * as value, for example: Integer.class -> int.class.
+ */
+ private static final Map, Class>> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap, Class>>(16);
private static final char PACKAGE_SEPARATOR_CHAR = '.';
static {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
index 1b73370c0b..13c55eb133 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java
@@ -39,28 +39,25 @@ import static java.util.Collections.unmodifiableSet;
*/
public class CollectionUtils {
- private static final Comparator SIMPLE_NAME_COMPARATOR = new Comparator() {
- @Override
- public int compare(String s1, String s2) {
- if (s1 == null && s2 == null) {
- return 0;
- }
- if (s1 == null) {
- return -1;
- }
- if (s2 == null) {
- return 1;
- }
- int i1 = s1.lastIndexOf('.');
- if (i1 >= 0) {
- s1 = s1.substring(i1 + 1);
- }
- int i2 = s2.lastIndexOf('.');
- if (i2 >= 0) {
- s2 = s2.substring(i2 + 1);
- }
- return s1.compareToIgnoreCase(s2);
+ private static final Comparator SIMPLE_NAME_COMPARATOR = (s1, s2) -> {
+ if (s1 == null && s2 == null) {
+ return 0;
}
+ if (s1 == null) {
+ return -1;
+ }
+ if (s2 == null) {
+ return 1;
+ }
+ int i1 = s1.lastIndexOf('.');
+ if (i1 >= 0) {
+ s1 = s1.substring(i1 + 1);
+ }
+ int i2 = s2.lastIndexOf('.');
+ if (i2 >= 0) {
+ s2 = s2.substring(i2 + 1);
+ }
+ return s1.compareToIgnoreCase(s2);
};
private CollectionUtils() {
@@ -324,9 +321,7 @@ public class CollectionUtils {
try {
return one.containsAll(another);
- } catch (ClassCastException unused) {
- return false;
- } catch (NullPointerException unused) {
+ } catch (ClassCastException | NullPointerException unused) {
return false;
}
}
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 5d5cc5c80a..fecec8b992 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
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
@@ -111,17 +112,23 @@ public class CompatibleTypeUtils {
+ DATE_FORMAT + ", cause: " + e.getMessage(), e);
}
}
- if (type == java.time.LocalDateTime.class || type == java.time.LocalDate.class
- || type == java.time.LocalTime.class) {
-
- LocalDateTime localDateTime = LocalDateTime.parse(string);
- if (type == java.time.LocalDate.class) {
- return localDateTime.toLocalDate();
+ if (type == java.time.LocalDateTime.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
}
- if (type == java.time.LocalTime.class) {
- return localDateTime.toLocalTime();
+ return LocalDateTime.parse(string);
+ }
+ if (type == java.time.LocalDate.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
}
- return localDateTime;
+ return LocalDate.parse(string);
+ }
+ if (type == java.time.LocalTime.class) {
+ if (StringUtils.isEmpty(string)) {
+ return null;
+ }
+ return LocalDateTime.parse(string).toLocalTime();
}
if (type == Class.class) {
try {
@@ -200,19 +207,19 @@ public class CompatibleTypeUtils {
}
}
if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {
+ int length = Array.getLength(value);
Collection collection;
if (!type.isInterface()) {
try {
collection = (Collection) type.newInstance();
} catch (Throwable e) {
- collection = new ArrayList