diff --git a/.github/ISSUE_TEMPLATE/1-bug.yml b/.github/ISSUE_TEMPLATE/1-bug.yml new file mode 100644 index 0000000000..e7d06e48ec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug.yml @@ -0,0 +1,126 @@ +# +# 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. +# + +name: Bug Report +description: File a bug report +title: "[Bug] " +labels: ["status/need-triage"] +projects: ["apache/337"] +body: +- type: markdown + attributes: + value: | + Dubbo logo + + Thank you for finding the time to report the problem! We really appreciate the community efforts to improve Dubbo. + + Please make sure what you are reporting is indeed a bug with reproducible steps, if you want to ask questions + or share ideas, please [subscribe to our mailing list](mailto:dev-subscribe@dubbo.apache.org) and sent + emails to [our mailing list](mailto:dev@dubbo.apache.org), you can also head to our + [Discussion](https://github.com/apache/dubbo/discussions) tab. + + If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy). + + **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.** + Remember that non-English issues is quite not friendly for everyone, and might unable to get the response! + +- type: checkboxes + attributes: + label: Pre-check + options: + - label: > + I am sure that all the content I provide is in English. + required: true + +- type: checkboxes + attributes: + label: Search before asking + description: > + Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see + whether the same issue was reported already. + options: + - label: > + I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar + issues. + required: true + +- type: input + attributes: + label: Dubbo Version + description: "Which Dubbo version, JDK version and operating system did you use?" + placeholder: "Example: Dubbo Java 3.2.12, OpenJDK 1.8, Ubuntu 20.04" + validations: + required: true + +- type: textarea + attributes: + label: Steps to reproduce this issue + description: > + Describe how to reproduce this issue.If you are not able to provide a reproducible case, + please open a [Discussion](https://github.com/apache/dubbo/discussions) instead. + placeholder: > + Please provide the context in which the problem occurred and explain what happened. + A [GitHub address] would be helpful for maintainers to reproduce the problem. + validations: + required: true + +- type: textarea + attributes: + label: What you expected to happen + description: What do you think went wrong? + placeholder: > + Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy and paste + the fragment of logs showing the exact error messages or wrong behaviour and screenshots for + UI problems. You can include files by dragging and dropping them here. + + **NOTE**: please copy and paste texts instead of taking screenshots of them for easy future search. + validations: + required: true + +- type: textarea + attributes: + label: Anything else + description: Anything else we need to know? + placeholder: > + How often does this problem occur? (Once? Every time? Only when certain conditions are met?) + Any relevant logs to include? Put them here inside fenced + ``` ``` blocks or inside a collapsable details tag if it's too long: +
x.log lots of stuff
+ +- type: checkboxes + attributes: + label: Are you willing to submit a pull request to fix on your own? + description: > + This is absolutely not required, but we are happy to guide you in the contribution process + especially if you already have a good understanding of how to implement the fix. + Dubbo is a totally community-driven project and we love to bring new contributors in. + options: + - label: Yes I am willing to submit a pull request on my own! + +- type: checkboxes + attributes: + label: Code of Conduct + description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it. + options: + - label: > + I agree to follow this project's + [Code of Conduct](https://www.apache.org/foundation/policies/conduct) + required: true + +- type: markdown + attributes: + value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/2-feature.yml b/.github/ISSUE_TEMPLATE/2-feature.yml new file mode 100644 index 0000000000..501122efcd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature.yml @@ -0,0 +1,90 @@ +# +# 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. +# + +name: Feature Request +description: Create a Feature Request for Dubbo +title: "[Feature] " +labels: ["status/need-triage"] +projects: ["apache/337"] +body: +- type: markdown + attributes: + value: | + Dubbo logo + + Thank you for finding the time to propose new feature! + + We really appreciate the community efforts to improve Dubbo. + + **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.** + Remember that non-English issues is quite not friendly for everyone, and might unable to get the response! + +- type: checkboxes + attributes: + label: Pre-check + options: + - label: > + I am sure that all the content I provide is in English. + required: true + +- type: checkboxes + attributes: + label: Search before asking + description: > + Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see + whether the same feature was requested already. + options: + - label: > + I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar + feature requirement. + required: true + +- type: textarea + attributes: + label: Descriptions + description: A short description of your feature + validations: + required: true + +- type: textarea + attributes: + label: Related issues + description: Is there currently another issue associated with this? + +- type: checkboxes + attributes: + label: Are you willing to submit a pull request to fix on your own? + description: > + This is absolutely not required, but we are happy to guide you in the contribution process + especially if you already have a good understanding of how to implement the feature. + Dubbo is a totally community-driven project and we love to bring new contributors in. + options: + - label: Yes I am willing to submit a pull request on my own! + +- type: checkboxes + attributes: + label: Code of Conduct + description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it. + options: + - label: > + I agree to follow this project's + [Code of Conduct](https://www.apache.org/foundation/policies/conduct) + required: true + +- type: markdown + attributes: + value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d5eade3841..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Bug Report -about: Report a bug in Dubbo -title: '' -labels: status/need-triage -assignees: '' - ---- - - -- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate. - -### Environment - -* Dubbo version: xxx -* Operating System version: xxx -* Java version: xxx - -### Steps to reproduce this issue - -1. xxx -2. xxx -3. xxx - -Pls. provide [GitHub address] to reproduce this issue. - -### Expected Behavior - - - -### Actual Behavior - - - -If there is an exception, please attach the exception trace: - -``` -Just put your stack trace here! -``` diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0602b36b44..b4e5b9e035 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,22 @@ -blank_issues_enabled: true +# +# 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. +# + +blank_issues_enabled: false contact_links: - - name: Dubbo Community Repo - url: https://github.com/apache/dubbo-website - about: Please see our community docs here. - - name: Report a security issue - url: https://github.com/apache/dubbo/security/policy - about: Please report security vulnerabilities using these instructions. + - name: Question & FAQ & Proposal + url: https://github.com/apache/dubbo/discussions/ + about: Ask a question, request support or submit a proposal for Apache Dubbo. diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md deleted file mode 100644 index dd9c3d8109..0000000000 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Discussion -about: Start a discussion for Dubbo -title: '' -labels: type/discussion -assignees: '' ---- - - - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 7a849f66b3..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Feature Request -about: Create a Feature Request for Dubbo -title: '' -labels: type/feature -assignees: '' - ---- - - -- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate. -- [ ] I have searched the [release notes](https://github.com/apache/dubbo/releases) of this repository and believe that this is not a duplicate. - -## Describe the feature - - diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md deleted file mode 100644 index ffde91a9df..0000000000 --- a/.github/ISSUE_TEMPLATE/proposal.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: Proposal -about: Create a technical proposal for Dubbo -title: '' -labels: type/proposal -assignees: '' - ---- - - -- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate. - -## Describe the proposal - - diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 86c4d8444a..0000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Question -about: Ask a question about Dubbo -title: '' -labels: type/question -assignees: '' - ---- - - -- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate. - -## Ask your question here diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index 087eacbade..be68810f4a 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java @@ -25,6 +25,7 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.common.utils.LockUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metrics.event.MetricsEventBus; @@ -56,6 +57,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; @@ -122,6 +125,8 @@ public abstract class AbstractDirectory implements Directory { private volatile ScheduledFuture connectivityCheckFuture; + private final ReentrantLock invokerRefreshLock = new ReentrantLock(); + /** * The max count of invokers for each reconnect task select to try to reconnect. */ @@ -293,17 +298,19 @@ public abstract class AbstractDirectory implements Directory { @Override public void addInvalidateInvoker(Invoker invoker) { - // 1. remove this invoker from validInvokers list, this invoker will not be listed in the next time - if (removeValidInvoker(invoker)) { - // 2. add this invoker to reconnect list - invokersToReconnect.add(invoker); - // 3. try start check connectivity task - checkConnectivity(); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + // 1. remove this invoker from validInvokers list, this invoker will not be listed in the next time + if (removeValidInvoker(invoker)) { + // 2. add this invoker to reconnect list + invokersToReconnect.add(invoker); + // 3. try start check connectivity task + checkConnectivity(); - logger.info("The invoker " + invoker.getUrl() - + " has been added to invalidate list due to connectivity problem. " - + "Will trying to reconnect to it in the background."); - } + logger.info("The invoker " + invoker.getUrl() + + " has been added to invalidate list due to connectivity problem. " + + "Will trying to reconnect to it in the background."); + } + }); } public void checkConnectivity() { @@ -322,23 +329,30 @@ public abstract class AbstractDirectory implements Directory { // 1. pick invokers from invokersToReconnect // limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor // for long time - if (invokersToReconnect.size() < reconnectTaskTryCount) { - invokersToTry.addAll(invokersToReconnect); - } else { - for (int i = 0; i < reconnectTaskTryCount; i++) { - Invoker tInvoker = invokersToReconnect.get( - ThreadLocalRandom.current().nextInt(invokersToReconnect.size())); - if (!invokersToTry.contains(tInvoker)) { - // ignore if is selected, invokersToTry's size is always smaller than - // reconnectTaskTryCount + 1 - invokersToTry.add(tInvoker); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + if (invokersToReconnect.size() < reconnectTaskTryCount) { + invokersToTry.addAll(invokersToReconnect); + } else { + for (int i = 0; i < reconnectTaskTryCount; i++) { + Invoker tInvoker = invokersToReconnect.get( + ThreadLocalRandom.current().nextInt(invokersToReconnect.size())); + if (!invokersToTry.contains(tInvoker)) { + // ignore if is selected, invokersToTry's size is always smaller than + // reconnectTaskTryCount + 1 + invokersToTry.add(tInvoker); + } } } - } + }); // 2. try to check the invoker's status for (Invoker invoker : invokersToTry) { - if (invokers.contains(invoker)) { + AtomicBoolean invokerExist = new AtomicBoolean(false); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + invokerExist.set(invokers.contains(invoker)); + }); + // Should not lock here, `invoker.isAvailable` may need some time to check + if (invokerExist.get()) { if (invoker.isAvailable()) { needDeleteList.add(invoker); } @@ -348,22 +362,37 @@ public abstract class AbstractDirectory implements Directory { } // 3. recover valid invoker - for (Invoker tInvoker : needDeleteList) { - if (invokers.contains(tInvoker)) { - addValidInvoker(tInvoker); - logger.info( - "Recover service address: " + tInvoker.getUrl() + " from invalid list."); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + for (Invoker tInvoker : needDeleteList) { + if (invokers.contains(tInvoker)) { + addValidInvoker(tInvoker); + logger.info("Recover service address: " + tInvoker.getUrl() + + " from invalid list."); + } else { + logger.info( + "The invoker " + tInvoker.getUrl() + + " has been removed from invokers list. Will remove it in reconnect list."); + } + invokersToReconnect.remove(tInvoker); } - invokersToReconnect.remove(tInvoker); - } + }); + } catch (Throwable t) { + logger.error( + LoggerCodeConstants.INTERNAL_ERROR, + "", + "", + "Error occurred when check connectivity. ", + t); } finally { checkConnectivityPermit.release(); } // 4. submit new task if it has more to recover - if (!invokersToReconnect.isEmpty()) { - checkConnectivity(); - } + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + if (!invokersToReconnect.isEmpty()) { + checkConnectivity(); + } + }); MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent( applicationModel, getSummary(), getDirectoryMeta())); }, @@ -382,9 +411,11 @@ public abstract class AbstractDirectory implements Directory { * 4. all the invokers disappeared from total invokers should be removed in the disabled invokers list */ public void refreshInvoker() { - if (invokersInitialized) { - refreshInvokerInternal(); - } + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + if (invokersInitialized) { + refreshInvokerInternal(); + } + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } @@ -393,7 +424,7 @@ public abstract class AbstractDirectory implements Directory { return Collections.emptyMap(); } - private synchronized void refreshInvokerInternal() { + private void refreshInvokerInternal() { BitList> copiedInvokers = invokers.clone(); refreshInvokers(copiedInvokers, invokersToReconnect); refreshInvokers(copiedInvokers, disabledInvokers); @@ -414,25 +445,29 @@ public abstract class AbstractDirectory implements Directory { @Override public void addDisabledInvoker(Invoker invoker) { - if (invokers.contains(invoker)) { - disabledInvokers.add(invoker); - removeValidInvoker(invoker); - logger.info("Disable service address: " + invoker.getUrl() + "."); - } + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + if (invokers.contains(invoker)) { + disabledInvokers.add(invoker); + removeValidInvoker(invoker); + logger.info("Disable service address: " + invoker.getUrl() + "."); + } + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } @Override public void recoverDisabledInvoker(Invoker invoker) { - if (disabledInvokers.remove(invoker)) { - try { - addValidInvoker(invoker); - logger.info("Recover service address: " + invoker.getUrl() + " from disabled list."); - } catch (Throwable ignore) { + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + if (disabledInvokers.remove(invoker)) { + try { + addValidInvoker(invoker); + logger.info("Recover service address: " + invoker.getUrl() + " from disabled list."); + } catch (Throwable ignore) { + } } - } + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } @@ -491,9 +526,11 @@ public abstract class AbstractDirectory implements Directory { } protected void setInvokers(BitList> invokers) { - this.invokers = invokers; - refreshInvokerInternal(); - this.invokersInitialized = true; + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + this.invokers = invokers; + refreshInvokerInternal(); + this.invokersInitialized = true; + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); @@ -501,29 +538,31 @@ public abstract class AbstractDirectory implements Directory { protected void destroyInvokers() { // set empty instead of clearing to support concurrent access. - this.invokers = BitList.emptyList(); - this.validInvokers = BitList.emptyList(); - this.invokersInitialized = false; + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + this.invokers = BitList.emptyList(); + this.validInvokers = BitList.emptyList(); + this.invokersInitialized = false; + }); } private boolean addValidInvoker(Invoker invoker) { - boolean result; - synchronized (this.validInvokers) { - result = this.validInvokers.add(invoker); - } + AtomicBoolean result = new AtomicBoolean(false); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + result.set(this.validInvokers.add(invoker)); + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); - return result; + return result.get(); } private boolean removeValidInvoker(Invoker invoker) { - boolean result; - synchronized (this.validInvokers) { - result = this.validInvokers.remove(invoker); - } + AtomicBoolean result = new AtomicBoolean(false); + LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { + result.set(this.validInvokers.remove(invoker)); + }); MetricsEventBus.publish( RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); - return result; + return result.get(); } protected abstract List> doList( diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouter.java index b89395ca69..84cf9ef663 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouter.java @@ -235,7 +235,7 @@ public class ConditionStateRouter extends AbstractStateRouter { CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY, "condition state router thenCondition is empty", "", - "The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + "The current consumer in the service blocklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey()); if (needToPrintMessage) { messageHolder.set("Empty return. Reason: ThenCondition is empty."); 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 28c841996c..0c7bb1e3e8 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 @@ -339,7 +339,7 @@ public /*final**/ class URL implements Serializable { } static String appendDefaultPort(String address, int defaultPort) { - if (address != null && address.length() > 0 && defaultPort > 0) { + if (StringUtils.isNotEmpty(address) && defaultPort > 0) { int i = address.indexOf(':'); if (i < 0) { return address + ":" + defaultPort; @@ -525,7 +525,7 @@ public /*final**/ class URL implements Serializable { List urls = new ArrayList<>(); urls.add(this); String[] backups = getParameter(RemotingConstants.BACKUP_KEY, new String[0]); - if (backups != null && backups.length > 0) { + if (ArrayUtils.isNotEmpty(backups)) { for (String backup : backups) { urls.add(this.setAddress(backup)); } @@ -805,7 +805,7 @@ public /*final**/ class URL implements Serializable { public boolean hasParameter(String key) { String value = getParameter(key); - return value != null && value.length() > 0; + return StringUtils.isNotEmpty(value); } public String getMethodParameterAndDecoded(String method, String key) { @@ -1061,7 +1061,7 @@ public /*final**/ class URL implements Serializable { } public URL addParameters(String... pairs) { - if (pairs == null || pairs.length == 0) { + if (ArrayUtils.isEmpty(pairs)) { return this; } if (pairs.length % 2 != 0) { @@ -1589,9 +1589,9 @@ public /*final**/ class URL implements Serializable { return attributes == null ? Collections.emptyMap() : attributes; } - public URL addAttributes(Map attributes) { - if (attributes != null) { - attributes.putAll(attributes); + public URL addAttributes(Map attributeMap) { + if (attributeMap != null) { + attributes.putAll(attributeMap); } return this; } @@ -1718,7 +1718,7 @@ public /*final**/ class URL implements Serializable { public boolean hasServiceParameter(String service, String key) { String value = getServiceParameter(service, key); - return value != null && value.length() > 0; + return StringUtils.isNotEmpty(value); } public float getPositiveServiceParameter(String service, String key, float defaultValue) { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java index e5c18bdaaf..ad2ec5cdf2 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java @@ -17,6 +17,7 @@ package org.apache.dubbo.common; import org.apache.dubbo.common.url.component.ServiceConfigURL; +import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.model.ScopeModel; @@ -376,7 +377,7 @@ public final class URLBuilder extends ServiceConfigURL { @Override public URLBuilder addParameters(String... pairs) { - if (pairs == null || pairs.length == 0) { + if (ArrayUtils.isEmpty(pairs)) { return this; } if (pairs.length % 2 != 0) { @@ -416,7 +417,7 @@ public final class URLBuilder extends ServiceConfigURL { @Override public URLBuilder removeParameters(String... keys) { - if (keys == null || keys.length == 0) { + if (ArrayUtils.isEmpty(keys)) { return this; } for (String key : keys) { @@ -458,7 +459,7 @@ public final class URLBuilder extends ServiceConfigURL { return false; } String value = getMethodParameter(method, key); - return value != null && value.length() > 0; + return StringUtils.isNotEmpty(value); } @Override diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ModuleEnvironment.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ModuleEnvironment.java index 3de18ccbf0..c014c57a64 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ModuleEnvironment.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ModuleEnvironment.java @@ -29,8 +29,6 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION; - public class ModuleEnvironment extends Environment implements ModuleExt { // delegate @@ -94,19 +92,13 @@ public class ModuleEnvironment extends Environment implements ModuleExt { @Override public Configuration getDynamicGlobalConfiguration() { if (dynamicConfiguration == null) { - return applicationDelegate.getDynamicGlobalConfiguration(); + CompositeConfiguration configuration = new CompositeConfiguration(); + configuration.addConfiguration(applicationDelegate.getDynamicGlobalConfiguration()); + configuration.addConfiguration(orderedPropertiesConfiguration); + return configuration; } + if (dynamicGlobalConfiguration == null) { - if (dynamicConfiguration == null) { - if (logger.isWarnEnabled()) { - logger.warn( - COMMON_UNEXPECTED_EXCEPTION, - "", - "", - "dynamicConfiguration is null , return globalConfiguration."); - } - return getConfiguration(); - } dynamicGlobalConfiguration = new CompositeConfiguration(); dynamicGlobalConfiguration.addConfiguration(dynamicConfiguration); dynamicGlobalConfiguration.addConfiguration(getConfiguration()); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java index b16b5d0325..a353bdab3e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java @@ -113,12 +113,12 @@ public class ServiceConfigURL extends URL { } @Override - public URL addAttributes(Map attributes) { + public URL addAttributes(Map attributeMap) { Map newAttributes = new HashMap<>(); if (this.attributes != null) { newAttributes.putAll(this.attributes); } - newAttributes.putAll(attributes); + newAttributes.putAll(attributeMap); return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java new file mode 100644 index 0000000000..f441dc9b2f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java @@ -0,0 +1,54 @@ +/* + * 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.utils; + +import org.apache.dubbo.common.constants.LoggerCodeConstants; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Lock; + +public class LockUtils { + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(LockUtils.class); + + public static final int DEFAULT_TIMEOUT = 60_000; + + public static void safeLock(Lock lock, int timeout, Runnable runnable) { + try { + if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) { + logger.error( + LoggerCodeConstants.INTERNAL_ERROR, + "", + "", + "Try to lock failed, timeout: " + timeout, + new TimeoutException()); + } + runnable.run(); + } catch (InterruptedException e) { + logger.warn(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Try to lock failed", e); + Thread.currentThread().interrupt(); + } finally { + try { + lock.unlock(); + } catch (Exception e) { + // ignore + } + } + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/OrderedPropertiesConfigurationTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/OrderedPropertiesConfigurationTest.java index 8fc082de28..aaf2eb628f 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/config/OrderedPropertiesConfigurationTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/OrderedPropertiesConfigurationTest.java @@ -17,6 +17,8 @@ package org.apache.dubbo.common.config; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.ModuleModel; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -32,4 +34,18 @@ class OrderedPropertiesConfigurationTest { ApplicationModel.defaultModel().getDefaultModule()); Assertions.assertEquals("999", configuration.getInternalProperty("testKey")); } + + @Test + void testGetPropertyFromOrderedPropertiesConfiguration() { + FrameworkModel frameworkModel = new FrameworkModel(); + + ApplicationModel applicationModel = frameworkModel.newApplication(); + + ModuleModel moduleModel = applicationModel.newModule(); + ModuleEnvironment moduleEnvironment = moduleModel.modelEnvironment(); + + Configuration configuration = moduleEnvironment.getDynamicGlobalConfiguration(); + // MockOrderedPropertiesProvider2 initProperties + Assertions.assertEquals("999", configuration.getString("testKey")); + } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java new file mode 100644 index 0000000000..87c1824930 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java @@ -0,0 +1,144 @@ +/* + * 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.utils; + +import java.lang.Thread.State; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.RepeatedTest; + +import static org.awaitility.Awaitility.await; + +public class LockUtilsTest { + @RepeatedTest(5) + void testLockFailed() { + ReentrantLock reentrantLock = new ReentrantLock(); + AtomicBoolean releaseLock = new AtomicBoolean(false); + new Thread(() -> { + reentrantLock.lock(); + while (!releaseLock.get()) { + try { + Thread.sleep(5); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + reentrantLock.unlock(); + }) + .start(); + + await().until(reentrantLock::isLocked); + + AtomicLong lockTime = new AtomicLong(0); + long startTime = System.currentTimeMillis(); + LockUtils.safeLock(reentrantLock, 1000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + Assertions.assertTrue(lockTime.get() - startTime >= 1000); + releaseLock.set(true); + + while (reentrantLock.isLocked()) { + try { + Thread.sleep(5); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + lockTime.set(0); + startTime = System.currentTimeMillis(); + LockUtils.safeLock(reentrantLock, 1000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + Assertions.assertTrue(lockTime.get() - startTime < 1000); + } + + @RepeatedTest(5) + void testReentrant() { + ReentrantLock reentrantLock = new ReentrantLock(); + reentrantLock.lock(); + + AtomicLong lockTime = new AtomicLong(0); + long startTime = System.currentTimeMillis(); + LockUtils.safeLock(reentrantLock, 1000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + Assertions.assertTrue(lockTime.get() - startTime < 1000); + + reentrantLock.lock(); + lockTime.set(0); + startTime = System.currentTimeMillis(); + LockUtils.safeLock(reentrantLock, 1000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + Assertions.assertTrue(lockTime.get() - startTime < 1000); + + Assertions.assertTrue(reentrantLock.isLocked()); + reentrantLock.unlock(); + Assertions.assertTrue(reentrantLock.isLocked()); + reentrantLock.unlock(); + Assertions.assertFalse(reentrantLock.isLocked()); + } + + @RepeatedTest(5) + void testInterrupt() { + ReentrantLock reentrantLock = new ReentrantLock(); + reentrantLock.lock(); + + AtomicBoolean locked = new AtomicBoolean(false); + Thread thread = new Thread(() -> { + LockUtils.safeLock(reentrantLock, 10000, () -> { + locked.set(true); + }); + }); + thread.start(); + + await().until(() -> thread.getState() == State.TIMED_WAITING); + thread.interrupt(); + await().until(() -> thread.getState() == State.TERMINATED); + + Assertions.assertFalse(locked.get()); + + reentrantLock.unlock(); + } + + @RepeatedTest(5) + void testHoldLock() throws InterruptedException { + ReentrantLock reentrantLock = new ReentrantLock(); + reentrantLock.lock(); + + AtomicLong lockTime = new AtomicLong(0); + long startTime = System.currentTimeMillis(); + Thread thread = new Thread(() -> { + LockUtils.safeLock(reentrantLock, 10000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + }); + thread.start(); + + await().until(() -> thread.getState() == State.TIMED_WAITING); + Thread.sleep(1000); + reentrantLock.unlock(); + + await().until(() -> thread.getState() == State.TERMINATED); + Assertions.assertTrue(lockTime.get() - startTime > 1000); + Assertions.assertTrue(lockTime.get() - startTime < 10000); + } +} diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/DelegateURL.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/DelegateURL.java index 918b7d8a92..7757fc1ac4 100644 --- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/DelegateURL.java +++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/DelegateURL.java @@ -854,8 +854,8 @@ public class DelegateURL extends com.alibaba.dubbo.common.URL { } @Override - public org.apache.dubbo.common.URL addAttributes(Map attributes) { - return apacheUrl.addAttributes(attributes); + public org.apache.dubbo.common.URL addAttributes(Map attributeMap) { + return apacheUrl.addAttributes(attributeMap); } @Override diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index f479452d14..a7fa622c77 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -242,7 +242,7 @@ org.testcontainers testcontainers - 1.19.5 + 1.19.6 test diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 3a092d4f8c..78316e6243 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -74,7 +74,7 @@ org.aspectj aspectjweaver - 1.9.21 + 1.9.21.1 test diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java index 0c0af139cd..68fdf1e717 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java @@ -534,6 +534,9 @@ public class ServiceAnnotationPostProcessor addPropertyReference(builder, "executor", executorBeanName); } + // service bean definition should not be lazy + builder.setLazyInit(false); + return builder.getBeanDefinition(); } diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java index f12536bfd1..0405b739f2 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java +++ b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java @@ -65,7 +65,7 @@ public interface RestDemoService { Boolean testBody2(Boolean b); @POST - @Path("/testBody3") + @Path("/testBody4") @Consumes({MediaType.TEXT_PLAIN}) TestPO testBody2(TestPO b); diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml index f48c27881d..eaf9f278b5 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml @@ -157,7 +157,7 @@ ch.qos.logback logback-core - 1.4.14 + 1.5.0 compile @@ -204,7 +204,7 @@ org.graalvm.buildtools native-maven-plugin - 0.10.0 + 0.10.1 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml index c705425d54..5bbb8fe126 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml @@ -157,7 +157,7 @@ ch.qos.logback logback-core - 1.4.14 + 1.5.0 compile @@ -204,7 +204,7 @@ org.graalvm.buildtools native-maven-plugin - 0.10.0 + 0.10.1 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/pom.xml index 90860bd948..2e8d489301 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml @@ -35,7 +35,7 @@ true 2.7.18 2.7.18 - 1.12.2 + 1.12.3 diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index c69bae2fd6..3cee586edc 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -21,7 +21,7 @@ org.apache apache - 27 + 31 @@ -91,24 +91,24 @@ 5.3.25 - 5.8.9 + 5.8.10 3.30.2-GA - 1.14.11 + 1.14.12 3.2.10.Final - 4.1.106.Final + 4.1.107.Final 4.5.14 4.4.16 1.2.83 - 2.0.46 + 2.0.47 3.7.2 5.1.0 2.12.0 3.10.0 4.0.66 - 3.25.2 + 3.25.3 1.3.2 3.1.0 - 9.4.53.v20231009 + 9.4.54.v20240208 3.0.2 1.1.0.Final 5.4.3.Final @@ -119,10 +119,10 @@ 2.2 3.14.0 0.1.35 - 1.12.2 + 1.12.3 1.26.0 2.16.4 - 1.2.2 + 1.2.3 3.3 0.16.0 1.0.4 @@ -133,7 +133,7 @@ 2.1.1 3.15.6.Final 1.9.13 - 8.5.98 + 8.5.99 2.2.4 1.8.6 1.6.1 @@ -147,7 +147,7 @@ 1.2.17 1.2.13 - 2.22.1 + 2.23.0 2.15.1 1.16.0 @@ -166,7 +166,7 @@ 2.2.7 1.2.0 - 1.19.5 + 1.19.6 3.2.13 1.6.13 @@ -179,7 +179,7 @@ 6.1.26 2.0 1.6.0 - 1.25.0 + 1.26.0 2.43.0 check 1.0.0 diff --git a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml b/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml index 2e6cf66a48..fab9f50a09 100644 --- a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml +++ b/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml @@ -21,7 +21,7 @@ org.apache apache - 27 + 31 diff --git a/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml b/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml index 5bc75c6540..0bab7fa215 100644 --- a/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml +++ b/dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml @@ -21,7 +21,7 @@ org.apache apache - 27 + 31 diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java index 87a1871067..be8c2e74c2 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java @@ -202,7 +202,7 @@ public abstract class DynamicDirectory extends AbstractDirectory implement + " for service " + getConsumerUrl().getServiceKey() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() - + ", please check status of providers(disabled, not registered or in blacklist)."); + + ", please check status of providers(disabled, not registered or in blocklist)."); } if (multiGroup) { diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/ResteasyContext.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/ResteasyContext.java index d1e6ec0fa4..91f2edfb43 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/ResteasyContext.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/ResteasyContext.java @@ -169,10 +169,13 @@ public interface ResteasyContext { for (Map.Entry> entry : headers.entrySet()) { String key = entry.getKey(); - if (entry.getValue() == null) { + List value = entry.getValue(); + if (value == null || value.isEmpty()) { continue; } - response.addOutputHeaders(key, entry.getValue().toString()); + for (Object tmp : value) { + response.addOutputHeaders(key, tmp.toString()); + } } } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyNettyHttpResponse.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyNettyHttpResponse.java index 826f84df70..92de82f8d9 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyNettyHttpResponse.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyNettyHttpResponse.java @@ -42,7 +42,14 @@ public class ResteasyNettyHttpResponse implements HttpResponse { for (Map.Entry> headers : outputHeaders.entrySet()) { String key = headers.getKey(); List value = headers.getValue(); - multivaluedMap.add(key, value); + + if (value == null || value.isEmpty()) { + continue; + } + + for (String val : value) { + multivaluedMap.add(key, val); + } } } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java index 0c3cedf8e9..d63b72d00b 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java @@ -33,13 +33,12 @@ import java.util.Set; /** * body is json */ -@Activate("json") +@Activate(value = "json", order = 100) public class JsonCodec implements HttpMessageCodec { private static final Set unSupportClasses = new HashSet<>(); static { unSupportClasses.add(byte[].class); - unSupportClasses.add(String.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java index 4f939ea7fb..1a543a2ad7 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java @@ -28,7 +28,7 @@ import java.nio.charset.StandardCharsets; /** * body is string */ -@Activate("string") +@Activate(value = "string", order = 200) public class StringCodec implements HttpMessageCodec { @Override diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java index 72256f53e9..d29e194104 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java @@ -190,6 +190,10 @@ public class NettyHttpResponse implements HttpResponse { outputHeaders.put(name, values); } + if (values.contains(value)) { + return; + } + values.add(value); } diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml index 17ad771623..5af7140e93 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml +++ b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml @@ -36,8 +36,8 @@ - 1.12.2 - 1.2.2 + 1.12.3 + 1.2.3 1.34.1 2.17.2 0.16.0 diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml index 632f0090d5..a555e7b6b4 100644 --- a/dubbo-spring-boot/pom.xml +++ b/dubbo-spring-boot/pom.xml @@ -41,7 +41,7 @@ 2.7.18 - 1.14.11 + 1.14.12 4.11.0 diff --git a/dubbo-test/dubbo-test-check/pom.xml b/dubbo-test/dubbo-test-check/pom.xml index 1f28cc007f..442b5b84a3 100644 --- a/dubbo-test/dubbo-test-check/pom.xml +++ b/dubbo-test/dubbo-test-check/pom.xml @@ -31,7 +31,7 @@ 4.2.0 3.7.2 4.2.0 - 1.25.0 + 1.26.0 1.9.3 1.4.0 2.12.3 diff --git a/pom.xml b/pom.xml index edae37626b..4dafbf47e6 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ org.apache apache - 23 + 31 org.apache.dubbo @@ -136,7 +136,7 @@ 3.12.1 3.3.0 3.6.3 - 9.4.53.v20231009 + 9.4.54.v20240208 3.3.1 0.8.11 1.6.0 @@ -280,7 +280,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.5.2 false