Merge branch 'apache-3.2' into apache-3.3

# Conflicts:
#	dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
#	dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java
#	dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java
This commit is contained in:
Albumen Kevin 2023-06-08 16:16:15 +08:00
commit 642f741dba
118 changed files with 3650 additions and 341 deletions

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
@ -36,6 +37,7 @@ import java.util.List;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_EXECUTE_FILTER_EXCEPTION;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
import static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;
@SPI(value = "default", scope = APPLICATION)
@ -294,6 +296,7 @@ public interface FilterChainBuilder {
@Experimental("Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough")
class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(CopyOfFilterChainNode.class);
TYPE originalInvoker;
Invoker<T> nextNode;
FILTER filter;
@ -329,6 +332,12 @@ public interface FilterChainBuilder {
try {
InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
asyncResult = filter.invoke(nextNode, invocation);
if (!(asyncResult instanceof AsyncRpcResult)) {
String msg = "The result of filter invocation must be AsyncRpcResult. (If you want to recreate a result, please use AsyncRpcResult.newDefaultAsyncResult.) " +
"Filter class: " + filter.getClass().getName() + ". Result class: " + asyncResult.getClass().getName() + ".";
LOGGER.error(INTERNAL_ERROR, "", "", msg);
throw new RpcException(msg);
}
} catch (Exception e) {
InvocationProfilerUtils.releaseDetailProfiler(invocation);
if (filter instanceof ListenableFilter) {

View File

@ -16,11 +16,6 @@
*/
package org.apache.dubbo.rpc.cluster.support;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.Configuration;
@ -37,6 +32,7 @@ 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.RpcServiceContext;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
@ -44,6 +40,11 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_LOADBALANCE;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RESELECT_COUNT;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION;
@ -372,7 +373,7 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
}
protected Result invokeWithContext(Invoker<T> invoker, Invocation invocation) {
setContext(invoker);
Invoker<T> originInvoker = setContext(invoker);
Result result;
try {
if (ProfilerSwitch.isEnableSimpleProfiler()) {
@ -381,7 +382,7 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
invocation.addInvokedInvoker(invoker);
result = invoker.invoke(invocation);
} finally {
clearContext(invoker);
clearContext(originInvoker);
InvocationProfilerUtils.releaseSimpleProfiler(invocation);
}
return result;
@ -394,12 +395,12 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
* @return
*/
protected Result invokeWithContextAsync(Invoker<T> invoker, Invocation invocation, URL consumerUrl) {
setContext(invoker, consumerUrl);
Invoker<T> originInvoker = setContext(invoker, consumerUrl);
Result result;
try {
result = invoker.invoke(invocation);
} finally {
clearContext(invoker);
clearContext(originInvoker);
}
return result;
}
@ -436,19 +437,21 @@ public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
}
private void setContext(Invoker<T> invoker) {
setContext(invoker, null);
private Invoker<T> setContext(Invoker<T> invoker) {
return setContext(invoker, null);
}
private void setContext(Invoker<T> invoker, URL consumerUrl) {
RpcContext context = RpcContext.getServiceContext();
private Invoker<T> setContext(Invoker<T> invoker, URL consumerUrl) {
RpcServiceContext context = RpcContext.getServiceContext();
Invoker<?> originInvoker = context.getInvoker();
context.setInvoker(invoker)
.setConsumerUrl(null != consumerUrl ? consumerUrl : RpcContext.getServiceContext().getConsumerUrl());
return (Invoker<T>) originInvoker;
}
private void clearContext(Invoker<T> invoker) {
// do nothing
RpcContext context = RpcContext.getServiceContext();
context.setInvoker(null);
context.setInvoker(invoker);
}
}

View File

@ -22,7 +22,12 @@ import java.util.List;
public interface ReferenceCache {
@SuppressWarnings("unchecked")
<T> T get(ReferenceConfigBase<T> referenceConfig);
default <T> T get(ReferenceConfigBase<T> referenceConfig) {
return get(referenceConfig, true);
}
@SuppressWarnings("unchecked")
<T> T get(ReferenceConfigBase<T> referenceConfig, boolean check);
@SuppressWarnings("unchecked")
<T> T get(String key, Class<T> type);
@ -36,6 +41,11 @@ public interface ReferenceCache {
@SuppressWarnings("unchecked")
<T> T get(Class<T> type);
@SuppressWarnings("unchecked")
<T> void check(ReferenceConfigBase<T> referenceConfig, long timeout);
void check(String key, Class<?> type, long timeout);
void destroy(String key, Class<?> type);
void destroy(Class<?> type);

View File

@ -0,0 +1,243 @@
/*
* 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.convert;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.StringUtils;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
public class StringToDurationConverter implements StringConverter<Duration> {
@Override
public Duration convert(String source) {
return isNotEmpty(source) ? DurationStyle.detectAndParse(source) : null;
}
@Override
public int getPriority() {
return NORMAL_PRIORITY + 10;
}
/**
* @author Phillip Webb
* @author Valentine Wu
* @link {org.springframework.boot.convert.DurationStyle}
*/
enum DurationStyle {
/**
* Simple formatting, for example '1s'.
*/
SIMPLE("^([+-]?\\d+)([a-zA-Z]{0,2})$") {
@Override
public Duration parse(String value, ChronoUnit unit) {
try {
Matcher matcher = matcher(value);
Assert.assertTrue(matcher.matches(), "Does not match simple duration pattern");
String suffix = matcher.group(2);
return (StringUtils.isNotBlank(suffix) ? TimeUnit.fromSuffix(suffix) : TimeUnit.fromChronoUnit(unit))
.parse(matcher.group(1));
} catch (Exception ex) {
throw new IllegalArgumentException("'" + value + "' is not a valid simple duration", ex);
}
}
},
/**
* ISO-8601 formatting.
*/
ISO8601("^[+-]?[pP].*$") {
@Override
public Duration parse(String value, ChronoUnit unit) {
try {
return Duration.parse(value);
} catch (Exception ex) {
throw new IllegalArgumentException("'" + value + "' is not a valid ISO-8601 duration", ex);
}
}
};
private final Pattern pattern;
DurationStyle(String pattern) {
this.pattern = Pattern.compile(pattern);
}
protected final boolean matches(String value) {
return this.pattern.matcher(value).matches();
}
protected final Matcher matcher(String value) {
return this.pattern.matcher(value);
}
/**
* Parse the given value to a duration.
*
* @param value the value to parse
* @return a duration
*/
public Duration parse(String value) {
return parse(value, null);
}
/**
* Parse the given value to a duration.
*
* @param value the value to parse
* @param unit the duration unit to use if the value doesn't specify one ({@code null}
* will default to ms)
* @return a duration
*/
public abstract Duration parse(String value, ChronoUnit unit);
/**
* Detect the style then parse the value to return a duration.
*
* @param value the value to parse
* @return the parsed duration
* @throws IllegalArgumentException if the value is not a known style or cannot be
* parsed
*/
public static Duration detectAndParse(String value) {
return detectAndParse(value, null);
}
/**
* Detect the style then parse the value to return a duration.
*
* @param value the value to parse
* @param unit the duration unit to use if the value doesn't specify one ({@code null}
* will default to ms)
* @return the parsed duration
* @throws IllegalArgumentException if the value is not a known style or cannot be
* parsed
*/
public static Duration detectAndParse(String value, ChronoUnit unit) {
return detect(value).parse(value, unit);
}
/**
* Detect the style from the given source value.
*
* @param value the source value
* @return the duration style
* @throws IllegalArgumentException if the value is not a known style
*/
public static DurationStyle detect(String value) {
Assert.notNull(value, "Value must not be null");
for (DurationStyle candidate : values()) {
if (candidate.matches(value)) {
return candidate;
}
}
throw new IllegalArgumentException("'" + value + "' is not a valid duration");
}
/**
* Time Unit that support.
*/
enum TimeUnit {
/**
* Nanoseconds.
*/
NANOS(ChronoUnit.NANOS, "ns", Duration::toNanos),
/**
* Microseconds.
*/
MICROS(ChronoUnit.MICROS, "us", (duration) -> duration.toNanos() / 1000L),
/**
* Milliseconds.
*/
MILLIS(ChronoUnit.MILLIS, "ms", Duration::toMillis),
/**
* Seconds.
*/
SECONDS(ChronoUnit.SECONDS, "s", Duration::getSeconds),
/**
* Minutes.
*/
MINUTES(ChronoUnit.MINUTES, "m", Duration::toMinutes),
/**
* Hours.
*/
HOURS(ChronoUnit.HOURS, "h", Duration::toHours),
/**
* Days.
*/
DAYS(ChronoUnit.DAYS, "d", Duration::toDays);
private final ChronoUnit chronoUnit;
private final String suffix;
private final Function<Duration, Long> longValue;
TimeUnit(ChronoUnit chronoUnit, String suffix, Function<Duration, Long> toUnit) {
this.chronoUnit = chronoUnit;
this.suffix = suffix;
this.longValue = toUnit;
}
public Duration parse(String value) {
return Duration.of(Long.parseLong(value), this.chronoUnit);
}
public long longValue(Duration value) {
return this.longValue.apply(value);
}
public static TimeUnit fromChronoUnit(ChronoUnit chronoUnit) {
if (chronoUnit == null) {
return TimeUnit.MILLIS;
}
for (TimeUnit candidate : values()) {
if (candidate.chronoUnit == chronoUnit) {
return candidate;
}
}
throw new IllegalArgumentException("Unknown unit " + chronoUnit);
}
public static TimeUnit fromSuffix(String suffix) {
for (TimeUnit candidate : values()) {
if (candidate.suffix.equalsIgnoreCase(suffix)) {
return candidate;
}
}
throw new IllegalArgumentException("Unknown unit '" + suffix + "'");
}
}
}
}

View File

@ -89,6 +89,11 @@ public interface ApplicationDeployer extends Deployer<ApplicationModel> {
*/
void notifyModuleChanged(ModuleModel moduleModel, DeployState state);
/**
* refresh service instance
*/
void refreshServiceInstance();
/**
* Increase the count of service update threads.
* NOTE: should call ${@link ApplicationDeployer#decreaseServiceRefreshCount()} after update finished

View File

@ -24,6 +24,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -87,7 +88,8 @@ public class ClassUtils {
BigDecimal.class,
BigInteger.class,
Date.class,
Object.class
Object.class,
Duration.class
);
/**
* Prefix for internal array class names: "[L"

View File

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.utils;
import java.util.Arrays;
public class ToStringUtils {
private ToStringUtils() {
}
public static String printToString(Object obj) {
if (obj == null) {
return "null";
}
try {
return JsonUtils.toJson(obj);
} catch (Throwable throwable) {
if (obj instanceof Object[]) {
return Arrays.toString((Object[]) obj);
}
return obj.toString();
}
}
}

View File

@ -277,9 +277,10 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
protected void appendMetricsCompatible(Map<String, String> map) {
MetricsConfig metricsConfig = getConfigManager().getMetrics().orElse(null);
if (metricsConfig != null) {
if (metricsConfig.getProtocol() != null && !StringUtils.isEquals(metricsConfig.getProtocol(), PROTOCOL_PROMETHEUS)) {
String protocol = Optional.ofNullable(metricsConfig.getProtocol()).orElse(PROTOCOL_PROMETHEUS);
if (!StringUtils.isEquals(protocol, PROTOCOL_PROMETHEUS)) {
Assert.notEmptyString(metricsConfig.getPort(), "Metrics port cannot be null");
map.put("metrics.protocol", metricsConfig.getProtocol());
map.put("metrics.protocol", protocol);
map.put("metrics.port", metricsConfig.getPort());
}
}
@ -375,8 +376,9 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
}
/**
* it is used for skipping the check of interface since dubbo 3.2
* rest protocol allow the service is implement class
* it is used for skipping the check of interface since dubbo 3.2
* rest protocol allow the service is implement class
*
* @return
*/
protected boolean canSkipInterfaceCheck() {

View File

@ -92,6 +92,7 @@ public class MetricsConfig extends AbstractConfig {
*/
private Boolean useGlobalRegistry;
private Boolean enableRpc;
public MetricsConfig() {
}
@ -214,4 +215,12 @@ public class MetricsConfig extends AbstractConfig {
public void setUseGlobalRegistry(Boolean useGlobalRegistry) {
this.useGlobalRegistry = useGlobalRegistry;
}
public Boolean getEnableRpc() {
return enableRpc;
}
public void setEnableRpc(Boolean enableRpc) {
this.enableRpc = enableRpc;
}
}

View File

@ -368,7 +368,15 @@ public abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {
}
@Transient
public abstract T get();
public abstract T get(boolean check);
@Transient
public abstract void checkOrDestroy(long timeout);
@Transient
public final T get() {
return get(true);
}
public void destroy() {
getModuleConfigManager().removeConfig(this);

View File

@ -415,7 +415,9 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
/**
* export service and auto start application instance
*/
public abstract void export();
public final void export() {
export(true);
}
public abstract void unexport();
@ -423,4 +425,7 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
public abstract boolean isUnexported();
public abstract void export(boolean register);
public abstract void register();
}

View File

@ -254,6 +254,7 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
// load dubbo.metrics.xxx
loadConfigsOfTypeFromProps(MetricsConfig.class);
//load dubbo.tracing.xxx
loadConfigsOfTypeFromProps(TracingConfig.class);
// load multiple config types:

View File

@ -9,4 +9,5 @@ string-to-long=org.apache.dubbo.common.convert.StringToLongConverter
string-to-optional=org.apache.dubbo.common.convert.StringToOptionalConverter
string-to-short=org.apache.dubbo.common.convert.StringToShortConverter
string-to-string=org.apache.dubbo.common.convert.StringToStringConverter
string-to-byte=org.apache.dubbo.common.convert.StringToByteConverter
string-to-byte=org.apache.dubbo.common.convert.StringToByteConverter
string-to-duration=org.apache.dubbo.common.convert.StringToDurationConverter

View File

@ -0,0 +1,62 @@
/*
* 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.convert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link StringToDurationConverter} Test
*
* @since 3.2.3
*/
class StringToDurationConverterTest {
private StringToDurationConverter converter;
@BeforeEach
public void init() {
converter = (StringToDurationConverter) getExtensionLoader(Converter.class).getExtension("string-to-duration");
}
@Test
void testAccept() {
assertTrue(converter.accept(String.class, Duration.class));
}
@Test
void testConvert() {
assertEquals(Duration.ofMillis(1000), converter.convert("1000ms"));
assertEquals(Duration.ofSeconds(1), converter.convert("1s"));
assertEquals(Duration.ofMinutes(1), converter.convert("1m"));
assertEquals(Duration.ofHours(1), converter.convert("1h"));
assertEquals(Duration.ofDays(1), converter.convert("1d"));
assertNull(converter.convert(null));
assertThrows(IllegalArgumentException.class, () -> {
converter.convert("ttt");
});
}
}

View File

@ -17,6 +17,7 @@
package com.alibaba.dubbo.cache;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
@ -26,6 +27,6 @@ public interface CacheFactory extends org.apache.dubbo.cache.CacheFactory {
Cache getCache(URL url, Invocation invocation);
default org.apache.dubbo.cache.Cache getCache(org.apache.dubbo.common.URL url, org.apache.dubbo.rpc.Invocation invocation) {
return this.getCache(new URL(url), new Invocation.CompatibleInvocation(invocation));
return this.getCache(new DelegateURL(url), new Invocation.CompatibleInvocation(invocation));
}
}

View File

@ -19,6 +19,7 @@ package com.alibaba.dubbo.cache.support;
import com.alibaba.dubbo.cache.Cache;
import com.alibaba.dubbo.cache.CacheFactory;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
@ -48,6 +49,6 @@ public abstract class AbstractCacheFactory implements CacheFactory {
@Override
public org.apache.dubbo.cache.Cache getCache(org.apache.dubbo.common.URL url, org.apache.dubbo.rpc.Invocation invocation) {
return getCache(new URL(url), new Invocation.CompatibleInvocation(invocation));
return getCache(new DelegateURL(url), new Invocation.CompatibleInvocation(invocation));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -73,7 +73,7 @@ public class URL extends org.apache.dubbo.common.URL {
public static URL valueOf(String url) {
org.apache.dubbo.common.URL result = org.apache.dubbo.common.URL.valueOf(url);
return new URL(result);
return new DelegateURL(result);
}
public static String encode(String value) {

View File

@ -17,6 +17,7 @@
package com.alibaba.dubbo.common.serialize;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import java.io.IOException;
@ -32,11 +33,11 @@ public interface Serialization extends org.apache.dubbo.common.serialize.Seriali
@Override
default org.apache.dubbo.common.serialize.ObjectOutput serialize(org.apache.dubbo.common.URL url, OutputStream output) throws IOException {
return this.serialize(new URL(url), output);
return this.serialize(new DelegateURL(url), output);
}
@Override
default org.apache.dubbo.common.serialize.ObjectInput deserialize(org.apache.dubbo.common.URL url, InputStream input) throws IOException {
return this.deserialize(new URL(url), input);
return this.deserialize(new DelegateURL(url), input);
}
}

View File

@ -28,6 +28,6 @@ public interface ThreadPool extends org.apache.dubbo.common.threadpool.ThreadPoo
@Override
default Executor getExecutor(URL url) {
return getExecutor(new com.alibaba.dubbo.common.URL(url));
return getExecutor(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -16,6 +16,7 @@
*/
package com.alibaba.dubbo.common.utils;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import java.util.List;
@ -30,11 +31,11 @@ import java.util.stream.Collectors;
public class UrlUtils {
public static URL parseURL(String address, Map<String, String> defaults) {
return new URL(org.apache.dubbo.common.utils.UrlUtils.parseURL(address, defaults));
return new DelegateURL(org.apache.dubbo.common.utils.UrlUtils.parseURL(address, defaults));
}
public static List<URL> parseURLs(String address, Map<String, String> defaults) {
return org.apache.dubbo.common.utils.UrlUtils.parseURLs(address, defaults).stream().map(e -> new URL(e)).collect(Collectors.toList());
return org.apache.dubbo.common.utils.UrlUtils.parseURLs(address, defaults).stream().map(e -> new DelegateURL(e)).collect(Collectors.toList());
}
public static Map<String, Map<String, String>> convertRegister(Map<String, Map<String, String>> register) {
@ -64,7 +65,7 @@ public class UrlUtils {
}
public static URL getEmptyUrl(String service, String category) {
return new URL(org.apache.dubbo.common.utils.UrlUtils.getEmptyUrl(service, category));
return new DelegateURL(org.apache.dubbo.common.utils.UrlUtils.getEmptyUrl(service, category));
}
public static boolean isMatchCategory(String category, String categories) {

View File

@ -34,11 +34,11 @@ public interface Monitor extends org.apache.dubbo.monitor.Monitor {
@Override
default void collect(URL statistics) {
this.collect(new com.alibaba.dubbo.common.URL(statistics));
this.collect(new com.alibaba.dubbo.common.DelegateURL(statistics));
}
@Override
default List<URL> lookup(URL query) {
return this.lookup(new com.alibaba.dubbo.common.URL(query)).stream().map(url -> url.getOriginalURL()).collect(Collectors.toList());
return this.lookup(new com.alibaba.dubbo.common.DelegateURL(query)).stream().map(url -> url.getOriginalURL()).collect(Collectors.toList());
}
}

View File

@ -27,6 +27,6 @@ public interface MonitorFactory extends org.apache.dubbo.monitor.MonitorFactory
@Override
default Monitor getMonitor(URL url) {
return this.getMonitor(new com.alibaba.dubbo.common.URL(url));
return this.getMonitor(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -17,6 +17,7 @@
package com.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import java.util.List;
@ -54,7 +55,7 @@ public interface NotifyListener {
@Override
public void notify(List<org.apache.dubbo.common.URL> urls) {
if (listener != null) {
listener.notify(urls.stream().map(url -> new URL(url)).collect(Collectors.toList()));
listener.notify(urls.stream().map(url -> new DelegateURL(url)).collect(Collectors.toList()));
}
}
}

View File

@ -41,29 +41,29 @@ public interface Registry extends org.apache.dubbo.registry.Registry {
@Override
default void register(URL url) {
this.register(new com.alibaba.dubbo.common.URL(url));
this.register(new com.alibaba.dubbo.common.DelegateURL(url));
}
@Override
default void unregister(URL url) {
this.unregister(new com.alibaba.dubbo.common.URL(url));
this.unregister(new com.alibaba.dubbo.common.DelegateURL(url));
}
@Override
default void subscribe(URL url, NotifyListener listener) {
this.subscribe(new com.alibaba.dubbo.common.URL(url),
this.subscribe(new com.alibaba.dubbo.common.DelegateURL(url),
new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
}
@Override
default void unsubscribe(URL url, NotifyListener listener) {
this.unsubscribe(new com.alibaba.dubbo.common.URL(url),
this.unsubscribe(new com.alibaba.dubbo.common.DelegateURL(url),
new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
}
@Override
default List<URL> lookup(URL url) {
return this.lookup(new com.alibaba.dubbo.common.URL(url)).stream().map(u -> u.getOriginalURL()).
return this.lookup(new com.alibaba.dubbo.common.DelegateURL(url)).stream().map(u -> u.getOriginalURL()).
collect(Collectors.toList());
}
}

View File

@ -27,6 +27,6 @@ public interface RegistryFactory extends org.apache.dubbo.registry.RegistryFacto
@Override
default Registry getRegistry(URL url) {
return this.getRegistry(new com.alibaba.dubbo.common.URL(url));
return this.getRegistry(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -39,7 +39,7 @@ public abstract class AbstractRegistry implements Registry {
@Override
public com.alibaba.dubbo.common.URL getUrl() {
return new com.alibaba.dubbo.common.URL(abstractRegistry.getUrl());
return new com.alibaba.dubbo.common.DelegateURL(abstractRegistry.getUrl());
}
protected void setUrl(com.alibaba.dubbo.common.URL url) {
@ -47,35 +47,35 @@ public abstract class AbstractRegistry implements Registry {
}
public Set<com.alibaba.dubbo.common.URL> getRegistered() {
return abstractRegistry.getRegistered().stream().map(url -> new com.alibaba.dubbo.common.URL(url)).collect(Collectors.toSet());
return abstractRegistry.getRegistered().stream().map(url -> new com.alibaba.dubbo.common.DelegateURL(url)).collect(Collectors.toSet());
}
public Map<com.alibaba.dubbo.common.URL, Set<com.alibaba.dubbo.registry.NotifyListener>> getSubscribed() {
return abstractRegistry.getSubscribed().entrySet()
.stream()
.collect(Collectors.toMap(entry -> new com.alibaba.dubbo.common.URL(entry.getKey()),
.collect(Collectors.toMap(entry -> new com.alibaba.dubbo.common.DelegateURL(entry.getKey()),
entry -> convertToNotifyListeners(entry.getValue())));
}
public Map<com.alibaba.dubbo.common.URL, Map<String, List<com.alibaba.dubbo.common.URL>>> getNotified() {
return abstractRegistry.getNotified().entrySet().stream()
.collect(Collectors.toMap(entry -> new com.alibaba.dubbo.common.URL(entry.getKey()),
.collect(Collectors.toMap(entry -> new com.alibaba.dubbo.common.DelegateURL(entry.getKey()),
entry -> {
return entry.getValue().entrySet()
.stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> {
return e.getValue().stream().map(url -> new com.alibaba.dubbo.common.URL(url)).collect(Collectors.toList());
return e.getValue().stream().map(url -> new com.alibaba.dubbo.common.DelegateURL(url)).collect(Collectors.toList());
}));
}));
}
public List<com.alibaba.dubbo.common.URL> getCacheUrls(com.alibaba.dubbo.common.URL url) {
return abstractRegistry.lookup(url.getOriginalURL()).stream().map(tmpUrl -> new com.alibaba.dubbo.common.URL(tmpUrl)).collect(Collectors.toList());
return abstractRegistry.lookup(url.getOriginalURL()).stream().map(tmpUrl -> new com.alibaba.dubbo.common.DelegateURL(tmpUrl)).collect(Collectors.toList());
}
public List<com.alibaba.dubbo.common.URL> lookup(com.alibaba.dubbo.common.URL url) {
return abstractRegistry.lookup(url.getOriginalURL()).stream().map(tmpUrl -> new com.alibaba.dubbo.common.URL(tmpUrl)).collect(Collectors.toList());
return abstractRegistry.lookup(url.getOriginalURL()).stream().map(tmpUrl -> new com.alibaba.dubbo.common.DelegateURL(tmpUrl)).collect(Collectors.toList());
}
protected void notify(com.alibaba.dubbo.common.URL url, com.alibaba.dubbo.registry.NotifyListener listener, List<com.alibaba.dubbo.common.URL> urls) {
@ -101,22 +101,22 @@ public abstract class AbstractRegistry implements Registry {
@Override
public void register(URL url) {
this.register(new com.alibaba.dubbo.common.URL(url));
this.register(new com.alibaba.dubbo.common.DelegateURL(url));
}
@Override
public void unregister(URL url) {
this.unregister(new com.alibaba.dubbo.common.URL(url));
this.unregister(new com.alibaba.dubbo.common.DelegateURL(url));
}
@Override
public void subscribe(URL url, NotifyListener listener) {
this.subscribe(new com.alibaba.dubbo.common.URL(url), new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
this.subscribe(new com.alibaba.dubbo.common.DelegateURL(url), new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
}
@Override
public void unsubscribe(URL url, NotifyListener listener) {
this.unsubscribe(new com.alibaba.dubbo.common.URL(url), new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
this.unsubscribe(new com.alibaba.dubbo.common.DelegateURL(url), new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));
}
final Set<com.alibaba.dubbo.registry.NotifyListener> convertToNotifyListeners(Set<NotifyListener> notifyListeners) {

View File

@ -36,6 +36,6 @@ public abstract class AbstractRegistryFactory extends org.apache.dubbo.registry.
@Override
protected Registry createRegistry(URL url) {
return createRegistry(new com.alibaba.dubbo.common.URL(url));
return createRegistry(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -16,6 +16,7 @@
*/
package com.alibaba.dubbo.registry.support;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.Registry;
@ -87,12 +88,12 @@ public abstract class FailbackRegistry implements org.apache.dubbo.registry.Regi
@Override
public List<URL> lookup(URL url) {
return failbackRegistry.lookup(url.getOriginalURL()).stream().map(e -> new URL(e)).collect(Collectors.toList());
return failbackRegistry.lookup(url.getOriginalURL()).stream().map(e -> new DelegateURL(e)).collect(Collectors.toList());
}
@Override
public URL getUrl() {
return new URL(failbackRegistry.getUrl());
return new DelegateURL(failbackRegistry.getUrl());
}
@Override
@ -112,22 +113,22 @@ public abstract class FailbackRegistry implements org.apache.dubbo.registry.Regi
@Override
public void register(org.apache.dubbo.common.URL url) {
this.register(new URL(url));
this.register(new DelegateURL(url));
}
@Override
public void unregister(org.apache.dubbo.common.URL url) {
this.unregister(new URL(url));
this.unregister(new DelegateURL(url));
}
@Override
public void subscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {
this.subscribe(new URL(url), new NotifyListener.CompatibleNotifyListener(listener));
this.subscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));
}
@Override
public void unsubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {
this.unsubscribe(new URL(url), new NotifyListener.CompatibleNotifyListener(listener));
this.unsubscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));
}
@Override
@ -147,22 +148,22 @@ public abstract class FailbackRegistry implements org.apache.dubbo.registry.Regi
@Override
public void doRegister(org.apache.dubbo.common.URL url) {
this.compatibleFailbackRegistry.doRegister(new URL(url));
this.compatibleFailbackRegistry.doRegister(new DelegateURL(url));
}
@Override
public void doUnregister(org.apache.dubbo.common.URL url) {
this.compatibleFailbackRegistry.doUnregister(new URL(url));
this.compatibleFailbackRegistry.doUnregister(new DelegateURL(url));
}
@Override
public void doSubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {
this.compatibleFailbackRegistry.doSubscribe(new URL(url), new NotifyListener.CompatibleNotifyListener(listener));
this.compatibleFailbackRegistry.doSubscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));
}
@Override
public void doUnsubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {
this.compatibleFailbackRegistry.doUnsubscribe(new URL(url), new NotifyListener.CompatibleNotifyListener(listener));
this.compatibleFailbackRegistry.doUnsubscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));
}
@Override

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.remoting.RemotingServer;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
@Deprecated
@ -32,7 +33,7 @@ public interface Transporter extends org.apache.dubbo.remoting.Transporter {
@Override
default RemotingServer bind(org.apache.dubbo.common.URL url, org.apache.dubbo.remoting.ChannelHandler handler)
throws org.apache.dubbo.remoting.RemotingException {
return bind(new URL(url), new ChannelHandler() {
return bind(new DelegateURL(url), new ChannelHandler() {
@Override
public void connected(Channel channel) throws RemotingException {
try {

View File

@ -23,6 +23,8 @@ public interface Exporter<T> extends org.apache.dubbo.rpc.Exporter<T> {
@Override
Invoker<T> getInvoker();
default void register() {}
default void unregister() {}
class CompatibleExporter<T> implements Exporter<T> {
@ -43,6 +45,11 @@ public interface Exporter<T> extends org.apache.dubbo.rpc.Exporter<T> {
delegate.unexport();
}
@Override
public void register() {
delegate.register();
}
@Override
public void unregister() {
delegate.unregister();

View File

@ -18,6 +18,9 @@
package com.alibaba.dubbo.rpc;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.AttachmentsAdapter;
import java.util.Map;
@Deprecated
public interface Filter extends org.apache.dubbo.rpc.Filter {
@ -27,17 +30,21 @@ public interface Filter extends org.apache.dubbo.rpc.Filter {
@Override
default org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invoker<?> invoker,
org.apache.dubbo.rpc.Invocation invocation)
throws org.apache.dubbo.rpc.RpcException {
throws org.apache.dubbo.rpc.RpcException {
Result invokeResult = invoke(new Invoker.CompatibleInvoker<>(invoker),
new Invocation.CompatibleInvocation(invocation));
if (invokeResult instanceof Result.CompatibleResult) {
return invokeResult;
return ((Result.CompatibleResult) invokeResult).getDelegate();
}
AsyncRpcResult asyncRpcResult = AsyncRpcResult.newDefaultAsyncResult(invocation);
asyncRpcResult.setValue(invokeResult.getValue());
asyncRpcResult.setException(invokeResult.getException());
Map<String, String> attachments = invokeResult.getAttachments();
if (!(attachments instanceof AttachmentsAdapter.ObjectToStringMap)) {
asyncRpcResult.setAttachments(attachments);
}
asyncRpcResult.setObjectAttachments(invokeResult.getObjectAttachments());
return asyncRpcResult;

View File

@ -19,6 +19,7 @@ package com.alibaba.dubbo.rpc;
import org.apache.dubbo.rpc.AsyncRpcResult;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
@Deprecated
@ -77,7 +78,7 @@ public interface Invoker<T> extends org.apache.dubbo.rpc.Invoker<T> {
@Override
public URL getUrl() {
return new URL(invoker.getUrl());
return new DelegateURL(invoker.getUrl());
}
@Override

View File

@ -19,6 +19,7 @@ package com.alibaba.dubbo.rpc;
import org.apache.dubbo.rpc.ProtocolServer;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import java.util.Collections;
@ -38,7 +39,7 @@ public interface Protocol extends org.apache.dubbo.rpc.Protocol {
@Override
default <T> org.apache.dubbo.rpc.Invoker<T> refer(Class<T> aClass, org.apache.dubbo.common.URL url) throws RpcException {
return this.refer(aClass, new URL(url));
return this.refer(aClass, new DelegateURL(url));
}
@Override

View File

@ -42,6 +42,6 @@ public interface ProxyFactory extends org.apache.dubbo.rpc.ProxyFactory {
@Override
default <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
return getInvoker(proxy, type, new com.alibaba.dubbo.common.URL(url));
return getInvoker(proxy, type, new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -64,6 +64,16 @@ public interface Result extends org.apache.dubbo.rpc.Result {
return null;
}
/**
* @see com.alibaba.dubbo.rpc.Result#getValue()
* @deprecated Replace to getValue()
*/
@Deprecated
default Object getResult() {
return getValue();
}
class CompatibleResult implements Result {
private org.apache.dubbo.rpc.Result delegate;

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.FutureContext;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.DelegateURL;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.protocol.dubbo.FutureAdapter;
@ -134,7 +135,7 @@ public class RpcContext {
if (CollectionUtils.isNotEmpty(newUrls)) {
List<URL> urls = new ArrayList<>(newUrls.size());
for (org.apache.dubbo.common.URL newUrl : newUrls) {
urls.add(new URL(newUrl));
urls.add(new DelegateURL(newUrl));
}
return urls;
}
@ -152,7 +153,7 @@ public class RpcContext {
}
public URL getUrl() {
return new URL(newRpcContext.getUrl());
return new DelegateURL(newRpcContext.getUrl());
}
public void setUrl(URL url) {

View File

@ -37,6 +37,6 @@ public interface Configurator extends org.apache.dubbo.rpc.cluster.Configurator
@Override
default URL configure(URL url) {
return this.configure(new com.alibaba.dubbo.common.URL(url));
return this.configure(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -28,6 +28,6 @@ public interface ConfiguratorFactory extends org.apache.dubbo.rpc.cluster.Config
@Override
default Configurator getConfigurator(URL url) {
return this.getConfigurator(new com.alibaba.dubbo.common.URL(url));
return this.getConfigurator(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import com.alibaba.dubbo.common.DelegateURL;
import java.util.List;
import java.util.stream.Collectors;
@ -38,7 +40,9 @@ public interface LoadBalance extends org.apache.dubbo.rpc.cluster.LoadBalance {
map(invoker -> new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<T>(invoker)).
collect(Collectors.toList());
return select(invs, new com.alibaba.dubbo.common.URL(url),
new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));
com.alibaba.dubbo.rpc.Invoker<T> selected = select(invs, new DelegateURL(url),
new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));
return selected == null ? null : selected.getOriginal();
}
}

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Deprecated
@ -44,9 +45,9 @@ public interface Router extends org.apache.dubbo.rpc.cluster.Router{
List<com.alibaba.dubbo.rpc.Invoker<T>> invs = invokers.stream().map(invoker -> new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<T>(invoker)).
collect(Collectors.toList());
List<com.alibaba.dubbo.rpc.Invoker<T>> res = this.route(invs, new com.alibaba.dubbo.common.URL(url), new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));
List<com.alibaba.dubbo.rpc.Invoker<T>> res = this.route(invs, new com.alibaba.dubbo.common.DelegateURL(url), new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));
return res.stream().map(inv -> inv.getOriginal()).collect(Collectors.toList());
return res.stream().map(inv -> inv.getOriginal()).filter(Objects::nonNull).collect(Collectors.toList());
}
@Override

View File

@ -27,6 +27,6 @@ public interface RouterFactory extends org.apache.dubbo.rpc.cluster.RouterFactor
@Override
default Router getRouter(URL url) {
return this.getRouter(new com.alibaba.dubbo.common.URL(url));
return this.getRouter(new com.alibaba.dubbo.common.DelegateURL(url));
}
}

View File

@ -29,7 +29,7 @@ public interface RuleConverter extends org.apache.dubbo.rpc.cluster.RuleConverte
@Override
default List<URL> convert(URL subscribeUrl, Object source) {
return this.convert(new com.alibaba.dubbo.common.URL(subscribeUrl), source).
return this.convert(new com.alibaba.dubbo.common.DelegateURL(subscribeUrl), source).
stream().map(url -> url.getOriginalURL()).collect(Collectors.toList());
}
}

View File

@ -229,7 +229,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.1</version>
<version>1.18.3</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.config;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.constants.LoggerCodeConstants;
import org.apache.dubbo.common.constants.RegistryConstants;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
@ -220,7 +221,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
@Override
@Transient
public T get() {
public T get(boolean check) {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
@ -229,12 +230,53 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
init();
init(check);
}
return ref;
}
@Override
public void checkOrDestroy(long timeout) {
if (!initialized || ref == null) {
return;
}
try {
checkInvokerAvailable(timeout);
} catch (Throwable t) {
logAndCleanup(t);
throw t;
}
}
private void logAndCleanup(Throwable t) {
try {
if (invoker != null) {
invoker.destroy();
}
} catch (Throwable destroy) {
logger.warn(CONFIG_FAILED_DESTROY_INVOKER, "", "", "Unexpected error occurred when destroy invoker of ReferenceConfig(" + url + ").", t);
}
if (consumerModel != null) {
ModuleServiceRepository repository = getScopeModel().getServiceRepository();
repository.unregisterConsumer(consumerModel);
}
initialized = false;
invoker = null;
ref = null;
consumerModel = null;
serviceMetadata.setTarget(null);
serviceMetadata.getAttributeMap().remove(PROXY_CLASS_REF);
// Thrown by checkInvokerAvailable().
if (t.getClass() == IllegalStateException.class &&
t.getMessage().contains("No provider available for the service")) {
// 2-2 - No provider available.
logger.error(CLUSTER_NO_VALID_PROVIDER, "server crashed", "", "No provider available.", t);
}
}
@Override
public synchronized void destroy() {
super.destroy();
@ -258,6 +300,10 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
}
protected synchronized void init() {
init(true);
}
protected synchronized void init(boolean check) {
if (initialized && ref != null) {
return;
}
@ -308,33 +354,11 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
consumerModel.setProxyObject(ref);
consumerModel.initMethodModels();
checkInvokerAvailable();
if (check) {
checkInvokerAvailable(0);
}
} catch (Throwable t) {
try {
if (invoker != null) {
invoker.destroy();
}
} catch (Throwable destroy) {
logger.warn(CONFIG_FAILED_DESTROY_INVOKER, "", "", "Unexpected error occurred when destroy invoker of ReferenceConfig(" + url + ").", t);
}
if (consumerModel != null) {
ModuleServiceRepository repository = getScopeModel().getServiceRepository();
repository.unregisterConsumer(consumerModel);
}
initialized = false;
invoker = null;
ref = null;
consumerModel = null;
serviceMetadata.setTarget(null);
serviceMetadata.getAttributeMap().remove(PROXY_CLASS_REF);
// Thrown by checkInvokerAvailable().
if (t.getClass() == IllegalStateException.class &&
t.getMessage().contains("No provider available for the service")) {
// 2-2 - No provider available.
logger.error(CLUSTER_NO_VALID_PROVIDER, "server crashed", "", "No provider available.", t);
}
logAndCleanup(t);
throw t;
}
@ -631,8 +655,31 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
}
}
private void checkInvokerAvailable() throws IllegalStateException {
if (shouldCheck() && !invoker.isAvailable()) {
private void checkInvokerAvailable(long timeout) throws IllegalStateException {
if (!shouldCheck()) {
return;
}
boolean available = invoker.isAvailable();
if (available) {
return;
}
long startTime = System.currentTimeMillis();
long checkDeadline = startTime + timeout;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
available = invoker.isAvailable();
} while (!available && checkDeadline > System.currentTimeMillis());
logger.warn(LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS, "", "",
"Check reference of [" + getUniqueServiceName() + "] failed very beginning. " +
"After " + (System.currentTimeMillis() - startTime) + "ms reties, finally " +
(available ? "succeed" : "failed") + ".");
if (!available) {
// 2-2 - No provider available.
IllegalStateException illegalStateException = new IllegalStateException("Failed to check the status of the service "

View File

@ -280,7 +280,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
}
@Override
public void export() {
public void export(boolean register) {
if (this.exported) {
return;
}
@ -300,19 +300,37 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
this.init();
if (shouldDelay()) {
doDelayExport();
// should register if delay export
doDelayExport(true);
} else {
doExport();
doExport(register);
}
}
}
}
protected void doDelayExport() {
@Override
public void register() {
if (!this.exported) {
return;
}
synchronized (this) {
if (!this.exported) {
return;
}
for (Exporter<?> exporter : exporters) {
exporter.register();
}
}
}
protected void doDelayExport(boolean register) {
ExecutorRepository.getInstance(getScopeModel().getApplicationModel()).getServiceExportExecutor()
.schedule(() -> {
try {
doExport();
doExport(register);
} catch (Exception e) {
logger.error(CONFIG_FAILED_EXPORT_SERVICE, "configuration server disconnected", "", "Failed to (async)export service config: " + interfaceName, e);
}
@ -439,7 +457,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
checkAndUpdateSubConfigs();
}
protected synchronized void doExport() {
protected synchronized void doExport(boolean register) {
if (unexported) {
throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
}
@ -450,12 +468,12 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
if (StringUtils.isEmpty(path)) {
path = interfaceName;
}
doExportUrls();
doExportUrls(register);
exported();
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
private void doExportUrls(boolean register) {
ModuleServiceRepository repository = getScopeModel().getServiceRepository();
ServiceDescriptor serviceDescriptor;
final boolean serverService = ref instanceof ServerService;
@ -490,7 +508,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
// In case user specified path, register service one more time to map it to path.
repository.registerService(pathKey, interfaceClass);
}
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
doExportUrlsFor1Protocol(protocolConfig, registryURLs, register);
}
return null;
}
@ -499,7 +517,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
providerModel.setServiceUrls(urls);
}
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs, boolean register) {
Map<String, String> map = buildAttributes(protocolConfig);
// remove null key and null value
@ -511,7 +529,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
processServiceExecutor(url);
exportUrl(url, registryURLs);
exportUrl(url, registryURLs, register);
}
private void processServiceExecutor(URL url) {
@ -695,7 +713,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
return url;
}
private void exportUrl(URL url, List<URL> registryURLs) {
private void exportUrl(URL url, List<URL> registryURLs, boolean register) {
String scope = url.getParameter(SCOPE_KEY);
// don't export when none is configured
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
@ -719,7 +737,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
build();
}
url = exportRemote(url, registryURLs);
url = exportRemote(url, registryURLs, register);
if (!isGeneric(generic) && !getScopeModel().isInternal()) {
MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel());
}
@ -734,7 +752,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
URL localUrl = URLBuilder.from(url).
setProtocol(protocol).
build();
localUrl = exportRemote(localUrl, registryURLs);
localUrl = exportRemote(localUrl, registryURLs, register);
if (!isGeneric(generic) && !getScopeModel().isInternal()) {
MetadataUtils.publishServiceDefinition(localUrl, providerModel.getServiceModel(), getApplicationModel());
}
@ -746,7 +764,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
this.urls.add(url);
}
private URL exportRemote(URL url, List<URL> registryURLs) {
private URL exportRemote(URL url, List<URL> registryURLs, boolean register) {
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
@ -778,7 +796,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
}
}
doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true);
doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true, register);
}
} else {
@ -787,7 +805,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
doExportUrl(url, true);
doExportUrl(url, true, register);
}
@ -795,7 +813,10 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrl(URL url, boolean withMetaData) {
private void doExportUrl(URL url, boolean withMetaData, boolean register) {
if (!register) {
url = url.addParameter(REGISTER_KEY, false);
}
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
if (withMetaData) {
invoker = new DelegateProviderMetaDataInvoker(invoker, this);
@ -817,7 +838,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
local = local.setScopeModel(getScopeModel())
.setServiceModel(providerModel);
local = local.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL);
doExportUrl(local, false);
doExportUrl(local, false, true);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
}

View File

@ -936,6 +936,17 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
}
@Override
public void refreshServiceInstance() {
if (registered) {
try {
ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);
} catch (Exception e) {
logger.error(CONFIG_REFRESH_INSTANCE_ERROR, "", "", "Refresh instance and metadata error.", e);
}
}
}
@Override
public void increaseServiceRefreshCount() {
serviceRefreshState.incrementAndGet();

View File

@ -54,10 +54,11 @@ public class DefaultMetricsServiceExporter implements MetricsServiceExporter, Sc
MetricsConfig metricsConfig = applicationModel.getApplicationConfigManager().getMetrics().orElse(null);
// TODO compatible with old usage of metrics, remove protocol check after new metrics is ready for use.
if (metricsConfig != null && metricsService == null) {
if (PROTOCOL_PROMETHEUS.equals(metricsConfig.getProtocol()) ) {
String protocol = Optional.ofNullable(metricsConfig.getProtocol()).orElse(PROTOCOL_PROMETHEUS);
if (PROTOCOL_PROMETHEUS.equals(protocol) ) {
this.metricsService = applicationModel.getExtensionLoader(MetricsService.class).getDefaultExtension();
} else {
logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, "", "", "Protocol " + metricsConfig.getProtocol() + " not support for new metrics mechanism. " +
logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, "", "", "Protocol " + protocol + " not support for new metrics mechanism. " +
"Using old metrics mechanism instead.");
}
}

View File

@ -32,6 +32,7 @@ import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.ReferenceConfigBase;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.ServiceConfigBase;
import org.apache.dubbo.config.context.ModuleConfigManager;
@ -174,7 +175,17 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
// if no async export/refer services, just set started
if (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) {
// publish module started event
onModuleStarted();
// register services to registry
registerServices();
// check reference config
checkReferences();
// complete module start future after application state changed
completeStartFuture(true);
} else {
frameworkExecutorRepository.getSharedExecutor().submit(() -> {
try {
@ -182,17 +193,30 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
waitExportFinish();
// wait for refer finish
waitReferFinish();
// publish module started event
onModuleStarted();
// register services to registry
registerServices();
// check reference config
checkReferences();
} catch (Throwable e) {
logger.warn(CONFIG_FAILED_WAIT_EXPORT_REFER, "", "", "wait for export/refer services occurred an exception", e);
onModuleFailed(getIdentifier() + " start failed: " + e, e);
} finally {
onModuleStarted();
// complete module start future after application state changed
completeStartFuture(true);
}
});
}
} catch (Throwable e) {
onModuleFailed(getIdentifier() + " start failed: " + e, e);
throw e;
}
return startFuture;
}
@ -300,16 +324,11 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
}
private void onModuleStarted() {
try {
if (isStarting()) {
setStarted();
logger.info(getIdentifier() + " has started.");
applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STARTED);
}
} finally {
// complete module start future after application state changed
completeStartFuture(true);
}
}
private void onModuleFailed(String msg, Throwable ex) {
@ -366,6 +385,21 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
}
}
private void registerServices() {
for (ServiceConfigBase sc : configManager.getServices()) {
if (!Boolean.FALSE.equals(sc.isRegister())) {
registerServiceInternal(sc);
}
}
applicationDeployer.refreshServiceInstance();
}
private void checkReferences() {
for (ReferenceConfigBase<?> rc : configManager.getReferences()) {
referenceCache.check(rc, 3000);
}
}
private void exportServiceInternal(ServiceConfigBase sc) {
ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
if (!serviceConfig.isRefreshed()) {
@ -390,12 +424,23 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
asyncExportingFutures.add(future);
} else {
if (!sc.isExported()) {
sc.export();
sc.export(false);
exportedServices.add(sc);
}
}
}
private void registerServiceInternal(ServiceConfigBase sc) {
ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
if (!serviceConfig.isRefreshed()) {
serviceConfig.refresh();
}
if (!sc.isExported()) {
return;
}
sc.register();
}
private void unexportServices() {
exportedServices.forEach(sc -> {
try {
@ -428,7 +473,7 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
ExecutorService executor = executorRepository.getServiceReferExecutor();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
referenceCache.get(rc);
referenceCache.get(rc, false);
} catch (Throwable t) {
logger.error(CONFIG_FAILED_EXPORT_SERVICE, "", "", "Failed to async export service config: " + getIdentifier() + " , catch error : " + t.getMessage(), t);
}
@ -436,7 +481,7 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
asyncReferringFutures.add(future);
} else {
referenceCache.get(rc);
referenceCache.get(rc, false);
}
}
} catch (Throwable t) {
@ -456,6 +501,9 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
});
asyncReferringFutures.clear();
referenceCache.destroyAll();
for (ReferenceConfigBase<?> rc : configManager.getReferences()) {
rc.destroy();
}
} catch (Exception ignored) {
}
}

View File

@ -43,7 +43,7 @@ public class CompositeReferenceCache implements ReferenceCache {
}
@Override
public <T> T get(ReferenceConfigBase<T> referenceConfig) {
public <T> T get(ReferenceConfigBase<T> referenceConfig, boolean check) {
Class<?> type = referenceConfig.getInterfaceClass();
String key = BaseServiceMetadata.buildServiceKey(type.getName(), referenceConfig.getGroup(), referenceConfig.getVersion());
@ -57,7 +57,7 @@ public class CompositeReferenceCache implements ReferenceCache {
"Call ReferenceConfig#get() directly for non-singleton ReferenceConfig instead of using ReferenceCache#get(ReferenceConfig)");
}
if (proxy == null) {
proxy = referenceConfig.get();
proxy = referenceConfig.get(check);
}
return proxy;
}
@ -111,6 +111,20 @@ public class CompositeReferenceCache implements ReferenceCache {
}
}
@Override
public void check(String key, Class<?> type, long timeout) {
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
moduleModel.getDeployer().getReferenceCache().check(key, type, timeout);
}
}
@Override
public <T> void check(ReferenceConfigBase<T> referenceConfig, long timeout) {
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
moduleModel.getDeployer().getReferenceCache().check(referenceConfig, timeout);
}
}
@Override
public void destroy(Class<?> type) {
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {

View File

@ -110,7 +110,7 @@ public class SimpleReferenceCache implements ReferenceCache {
@Override
@SuppressWarnings("unchecked")
public <T> T get(ReferenceConfigBase<T> rc) {
public <T> T get(ReferenceConfigBase<T> rc, boolean check) {
String key = generator.generateKey(rc);
Class<?> type = rc.getInterfaceClass();
@ -129,7 +129,7 @@ public class SimpleReferenceCache implements ReferenceCache {
referencesOfType.add(rc);
List<ReferenceConfigBase<?>> referenceConfigList = ConcurrentHashMapUtils.computeIfAbsent(referenceKeyMap, key, _k -> Collections.synchronizedList(new ArrayList<>()));
referenceConfigList.add(rc);
proxy = rc.get();
proxy = rc.get(check);
}
return proxy;
@ -203,6 +203,29 @@ public class SimpleReferenceCache implements ReferenceCache {
return null;
}
@Override
public void check(String key, Class<?> type, long timeout) {
List<ReferenceConfigBase<?>> referencesOfKey = referenceKeyMap.get(key);
if (CollectionUtils.isEmpty(referencesOfKey)) {
return;
}
List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.get(type);
if (CollectionUtils.isEmpty(referencesOfType)) {
return;
}
for (ReferenceConfigBase<?> rc : referencesOfKey) {
rc.checkOrDestroy(timeout);
}
}
@Override
public <T> void check(ReferenceConfigBase<T> referenceConfig, long timeout) {
String key = generator.generateKey(referenceConfig);
Class<?> type = referenceConfig.getInterfaceClass();
check(key, type, timeout);
}
@Override
public void destroy(String key, Class<?> type) {
List<ReferenceConfigBase<?>> referencesOfKey = referenceKeyMap.remove(key);

View File

@ -188,7 +188,7 @@ class MultipleRegistryCenterExportProviderIntegrationTest implements Integration
// 1. InjvmExporter
// 2. DubboExporter with service-discovery-registry protocol
// 3. DubboExporter with registry protocol
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 3);
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 5);
// The exported exporter contains MultipleRegistryCenterExportProviderFilter
Assertions.assertTrue(exporterListener.getFilters().contains(filter));
@ -244,4 +244,4 @@ class MultipleRegistryCenterExportProviderIntegrationTest implements Integration
logger.info(getClass().getSimpleName() + " testcase is ending...");
registryProtocolListener = null;
}
}
}

View File

@ -40,11 +40,11 @@ public class MockReferenceConfig extends ReferenceConfig<FooService> {
}
@Override
public synchronized FooService get() {
public synchronized FooService get(boolean check) {
if (value != null) return value;
counter.getAndIncrement();
value = super.get();
value = super.get(check);
return value;
}

View File

@ -40,11 +40,11 @@ public class XxxMockReferenceConfig extends ReferenceConfig<XxxService> {
}
@Override
public synchronized XxxService get() {
public synchronized XxxService get(boolean check) {
if (value != null) return value;
counter.getAndIncrement();
value = super.get();
value = super.get(check);
return value;
}

View File

@ -16,6 +16,10 @@
*/
package org.apache.dubbo.config.spring;
import org.apache.dubbo.common.bytecode.Proxy;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.StringUtils;
@ -26,11 +30,11 @@ import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;
import org.apache.dubbo.config.spring.schema.DubboBeanDefinitionParser;
import org.apache.dubbo.config.spring.util.LazyTargetInvocationHandler;
import org.apache.dubbo.config.spring.util.LazyTargetSource;
import org.apache.dubbo.config.support.Parameter;
import org.apache.dubbo.rpc.proxy.AbstractProxyFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.AbstractLazyCreationTargetSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
@ -45,10 +49,13 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED;
/**
* <p>
@ -99,7 +106,7 @@ import java.util.Map;
*/
public class ReferenceBean<T> implements FactoryBean<T>,
ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
private transient ApplicationContext applicationContext;
private ClassLoader beanClassLoader;
@ -124,6 +131,9 @@ public class ReferenceBean<T> implements FactoryBean<T>,
// 'interfaceName' field for compatible with seata-1.4.0: io.seata.rm.tcc.remoting.parser.DubboRemotingParser#getServiceDesc()
private String interfaceName;
// proxy style
private String proxy;
//from annotation attributes
private Map<String, Object> referenceProps;
@ -240,6 +250,10 @@ public class ReferenceBean<T> implements FactoryBean<T>,
propertyValues = beanDefinition.getPropertyValues();
}
}
if (referenceProps != null) {
this.proxy = (String) referenceProps.get(ReferenceAttributes.PROXY);
}
Assert.notNull(this.interfaceName, "The interface name of ReferenceBean is not initialized");
ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
@ -325,24 +339,56 @@ public class ReferenceBean<T> implements FactoryBean<T>,
//set proxy interfaces
//see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
proxyFactory.addInterface(interfaceClass);
List<Class<?>> interfaces = new ArrayList<>();
interfaces.add(interfaceClass);
Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
for (Class<?> anInterface : internalInterfaces) {
proxyFactory.addInterface(anInterface);
}
Collections.addAll(interfaces, internalInterfaces);
if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
//add service interface
try {
Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
proxyFactory.addInterface(serviceInterface);
interfaces.add(serviceInterface);
} catch (ClassNotFoundException e) {
// generic call maybe without service interface class locally
}
}
this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
if (StringUtils.isEmpty(this.proxy) || CommonConstants.DEFAULT_PROXY.equalsIgnoreCase(this.proxy)) {
generateFromJavassistFirst(interfaces);
}
if (this.lazyProxy == null) {
generateFromJdk(interfaces);
}
}
private void generateFromJavassistFirst(List<Class<?>> interfaces) {
try {
this.lazyProxy = Proxy.getProxy(interfaces.toArray(new Class[0])).newInstance(new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));
} catch (Throwable fromJavassist) {
// try fall back to JDK proxy factory
try {
this.lazyProxy = java.lang.reflect.Proxy.newProxyInstance(beanClassLoader, interfaces.toArray(new Class[0]), new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));
logger.error(PROXY_FAILED, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. " +
"Interfaces: " + interfaces, fromJavassist);
} catch (Throwable fromJdk) {
logger.error(PROXY_FAILED, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + interfaces + " Javassist Error.", fromJavassist);
logger.error(PROXY_FAILED, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + interfaces + " JDK Error.", fromJdk);
throw fromJavassist;
}
}
}
private void generateFromJdk(List<Class<?>> interfaces) {
try {
this.lazyProxy = java.lang.reflect.Proxy.newProxyInstance(beanClassLoader, interfaces.toArray(new Class[0]), new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));
} catch (Throwable fromJdk) {
logger.error(PROXY_FAILED, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + interfaces + " JDK Error.", fromJdk);
throw fromJdk;
}
}
private Object getCallProxy() throws Exception {
@ -350,7 +396,7 @@ public class ReferenceBean<T> implements FactoryBean<T>,
throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");
}
//get reference proxy
//Subclasses should synchronize on the given Object if they perform any sort of extended singleton creation phase.
//Subclasses should synchronize on the given Object if they perform any sort of extended singleton creation phase.
// In particular, subclasses should not have their own mutexes involved in singleton creation, to avoid the potential for deadlocks in lazy-init situations.
//The redundant type cast is to be compatible with earlier than spring-4.2
synchronized (((DefaultSingletonBeanRegistry) getBeanFactory()).getSingletonMutex()) {
@ -358,17 +404,11 @@ public class ReferenceBean<T> implements FactoryBean<T>,
}
}
private class DubboReferenceLazyInitTargetSource extends AbstractLazyCreationTargetSource {
private class DubboReferenceLazyInitTargetSource implements LazyTargetSource {
@Override
protected Object createObject() throws Exception {
public Object getTarget() throws Exception {
return getCallProxy();
}
@Override
public synchronized Class<?> getTargetClass() {
return getInterfaceClass();
}
}
public void setInterfaceClass(Class<?> interfaceClass) {

View File

@ -18,6 +18,8 @@ package org.apache.dubbo.config.spring.beans.factory.annotation;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
@ -53,7 +55,6 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAnnotationAttributes;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;
@ -135,7 +136,7 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);
AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);
if (attributes != null) {
@ -180,7 +181,7 @@ public abstract class AbstractAnnotationBeanPostProcessor implements
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = getAnnotationAttributes(bridgedMethod, annotationType, getEnvironment(), true, true);
AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(bridgedMethod, annotationType, getEnvironment(), true, true);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {

View File

@ -16,6 +16,8 @@
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
@ -24,8 +26,6 @@ import org.springframework.core.env.PropertyResolver;
import java.lang.annotation.Annotation;
import java.util.Map;
import static com.alibaba.spring.util.AnnotationUtils.getAttributes;
/**
* {@link Annotation} {@link PropertyValues} Adapter
*
@ -45,12 +45,12 @@ public class AnnotationPropertyValuesAdapter implements PropertyValues {
*/
public AnnotationPropertyValuesAdapter(Map<String, Object> attributes, PropertyResolver propertyResolver,
String... ignoreAttributeNames) {
this.delegate = new MutablePropertyValues(getAttributes(attributes, propertyResolver, ignoreAttributeNames));
this.delegate = new MutablePropertyValues(AnnotationUtils.getAttributes(attributes, propertyResolver, ignoreAttributeNames));
}
public AnnotationPropertyValuesAdapter(Annotation annotation, PropertyResolver propertyResolver,
boolean ignoreDefaultValue, String... ignoreAttributeNames) {
this.delegate = new MutablePropertyValues(getAttributes(annotation, propertyResolver, ignoreDefaultValue, ignoreAttributeNames));
this.delegate = new MutablePropertyValues(AnnotationUtils.getAttributes(annotation, propertyResolver, ignoreDefaultValue, ignoreAttributeNames));
}
public AnnotationPropertyValuesAdapter(Annotation annotation, PropertyResolver propertyResolver, String... ignoreAttributeNames) {

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.beans.factory.annotation;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar;
import org.apache.dubbo.config.spring.util.BeanRegistrar;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
@ -25,7 +26,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import static com.alibaba.spring.util.BeanRegistrar.hasAlias;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import static org.springframework.util.StringUtils.hasText;
@ -65,7 +65,7 @@ public class DubboConfigAliasPostProcessor implements BeanDefinitionRegistryPost
String id = ((AbstractConfig) bean).getId();
if (hasText(id) // id MUST be present in AbstractConfig
&& !nullSafeEquals(id, beanName) // id MUST NOT be equal to bean name
&& !hasAlias(registry, beanName, id)) { // id MUST NOT be present in AliasRegistry
&& !BeanRegistrar.hasAlias(registry, beanName, id)) { // id MUST NOT be present in AliasRegistry
registry.registerAlias(beanName, id);
}
}

View File

@ -31,8 +31,10 @@ import org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;
import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
@ -65,7 +67,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;
import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
import static org.springframework.util.StringUtils.hasText;
@ -385,7 +386,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
boolean renameable = true;
// referenceBeanName
String referenceBeanName = getAttribute(attributes, ReferenceAttributes.ID);
String referenceBeanName = AnnotationUtils.getAttribute(attributes, ReferenceAttributes.ID);
if (hasText(referenceBeanName)) {
renameable = false;
} else {

View File

@ -16,9 +16,9 @@
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;
import com.alibaba.spring.util.AnnotationUtils;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.AnnotationUtils;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
@ -32,7 +32,9 @@ import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.apache.dubbo.config.spring.util.ObjectUtils;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
@ -80,7 +82,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.alibaba.spring.util.ObjectUtils.of;
import static java.util.Arrays.asList;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUPLICATED_BEAN_DEFINITION;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_ANNOTATIONS_FOUND;
@ -431,7 +432,7 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
String[] ignoreAttributeNames = ObjectUtils.of("provider", "monitor", "application", "module", "registry", "protocol",
"methods", "interfaceName", "parameters", "executor");
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));

View File

@ -20,12 +20,12 @@ import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveInterfaceName;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
@ -63,8 +63,8 @@ public class ServiceBeanNameBuilder {
private ServiceBeanNameBuilder(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
this(resolveInterfaceName(attributes, defaultInterfaceClass), environment);
this.group(getAttribute(attributes,"group"));
this.version(getAttribute(attributes,"version"));
this.group(AnnotationUtils.getAttribute(attributes,"group"));
this.version(AnnotationUtils.getAttribute(attributes,"version"));
}
/**

View File

@ -18,8 +18,9 @@ package org.apache.dubbo.config.spring.beans.factory.config;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.Constants;
import org.apache.dubbo.config.spring.util.GenericBeanPostProcessorAdapter;
import org.apache.dubbo.config.spring.util.ObjectUtils;
import com.alibaba.spring.beans.factory.config.GenericBeanPostProcessorAdapter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
@ -34,7 +35,6 @@ import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import static com.alibaba.spring.util.ObjectUtils.of;
import static org.springframework.aop.support.AopUtils.getTargetClass;
import static org.springframework.beans.BeanUtils.getPropertyDescriptor;
import static org.springframework.util.ReflectionUtils.invokeMethod;
@ -91,7 +91,7 @@ public class DubboConfigDefaultPropertyValueBeanPostProcessor extends GenericBea
Method setterMethod = propertyDescriptor.getWriteMethod();
if (setterMethod != null) { // the getter and setter methods are present
if (Arrays.equals(of(String.class), setterMethod.getParameterTypes())) { // the param type is String
if (Arrays.equals(ObjectUtils.of(String.class), setterMethod.getParameterTypes())) { // the param type is String
// set bean name to the value of the property
invokeMethod(setterMethod, bean, beanName);
}

View File

@ -16,11 +16,6 @@
*/
package org.apache.dubbo.config.spring.context;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_STOP_DUBBO_ERROR;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import java.util.concurrent.Future;
import org.apache.dubbo.common.deploy.DeployListenerAdapter;
import org.apache.dubbo.common.deploy.DeployState;
import org.apache.dubbo.common.deploy.ModuleDeployer;
@ -28,10 +23,12 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.config.spring.context.event.DubboApplicationStateEvent;
import org.apache.dubbo.config.spring.context.event.DubboModuleStateEvent;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModelConstants;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@ -41,6 +38,12 @@ import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import java.util.concurrent.Future;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_STOP_DUBBO_ERROR;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
/**
* An ApplicationListener to control Dubbo application.
*/
@ -62,39 +65,73 @@ public class DubboDeployApplicationListener implements ApplicationListener<Appli
applicationModel.getDeployer().addDeployListener(new DeployListenerAdapter<ApplicationModel>(){
@Override
public void onStarting(ApplicationModel scopeModel) {
publishEvent(DeployState.STARTING);
publishApplicationEvent(DeployState.STARTING);
}
@Override
public void onStarted(ApplicationModel scopeModel) {
publishEvent(DeployState.STARTED);
publishApplicationEvent(DeployState.STARTED);
}
@Override
public void onStopping(ApplicationModel scopeModel) {
publishEvent(DeployState.STOPPING);
publishApplicationEvent(DeployState.STOPPING);
}
@Override
public void onStopped(ApplicationModel scopeModel) {
publishEvent(DeployState.STOPPED);
publishApplicationEvent(DeployState.STOPPED);
}
@Override
public void onFailure(ApplicationModel scopeModel, Throwable cause) {
publishEvent(DeployState.FAILED, cause);
publishApplicationEvent(DeployState.FAILED, cause);
}
});
moduleModel.getDeployer().addDeployListener(new DeployListenerAdapter<ModuleModel>(){
@Override
public void onStarting(ModuleModel scopeModel) {
publishModuleEvent(DeployState.STARTING);
}
@Override
public void onStarted(ModuleModel scopeModel) {
publishModuleEvent(DeployState.STARTED);
}
@Override
public void onStopping(ModuleModel scopeModel) {
publishModuleEvent(DeployState.STOPPING);
}
@Override
public void onStopped(ModuleModel scopeModel) {
publishModuleEvent(DeployState.STOPPED);
}
@Override
public void onFailure(ModuleModel scopeModel, Throwable cause) {
publishModuleEvent(DeployState.FAILED, cause);
}
});
}
private void publishEvent(DeployState state) {
private void publishApplicationEvent(DeployState state) {
applicationContext.publishEvent(new DubboApplicationStateEvent(applicationModel, state));
}
private void publishEvent(DeployState state, Throwable cause) {
private void publishApplicationEvent(DeployState state, Throwable cause) {
applicationContext.publishEvent(new DubboApplicationStateEvent(applicationModel, state, cause));
}
private void publishModuleEvent(DeployState state) {
applicationContext.publishEvent(new DubboModuleStateEvent(moduleModel, state));
}
private void publishModuleEvent(DeployState state, Throwable cause) {
applicationContext.publishEvent(new DubboModuleStateEvent(moduleModel, state, cause));
}
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
if (nullSafeEquals(applicationContext, event.getSource())) {

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.context.config;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;
import org.apache.dubbo.config.spring.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@ -25,7 +26,6 @@ import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import static com.alibaba.spring.util.ObjectUtils.of;
import static org.springframework.beans.BeanUtils.getPropertyDescriptor;
/**
@ -71,7 +71,7 @@ public class NamePropertyDefaultValueDubboConfigBeanCustomizer implements DubboC
Method setNameMethod = propertyDescriptor.getWriteMethod();
if (setNameMethod != null) { // "setName" and "getName" methods are present
if (Arrays.equals(of(String.class), setNameMethod.getParameterTypes())) { // the param type is String
if (Arrays.equals(ObjectUtils.of(String.class), setNameMethod.getParameterTypes())) { // the param type is String
// set bean name to the value of the "name" property
ReflectionUtils.invokeMethod(setNameMethod, dubboConfigBean, beanName);
}

View File

@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.context.event;
import org.apache.dubbo.common.deploy.DeployState;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.context.ApplicationEvent;
/**
* Dubbo's module state event on starting/started/stopping/stopped
*/
public class DubboModuleStateEvent extends ApplicationEvent {
private final DeployState state;
private Throwable cause;
public DubboModuleStateEvent(ModuleModel applicationModel, DeployState state) {
super(applicationModel);
this.state = state;
}
public DubboModuleStateEvent(ModuleModel applicationModel, DeployState state, Throwable cause) {
super(applicationModel);
this.state = state;
this.cause = cause;
}
public ModuleModel getModule() {
return (ModuleModel) getSource();
}
public DeployState getState() {
return state;
}
public Throwable getCause() {
return cause;
}
}

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.config.spring.context.properties;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.spring.util.PropertySourcesUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.validation.BindingResult;
@ -27,8 +28,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties;
/**
* Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder}
*/
@ -41,7 +40,7 @@ public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {
dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
// Get properties under specified prefix from PropertySources
Map<String, Object> properties = getSubProperties(getPropertySources(), prefix);
Map<String, Object> properties = PropertySourcesUtils.getSubProperties(getPropertySources(), prefix);
// Convert Map to MutablePropertyValues
MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
// Bind

View File

@ -16,15 +16,16 @@
*/
package org.apache.dubbo.config.spring.reference;
import com.alibaba.spring.util.AnnotationUtils;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.annotation.ProvidedBy;
import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;

View File

@ -29,11 +29,12 @@ import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationPropertyValuesAdapter;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.apache.dubbo.config.spring.util.DubboAnnotationUtils;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.config.spring.util.ObjectUtils;
import org.apache.dubbo.rpc.model.ModuleModel;
import com.alibaba.spring.util.AnnotationUtils;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.support.DefaultConversionService;
@ -43,9 +44,6 @@ import org.springframework.validation.DataBinder;
import java.util.Map;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static com.alibaba.spring.util.ObjectUtils.of;
/**
* {@link ReferenceConfig} Creator for @{@link DubboReference}
*
@ -54,7 +52,7 @@ import static com.alibaba.spring.util.ObjectUtils.of;
public class ReferenceCreator {
// Ignore those fields
static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry", "interfaceClass");
static final String[] IGNORE_FIELD_NAMES = ObjectUtils.of("application", "module", "consumer", "monitor", "registry", "interfaceClass");
private static final String ONRETURN = "onreturn";
@ -117,7 +115,7 @@ public class ReferenceCreator {
}
private void configureMonitorConfig(ReferenceConfig configBean) {
String monitorConfigId = getAttribute(attributes, "monitor");
String monitorConfigId = AnnotationUtils.getAttribute(attributes, "monitor");
if (StringUtils.hasText(monitorConfigId)) {
MonitorConfig monitorConfig = getConfig(monitorConfigId, MonitorConfig.class);
configBean.setMonitor(monitorConfig);
@ -125,7 +123,7 @@ public class ReferenceCreator {
}
private void configureModuleConfig(ReferenceConfig configBean) {
String moduleConfigId = getAttribute(attributes, "module");
String moduleConfigId = AnnotationUtils.getAttribute(attributes, "module");
if (StringUtils.hasText(moduleConfigId)) {
ModuleConfig moduleConfig = getConfig(moduleConfigId, ModuleConfig.class);
configBean.setModule(moduleConfig);
@ -134,7 +132,7 @@ public class ReferenceCreator {
private void configureConsumerConfig(ReferenceConfig<?> referenceBean) {
ConsumerConfig consumerConfig = null;
Object consumer = getAttribute(attributes, "consumer");
Object consumer = AnnotationUtils.getAttribute(attributes, "consumer");
if (consumer != null) {
if (consumer instanceof String) {
consumerConfig = getConfig((String) consumer, ConsumerConfig.class);

View File

@ -32,8 +32,8 @@ import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.config.nested.PrometheusConfig;
import org.apache.dubbo.config.nested.HistogramConfig;
import org.apache.dubbo.config.nested.PrometheusConfig;
import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
@ -103,9 +103,11 @@ public class DubboBeanDefinitionParser implements BeanDefinitionParser {
if (StringUtils.isNotEmpty(configId)) {
beanDefinition.getPropertyValues().addPropertyValue("id", configId);
}
// get id from name
String configName = "";
// get configName from name
if (StringUtils.isEmpty(configId)) {
configId = resolveAttribute(element, "name", parserContext);
configName = resolveAttribute(element, "name", parserContext);
}
String beanName = configId;
@ -113,13 +115,14 @@ public class DubboBeanDefinitionParser implements BeanDefinitionParser {
// generate bean name
String prefix = beanClass.getName();
int counter = 0;
beanName = prefix + "#" + counter;
beanName = prefix + (StringUtils.isEmpty(configName) ? "#" : ("#" + configName + "#")) + counter;
while (parserContext.getRegistry().containsBeanDefinition(beanName)) {
beanName = prefix + "#" + (counter++);
beanName = prefix + (StringUtils.isEmpty(configName) ? "#" : ("#" + configName + "#")) + (counter++);
}
}
beanDefinition.setAttribute(BEAN_NAME, beanName);
if (ProtocolConfig.class.equals(beanClass)) {
// for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
// BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
@ -184,7 +187,7 @@ public class DubboBeanDefinitionParser implements BeanDefinitionParser {
* For 'provider' 'protocol' 'registry', keep literal value (should be id/name) and set the value to 'registryIds' 'providerIds' protocolIds'
* The following process should make sure each id refers to the corresponding instance, here's how to find the instance for different use cases:
* 1. Spring, check existing bean by id, see{@link ServiceBean#afterPropertiesSet()}; then try to use id to find configs defined in remote Config Center
* 2. API, directly use id to find configs defined in remote Config Center; if all config instances are defined locally, please use {@link ServiceConfig#setRegistries(List)}
* 2. API, directly use id to find configs defined in remote Config Center; if all config instances are defined locally, please use {@link org.apache.dubbo.config.ServiceConfig#setRegistries(List)}
*/
beanDefinition.getPropertyValues().addPropertyValue(beanProperty + "Ids", value);
} else {

View File

@ -0,0 +1,437 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static java.lang.String.valueOf;
import static java.util.Arrays.asList;
import static org.springframework.core.annotation.AnnotationAttributes.fromMap;
import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue;
import static org.springframework.util.ClassUtils.resolveClassName;
import static org.springframework.util.CollectionUtils.isEmpty;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import static org.springframework.util.ReflectionUtils.findMethod;
import static org.springframework.util.ReflectionUtils.invokeMethod;
import static org.springframework.util.StringUtils.trimWhitespace;
@SuppressWarnings("unchecked")
public abstract class AnnotationUtils {
/**
* The class name of AnnotatedElementUtils that is introduced since Spring Framework 4
*/
public static final String ANNOTATED_ELEMENT_UTILS_CLASS_NAME = "org.springframework.core.annotation.AnnotatedElementUtils";
private static final Map<Integer, Boolean> annotatedElementUtilsPresentCache = new ConcurrentHashMap<>();
/**
* Get the {@link Annotation} attributes
*
* @param annotation specified {@link Annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return non-null
*/
public static Map<String, Object> getAttributes(Annotation annotation, PropertyResolver propertyResolver,
boolean ignoreDefaultValue, String... ignoreAttributeNames) {
return getAttributes(annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);
}
/**
* Get the {@link Annotation} attributes
*
* @param annotationAttributes the attributes of specified {@link Annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return non-null
*/
public static Map<String, Object> getAttributes(Map<String, Object> annotationAttributes,
PropertyResolver propertyResolver, String... ignoreAttributeNames) {
Set<String> ignoreAttributeNamesSet = new HashSet<>(Arrays.asList(ignoreAttributeNames));
Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();
for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {
String attributeName = annotationAttribute.getKey();
Object attributeValue = annotationAttribute.getValue();
// ignore attribute name
if (ignoreAttributeNamesSet.contains(attributeName)) {
continue;
}
if (attributeValue instanceof String) {
attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);
} else if (attributeValue instanceof String[]) {
String[] values = (String[]) attributeValue;
for (int i = 0; i < values.length; i++) {
values[i] = resolvePlaceholders(values[i], propertyResolver);
}
attributeValue = values;
}
actualAttributes.put(attributeName, attributeValue);
}
return actualAttributes;
}
/**
* @param annotation specified {@link Annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return
*/
public static Map<String, Object> getAttributes(Annotation annotation,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Map<String, Object> annotationAttributes = org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);
String[] actualIgnoreAttributeNames = ignoreAttributeNames;
if (ignoreDefaultValue && !isEmpty(annotationAttributes)) {
List<String> attributeNamesToIgnore = new LinkedList<String>(asList(ignoreAttributeNames));
for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {
String attributeName = annotationAttribute.getKey();
Object attributeValue = annotationAttribute.getValue();
if (nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {
attributeNamesToIgnore.add(attributeName);
}
}
// extends the ignored list
actualIgnoreAttributeNames = attributeNamesToIgnore.toArray(new String[attributeNamesToIgnore.size()]);
}
return getAttributes(annotationAttributes, propertyResolver, actualIgnoreAttributeNames);
}
private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {
String resolvedValue = attributeValue;
if (propertyResolver != null) {
resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);
resolvedValue = trimWhitespace(resolvedValue);
}
return resolvedValue;
}
/**
* Get the attribute value
*
* @param attributes {@link Map the annotation attributes} or {@link AnnotationAttributes}
* @param attributeName the name of attribute
* @param <T> the type of attribute value
* @return the attribute value if found
*/
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName) {
return getAttribute(attributes, attributeName, false);
}
/**
* Get the attribute value the will
*
* @param attributes {@link Map the annotation attributes} or {@link AnnotationAttributes}
* @param attributeName the name of attribute
* @param required the required attribute or not
* @param <T> the type of attribute value
* @return the attribute value if found
* @throws IllegalStateException if attribute value can't be found
*/
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, boolean required) {
T value = getAttribute(attributes, attributeName, null);
if (required && value == null) {
throw new IllegalStateException("The attribute['" + attributeName + "] is required!");
}
return value;
}
/**
* Get the attribute value with default value
*
* @param attributes {@link Map the annotation attributes} or {@link AnnotationAttributes}
* @param attributeName the name of attribute
* @param defaultValue the default value of attribute
* @param <T> the type of attribute value
* @return the attribute value if found
*/
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, T defaultValue) {
T value = (T) attributes.get(attributeName);
return value == null ? defaultValue : value;
}
/**
* Get the required attribute value
*
* @param attributes {@link Map the annotation attributes} or {@link AnnotationAttributes}
* @param attributeName the name of attribute
* @param <T> the type of attribute value
* @return the attribute value if found
* @throws IllegalStateException if attribute value can't be found
*/
public static <T> T getRequiredAttribute(Map<String, Object> attributes, String attributeName) {
return getAttribute(attributes, attributeName, true);
}
/**
* Get the {@link AnnotationAttributes}
*
* @param annotation specified {@link Annotation}
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return non-null
* @see #getAnnotationAttributes(Annotation, PropertyResolver, boolean, String...)
*/
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
return getAnnotationAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);
}
/**
* Get the {@link AnnotationAttributes}
*
* @param annotation specified {@link Annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @param ignoreDefaultValue whether ignore default value or not
* @return non-null
* @see #getAttributes(Annotation, PropertyResolver, boolean, String...)
* @see #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...)
*/
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
return fromMap(getAttributes(annotation, propertyResolver, classValuesAsString, nestedAnnotationsAsMap,
ignoreDefaultValue, ignoreAttributeNames));
}
/**
* Get the {@link AnnotationAttributes}
*
* @param annotation specified {@link Annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return non-null
* @see #getAttributes(Annotation, PropertyResolver, boolean, String...)
* @see #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...)
*/
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, PropertyResolver propertyResolver,
boolean ignoreDefaultValue, String... ignoreAttributeNames) {
return getAnnotationAttributes(annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);
}
/**
* Get the {@link AnnotationAttributes}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>
*/
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Annotation annotation = annotatedElement.getAnnotation(annotationType);
return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
/**
* Get the {@link AnnotationAttributes}, if the argument <code>tryMergedAnnotation</code> is <code>true</code>,
* the {@link AnnotationAttributes} will be got from
* {@link #tryGetMergedAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...) merged annotation} first,
* if failed, and then to get from
* {@link #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, boolean, String...) normal one}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param ignoreDefaultValue whether ignore default value or not
* @param tryMergedAnnotation whether try merged annotation or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>
*/
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean ignoreDefaultValue,
boolean tryMergedAnnotation,
String... ignoreAttributeNames) {
return getAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
false, false, ignoreDefaultValue, tryMergedAnnotation, ignoreAttributeNames);
}
/**
* Get the {@link AnnotationAttributes}, if the argument <code>tryMergedAnnotation</code> is <code>true</code>,
* the {@link AnnotationAttributes} will be got from
* {@link #tryGetMergedAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...) merged annotation} first,
* if failed, and then to get from
* {@link #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, boolean, String...) normal one}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @param ignoreDefaultValue whether ignore default value or not
* @param tryMergedAnnotation whether try merged annotation or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>
*/
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
boolean tryMergedAnnotation,
String... ignoreAttributeNames) {
AnnotationAttributes attributes = null;
if (tryMergedAnnotation) {
attributes = tryGetMergedAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
if (attributes == null) {
attributes = getAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
return attributes;
}
/**
* Try to get the merged {@link Annotation annotation}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @return If current version of Spring Framework is below 4.2, return <code>null</code>
*/
public static Annotation tryGetMergedAnnotation(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap) {
Annotation mergedAnnotation = null;
ClassLoader classLoader = annotationType.getClassLoader();
if (annotatedElementUtilsPresentCache.computeIfAbsent(System.identityHashCode(classLoader),
(_k) -> ClassUtils.isPresent(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader))) {
Class<?> annotatedElementUtilsClass = resolveClassName(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader);
// getMergedAnnotation method appears in the Spring Framework 4.2
Method getMergedAnnotationMethod = findMethod(annotatedElementUtilsClass, "getMergedAnnotation",
AnnotatedElement.class, Class.class, boolean.class, boolean.class);
if (getMergedAnnotationMethod != null) {
mergedAnnotation = (Annotation) invokeMethod(getMergedAnnotationMethod, null,
annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
}
}
return mergedAnnotation;
}
/**
* Try to get {@link AnnotationAttributes the annotation attributes} after merging and resolving the placeholders
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment}
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @param ignoreDefaultValue whether ignore default value or not
* @param ignoreAttributeNames the attribute names of annotation should be ignored
* @return If the specified annotation type is not found, return <code>null</code>
*/
public static AnnotationAttributes tryGetMergedAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Annotation annotation = tryGetMergedAnnotation(annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
import org.springframework.core.AliasRegistry;
import static org.springframework.util.ObjectUtils.containsElement;
import static org.springframework.util.StringUtils.hasText;
/**
* Bean Registrar
*/
public abstract class BeanRegistrar {
/**
* Detect the alias is present or not in the given bean name from {@link AliasRegistry}
*
* @param registry {@link AliasRegistry}
* @param beanName the bean name
* @param alias alias to test
* @return if present, return <code>true</code>, or <code>false</code>
*/
public static boolean hasAlias(AliasRegistry registry, String beanName, String alias) {
return hasText(beanName) && hasText(alias) && containsElement(registry.getAliases(beanName), alias);
}
}

View File

@ -32,7 +32,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.springframework.util.ClassUtils.getAllInterfacesForClass;
import static org.springframework.util.StringUtils.hasText;
@ -78,7 +77,7 @@ public class DubboAnnotationUtils {
*/
public static String resolveInterfaceName(Map<String, Object> attributes, Class<?> defaultInterfaceClass) {
// 1. get from DubboService.interfaceName()
String interfaceClassName = getAttribute(attributes, "interfaceName");
String interfaceClassName = AnnotationUtils.getAttribute(attributes, "interfaceName");
if (StringUtils.hasText(interfaceClassName)) {
if (GenericService.class.getName().equals(interfaceClassName) ||
com.alibaba.dubbo.rpc.service.GenericService.class.getName().equals(interfaceClassName)) {
@ -88,7 +87,7 @@ public class DubboAnnotationUtils {
}
// 2. get from DubboService.interfaceClass()
Class<?> interfaceClass = getAttribute(attributes, "interfaceClass");
Class<?> interfaceClass = AnnotationUtils.getAttribute(attributes, "interfaceClass");
if (interfaceClass == null || void.class.equals(interfaceClass)) { // default or set void.class for purpose.
interfaceClass = null;
} else if (GenericService.class.isAssignableFrom(interfaceClass)) {

View File

@ -0,0 +1,125 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ClassUtils;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Generic {@link BeanPostProcessor} Adapter
*
* @see BeanPostProcessor
*/
@SuppressWarnings("unchecked")
public abstract class GenericBeanPostProcessorAdapter<T> implements BeanPostProcessor {
private final Class<T> beanType;
public GenericBeanPostProcessorAdapter() {
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
this.beanType = (Class<T>) actualTypeArguments[0];
}
@Override
public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (ClassUtils.isAssignableValue(beanType, bean)) {
return doPostProcessBeforeInitialization((T) bean, beanName);
}
return bean;
}
@Override
public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (ClassUtils.isAssignableValue(beanType, bean)) {
return doPostProcessAfterInitialization((T) bean, beanName);
}
return bean;
}
/**
* Bean Type
*
* @return Bean Type
*/
public final Class<T> getBeanType() {
return beanType;
}
/**
* Adapter BeanPostProcessor#postProcessBeforeInitialization(Object, String) method , sub-type
* could override this method.
*
* @param bean Bean Object
* @param beanName Bean Name
* @return Bean Object
* @see BeanPostProcessor#postProcessBeforeInitialization(Object, String)
*/
protected T doPostProcessBeforeInitialization(T bean, String beanName) throws BeansException {
processBeforeInitialization(bean, beanName);
return bean;
}
/**
* Adapter BeanPostProcessor#postProcessAfterInitialization(Object, String) method , sub-type
* could override this method.
*
* @param bean Bean Object
* @param beanName Bean Name
* @return Bean Object
* @see BeanPostProcessor#postProcessAfterInitialization(Object, String)
*/
protected T doPostProcessAfterInitialization(T bean, String beanName) throws BeansException {
processAfterInitialization(bean, beanName);
return bean;
}
/**
* Process {@link T Bean} with name without return value before initialization,
* <p>
* This method will be invoked by BeanPostProcessor#postProcessBeforeInitialization(Object, String)
*
* @param bean Bean Object
* @param beanName Bean Name
* @throws BeansException in case of errors
*/
protected void processBeforeInitialization(T bean, String beanName) throws BeansException {
}
/**
* Process {@link T Bean} with name without return value after initialization,
* <p>
* This method will be invoked by BeanPostProcessor#postProcessAfterInitialization(Object, String)
*
* @param bean Bean Object
* @param beanName Bean Name
* @throws BeansException in case of errors
*/
protected void processAfterInitialization(T bean, String beanName) throws BeansException {
}
}

View File

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class LazyTargetInvocationHandler implements InvocationHandler {
private final LazyTargetSource lazyTargetSource;
private volatile Object target;
public LazyTargetInvocationHandler(LazyTargetSource lazyTargetSource) {
this.lazyTargetSource = lazyTargetSource;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
if ("toString".equals(methodName)) {
if (target != null) {
return target.toString();
} else {
return this.toString();
}
} else if ("hashCode".equals(methodName)) {
return this.hashCode();
}
} else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
return this.equals(args[0]);
}
if (target == null) {
synchronized (this) {
if (target == null) {
target = lazyTargetSource.getTarget();
}
}
}
if (method.getDeclaringClass().isInstance(target)) {
try {
return method.invoke(target, args);
} catch (InvocationTargetException exception) {
Throwable targetException = exception.getTargetException();
if (targetException != null) {
throw targetException;
}
}
}
throw new IllegalStateException("The proxied interface [" + method.getDeclaringClass() +
"] contains a method [" + method + "] that is not implemented by the proxy class [" + target.getClass() + "]");
}
}

View File

@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
public interface LazyTargetSource {
Object getTarget() throws Exception;
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
/**
* Object Utilities
*/
@SuppressWarnings("unchecked")
public abstract class ObjectUtils {
/**
* Empty String array
*/
public static final String[] EMPTY_STRING_ARRAY = {};
/**
* Convert from variable arguments to array
*
* @param values variable arguments
* @param <T> The class
* @return array
*/
public static <T> T[] of(T... values) {
return values;
}
}

View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring.util;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import static java.util.Collections.unmodifiableMap;
/**
* {@link PropertySources} Utilities
*
* @see PropertySources
*/
public abstract class PropertySourcesUtils {
/**
* Get Sub {@link Properties}
*
* @param propertySources {@link PropertySource} Iterable
* @param prefix the prefix of property name
* @return Map
* @see Properties
*/
public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {
MutablePropertySources mutablePropertySources = new MutablePropertySources();
for (PropertySource<?> source : propertySources) {
mutablePropertySources.addLast(source);
}
return getSubProperties(mutablePropertySources, prefix);
}
/**
* Get Sub {@link Properties}
*
* @param environment {@link ConfigurableEnvironment}
* @param prefix the prefix of property name
* @return Map
* @see Properties
*/
public static Map<String, Object> getSubProperties(ConfigurableEnvironment environment, String prefix) {
return getSubProperties(environment.getPropertySources(), environment, prefix);
}
/**
* Normalize the prefix
*
* @param prefix the prefix
* @return the prefix
*/
public static String normalizePrefix(String prefix) {
return prefix.endsWith(".") ? prefix : prefix + ".";
}
/**
* Get prefixed {@link Properties}
*
* @param propertySources {@link PropertySources}
* @param prefix the prefix of property name
* @return Map
* @see Properties
*/
public static Map<String, Object> getSubProperties(PropertySources propertySources, String prefix) {
return getSubProperties(propertySources, new PropertySourcesPropertyResolver(propertySources), prefix);
}
/**
* Get prefixed {@link Properties}
*
* @param propertySources {@link PropertySources}
* @param propertyResolver {@link PropertyResolver} to resolve the placeholder if present
* @param prefix the prefix of property name
* @return Map
* @see Properties
*/
public static Map<String, Object> getSubProperties(PropertySources propertySources, PropertyResolver propertyResolver, String prefix) {
Map<String, Object> subProperties = new LinkedHashMap<String, Object>();
String normalizedPrefix = normalizePrefix(prefix);
Iterator<PropertySource<?>> iterator = propertySources.iterator();
while (iterator.hasNext()) {
PropertySource<?> source = iterator.next();
for (String name : getPropertyNames(source)) {
if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
String subName = name.substring(normalizedPrefix.length());
if (!subProperties.containsKey(subName)) { // take first one
Object value = source.getProperty(name);
if (value instanceof String) {
// Resolve placeholder
value = propertyResolver.resolvePlaceholders((String) value);
}
subProperties.put(subName, value);
}
}
}
}
return unmodifiableMap(subProperties);
}
/**
* Get the property names as the array from the specified {@link PropertySource} instance.
*
* @param propertySource {@link PropertySource} instance
* @return non-null
*/
public static String[] getPropertyNames(PropertySource propertySource) {
String[] propertyNames = propertySource instanceof EnumerablePropertySource ?
((EnumerablePropertySource) propertySource).getPropertyNames() : null;
if (propertyNames == null) {
propertyNames = ObjectUtils.EMPTY_STRING_ARRAY;
}
return propertyNames;
}
}

View File

@ -1098,6 +1098,12 @@
<xsd:documentation><![CDATA[ Deprecated. No longer use. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="enable-rpc" type="xsd:boolean" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[ Enable record rpc metrics. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="tracingType">

View File

@ -41,6 +41,7 @@ import org.springframework.context.annotation.PropertySource;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -97,6 +98,63 @@ class JavaConfigReferenceBeanTest {
}
}
@Test
void testLazyProxy1() {
AnnotationConfigApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(CommonConfig.class,
LazyProxyConfiguration1.class);
HelloService helloServiceClient = context.getBean("helloServiceClient", HelloService.class);
Assertions.assertNotNull(helloServiceClient);
Assertions.assertInstanceOf(HelloService.class, helloServiceClient);
Class<? extends HelloService> clientClass = helloServiceClient.getClass();
Assertions.assertFalse(Modifier.isFinal(clientClass.getModifiers()));
Assertions.assertEquals("Hello, dubbo", helloServiceClient.sayHello("dubbo"));
} finally {
if (context != null) {
context.close();
}
}
}
@Test
void testLazyProxy2() {
AnnotationConfigApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(CommonConfig.class,
LazyProxyConfiguration2.class);
HelloService helloServiceClient = context.getBean("helloServiceClient", HelloService.class);
Assertions.assertNotNull(helloServiceClient);
Assertions.assertInstanceOf(HelloService.class, helloServiceClient);
Class<? extends HelloService> clientClass = helloServiceClient.getClass();
Assertions.assertFalse(Modifier.isFinal(clientClass.getModifiers()));
Assertions.assertEquals("Hello, dubbo", helloServiceClient.sayHello("dubbo"));
} finally {
if (context != null) {
context.close();
}
}
}
@Test
void testLazyProxy3() {
AnnotationConfigApplicationContext context = null;
try {
context = new AnnotationConfigApplicationContext(CommonConfig.class,
LazyProxyConfiguration3.class);
HelloService helloServiceClient = context.getBean("helloServiceClient", HelloService.class);
Assertions.assertNotNull(helloServiceClient);
Assertions.assertInstanceOf(HelloService.class, helloServiceClient);
Class<? extends HelloService> clientClass = helloServiceClient.getClass();
Assertions.assertTrue(Modifier.isFinal(clientClass.getModifiers()));
Assertions.assertEquals("Hello, dubbo", helloServiceClient.sayHello("dubbo"));
} finally {
if (context != null) {
context.close();
}
}
}
private String getStackTrace(Throwable ex) {
StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
@ -106,7 +164,7 @@ class JavaConfigReferenceBeanTest {
@Test
void testAnnotationBean() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CommonConfig.class,
AnnotationBeanConfiguration.class);
AnnotationBeanConfiguration.class);
try {
Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);
@ -165,7 +223,7 @@ class JavaConfigReferenceBeanTest {
@Test
void testReferenceBean() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CommonConfig.class,
ReferenceBeanConfiguration.class);
ReferenceBeanConfiguration.class);
try {
Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);
@ -316,6 +374,42 @@ class JavaConfigReferenceBeanTest {
}
@Configuration
public static class LazyProxyConfiguration1 {
@DubboReference(group = "${myapp.group}")
private HelloService helloService;
@Bean(name = "helloServiceClient")
public HelloService helloService() {
return helloService;
}
}
@Configuration
public static class LazyProxyConfiguration2 {
@DubboReference(group = "${myapp.group}", proxy = "javassist")
private HelloService helloService;
@Bean(name = "helloServiceClient")
public HelloService helloService() {
return helloService;
}
}
@Configuration
public static class LazyProxyConfiguration3 {
@DubboReference(group = "${myapp.group}", proxy = "jdk")
private HelloService helloService;
@Bean(name = "helloServiceClient")
public HelloService helloService() {
return helloService;
}
}
@Configuration
public static class AnnotationAtFieldConfiguration {
@ -353,7 +447,7 @@ class JavaConfigReferenceBeanTest {
}
@Bean
@Reference(group = "${myapp.group}", interfaceName = "org.apache.dubbo.config.spring.api.LocalMissClass")
@DubboReference(group = "${myapp.group}", interfaceName = "org.apache.dubbo.config.spring.api.LocalMissClass", scope = "local")
public ReferenceBean<GenericService> genericServiceWithoutInterface() {
return new ReferenceBean();
}
@ -365,8 +459,8 @@ class JavaConfigReferenceBeanTest {
@Bean
public ReferenceBean<HelloService> helloService() {
return new ReferenceBeanBuilder()
.setGroup("${myapp.group}")
.build();
.setGroup("${myapp.group}")
.build();
}
@Bean
@ -394,9 +488,9 @@ class JavaConfigReferenceBeanTest {
@Bean
public ReferenceBean helloService() {
return new ReferenceBeanBuilder()
.setGroup("${myapp.group}")
.setInterface(HelloService.class)
.build();
.setGroup("${myapp.group}")
.setInterface(HelloService.class)
.build();
}
}
@ -435,4 +529,4 @@ class JavaConfigReferenceBeanTest {
}
}
}
}

View File

@ -99,11 +99,12 @@ class DubboNamespaceHandlerTest {
private void testProviderXml(ApplicationContext context) {
String appName = "demo-provider";
String configId = ApplicationConfig.class.getName() + "#" + appName + "#0";
Map<String, ApplicationConfig> applicationConfigMap = context.getBeansOfType(ApplicationConfig.class);
ApplicationConfig providerAppConfig = context.getBean(appName, ApplicationConfig.class);
ApplicationConfig providerAppConfig = context.getBean(configId, ApplicationConfig.class);
assertNotNull(providerAppConfig);
assertEquals(appName, providerAppConfig.getName());
assertEquals(appName, providerAppConfig.getId());
// assertEquals(configId, providerAppConfig.getId());
ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);
assertThat(protocolConfig, not(nullValue()));

View File

@ -94,7 +94,7 @@
<spring_version>5.3.25</spring_version>
<spring_security_version>5.8.3</spring_security_version>
<javassist_version>3.29.2-GA</javassist_version>
<bytebuddy.version>1.14.4</bytebuddy.version>
<bytebuddy.version>1.14.5</bytebuddy.version>
<netty_version>3.2.10.Final</netty_version>
<netty4_version>4.1.92.Final</netty4_version>
<mina_version>2.2.1</mina_version>
@ -102,7 +102,7 @@
<httpclient_version>4.5.14</httpclient_version>
<httpcore_version>4.4.16</httpcore_version>
<fastjson_version>1.2.83</fastjson_version>
<fastjson2_version>2.0.32</fastjson2_version>
<fastjson2_version>2.0.33</fastjson2_version>
<zookeeper_version>3.4.14</zookeeper_version>
<curator_version>4.3.0</curator_version>
<curator_test_version>2.12.0</curator_test_version>
@ -114,7 +114,7 @@
<cxf_version>3.5.5</cxf_version>
<thrift_version>0.18.1</thrift_version>
<hessian_version>4.0.66</hessian_version>
<protobuf-java_version>3.23.1</protobuf-java_version>
<protobuf-java_version>3.23.2</protobuf-java_version>
<javax_annotation-api_version>1.3.2</javax_annotation-api_version>
<servlet_version>3.1.0</servlet_version>
<jetty_version>9.4.51.v20230217</jetty_version>
@ -148,7 +148,7 @@
<codehaus-jackson_version>1.9.13</codehaus-jackson_version>
<tomcat_embed_version>8.5.87</tomcat_embed_version>
<jetcd_version>0.7.5</jetcd_version>
<nacos_version>2.2.2</nacos_version>
<nacos_version>2.2.3</nacos_version>
<grpc.version>1.55.1</grpc.version>
<grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>
<jprotoc_version>1.2.2</jprotoc_version>
@ -174,17 +174,17 @@
<jaxb_version>2.2.7</jaxb_version>
<activation_version>1.2.0</activation_version>
<test_container_version>1.18.1</test_container_version>
<test_container_version>1.18.3</test_container_version>
<etcd_launcher_version>0.7.5</etcd_launcher_version>
<hessian_lite_version>3.2.13</hessian_lite_version>
<swagger_version>1.6.11</swagger_version>
<snappy_java_version>1.1.9.1</snappy_java_version>
<snappy_java_version>1.1.10.0</snappy_java_version>
<bouncycastle-bcprov_version>1.70</bouncycastle-bcprov_version>
<metrics_version>2.0.6</metrics_version>
<sofa_registry_version>5.4.3</sofa_registry_version>
<gson_version>2.10.1</gson_version>
<jackson_version>2.15.1</jackson_version>
<jackson_version>2.15.2</jackson_version>
<jsonrpc_version>1.6</jsonrpc_version>
<mortbay_jetty_version>6.1.26</mortbay_jetty_version>
<portlet_version>2.0</portlet_version>

View File

@ -94,7 +94,7 @@ public class RtStatComposite extends AbstractMetricsExport {
public void calcMethodKeyRt(Invocation invocation, String registryOpType, Long responseTime) {
for (LongContainer container : rtStats.stream().filter(longContainer -> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, invocation.getServiceName() + "_" + invocation.getMethodName(), container.getInitFunc());
Number current = (Number) ConcurrentHashMapUtils.computeIfAbsent(container, invocation.getTargetServiceUniqueName() + "_" + invocation.getMethodName(), container.getInitFunc());
container.getConsumerFunc().accept(responseTime, current);
}
}

View File

@ -27,7 +27,7 @@ public enum MetricsKey {
METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Total Succeed Requests"),
METRIC_REQUEST_BUSINESS_FAILED("dubbo.%s.requests.business.failed.total", "Total Failed Business Requests"),
METRIC_REQUESTS_PROCESSING("dubbo.%s.requests.processing", "Processing Requests"),
METRIC_REQUESTS_PROCESSING("dubbo.%s.requests.processing.total", "Processing Requests"),
METRIC_REQUESTS_TIMEOUT("dubbo.%s.requests.timeout.total", "Total Timeout Failed Requests"),
METRIC_REQUESTS_LIMIT("dubbo.%s.requests.limit.total", "Total Limit Failed Requests"),
METRIC_REQUESTS_FAILED("dubbo.%s.requests.unknown.failed.total", "Total Unknown Failed Requests"),

View File

@ -27,7 +27,8 @@ public class TimeWindowAggregatorTest {
public void testTimeWindowAggregator() {
TimeWindowAggregator aggregator = new TimeWindowAggregator(5, 5);
// 第一个时间窗口时间范围0秒 - 5秒
//First time window, time range: 0 - 5 seconds
aggregator.add(10);
aggregator.add(20);
aggregator.add(30);
@ -39,7 +40,7 @@ public class TimeWindowAggregatorTest {
Assertions.assertEquals(30, entry1.getMax());
Assertions.assertEquals(10, entry1.getMin());
// 第二个时间窗口时间范围5秒 - 10秒
//Second time window, time range: 5 - 10 seconds
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
@ -57,7 +58,9 @@ public class TimeWindowAggregatorTest {
Assertions.assertEquals(35, entry2.getMax());
Assertions.assertEquals(15, entry2.getMin());
// 第三个时间窗口时间范围10秒 - 15秒
//Third time window, time range: 10 - 15 seconds
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {

View File

@ -53,10 +53,16 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
ConfigManager configManager = applicationModel.getApplicationConfigManager();
MetricsConfig config = configManager.getMetrics().orElse(null);
if (config != null && config.getHistogram() != null && Boolean.TRUE.equals(config.getHistogram().getEnabled())) {
if (config == null || config.getHistogram() == null || config.getHistogram().getEnabled() == null || Boolean.TRUE.equals(config.getHistogram().getEnabled())) {
registerListener();
HistogramConfig histogram = config.getHistogram();
HistogramConfig histogram;
if (config == null || config.getHistogram() == null) {
histogram = new HistogramConfig();
} else {
histogram = config.getHistogram();
}
if (!Boolean.TRUE.equals(histogram.getEnabledPercentiles()) && histogram.getBucketsMs() == null) {
histogram.setBucketsMs(DEFAULT_BUCKETS_MS);
}

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.metrics.filter;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.rpc.BaseFilter;
@ -40,20 +41,24 @@ import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
public class MetricsFilter implements Filter, BaseFilter.Listener, ScopeModelAware {
private ApplicationModel applicationModel;
private final static ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(MetricsFilter.class);
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(MetricsFilter.class);
private boolean rpcMetricsEnable;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
this.rpcMetricsEnable = applicationModel.getApplicationConfigManager().getMetrics().map(MetricsConfig::getEnableRpc).orElse(true);
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, invocation);
MetricsEventBus.before(requestEvent, () -> invocation.put(METRIC_FILTER_EVENT, requestEvent));
} catch (Throwable t) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when invoke.", t);
if (rpcMetricsEnable) {
try {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, invocation);
MetricsEventBus.before(requestEvent, () -> invocation.put(METRIC_FILTER_EVENT, requestEvent));
} catch (Throwable t) {
LOGGER.warn(INTERNAL_ERROR, "", "", "Error occurred when invoke.", t);
}
}
return invoker.invoke(invocation);
}
@ -84,6 +89,4 @@ public class MetricsFilter implements Filter, BaseFilter.Listener, ScopeModelAwa
}
}
}

View File

@ -82,7 +82,6 @@ class MetricsFilterTest {
config.setName("MockMetrics");
applicationModel = ApplicationModel.defaultModel();
applicationModel.getApplicationConfigManager().setApplication(config);
invocation = new RpcInvocation();
filter = new MetricsFilter();

View File

@ -27,7 +27,7 @@
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
<protobuf-java.version>3.22.2</protobuf-java.version>
<grpc.version>1.41.0</grpc.version>
<grpc.version>1.55.1</grpc.version>
</properties>
<artifactId>dubbo-security</artifactId>

View File

@ -70,6 +70,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
@ -162,8 +163,8 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
private final Map<String, ServiceConfigurationListener> serviceConfigurationListeners = new ConcurrentHashMap<>();
//To solve the problem of RMI repeated exposure port conflicts, the services that have been exposed are no longer exposed.
//provider url <--> exporter
private final ConcurrentMap<String, ExporterChangeableWrapper<?>> bounds = new ConcurrentHashMap<>();
//provider url <--> registry url <--> exporter
private final Map<String, Map<String, ExporterChangeableWrapper<?>>> bounds = new ConcurrentHashMap<>();
protected Protocol protocol;
protected ProxyFactory proxyFactory;
@ -217,7 +218,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
return map;
}
private void register(Registry registry, URL registeredProviderUrl) {
private static void register(Registry registry, URL registeredProviderUrl) {
ApplicationDeployer deployer = registeredProviderUrl.getOrDefaultApplicationModel().getDeployer();
try {
deployer.increaseServiceRefreshCount();
@ -272,6 +273,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
exporter.setNotifyListener(overrideSubscribeListener);
exporter.setRegistered(register);
ApplicationModel applicationModel = getApplicationModel(providerUrl.getScopeModel());
if (applicationModel.getModelEnvironment().getConfiguration().convert(Boolean.class, ENABLE_26X_CONFIGURATION_LISTEN, true)) {
@ -308,12 +310,14 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
@SuppressWarnings("unchecked")
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
String key = getCacheKey(originInvoker);
String providerUrlKey = getProviderUrlKey(originInvoker);
String registryUrlKey = getRegistryUrlKey(originInvoker);
return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
});
return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(providerUrlKey, _k -> new ConcurrentHashMap<>())
.computeIfAbsent(registryUrlKey, s ->{
Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
});
}
public <T> void reExport(Exporter<T> exporter, URL newInvokerUrl) {
@ -333,8 +337,18 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
*/
@SuppressWarnings("unchecked")
public <T> void reExport(final Invoker<T> originInvoker, URL newInvokerUrl) {
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
String providerUrlKey = getProviderUrlKey(originInvoker);
String registryUrlKey = getRegistryUrlKey(originInvoker);
Map<String, ExporterChangeableWrapper<?>> registryMap = bounds.get(providerUrlKey);
if (registryMap == null) {
logger.warn(INTERNAL_ERROR, "error state, exporterMap can not be null", "", "error state, exporterMap can not be null", new IllegalStateException("error state, exporterMap can not be null"));
return;
}
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) registryMap.get(registryUrlKey);
if (exporter == null) {
logger.warn(INTERNAL_ERROR, "error state, exporterMap can not be null", "", "error state, exporterMap can not be null", new IllegalStateException("error state, exporterMap can not be null"));
return;
}
URL registeredUrl = exporter.getRegisterUrl();
URL registryUrl = getRegistryUrl(originInvoker);
@ -369,7 +383,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
private <T> void doReExport(final Invoker<T> originInvoker, ExporterChangeableWrapper<T> exporter,
URL registryUrl, URL oldProviderUrl, URL newProviderUrl) {
if (getProviderUrl(originInvoker).getParameter(REGISTER_KEY, true)) {
if (exporter.isRegistered()) {
Registry registry;
try {
registry = getRegistry(getRegistryUrl(originInvoker));
@ -480,12 +494,18 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
* @param originInvoker
* @return
*/
private String getCacheKey(final Invoker<?> originInvoker) {
private String getProviderUrlKey(final Invoker<?> originInvoker) {
URL providerUrl = getProviderUrl(originInvoker);
String key = providerUrl.removeParameters(DYNAMIC_KEY, ENABLED_KEY).toFullString();
return key;
}
private String getRegistryUrlKey(final Invoker<?> originInvoker) {
URL registryUrl = getRegistryUrl(originInvoker);
String key = registryUrl.removeParameters(DYNAMIC_KEY, ENABLED_KEY).toFullString();
return key;
}
@Override
@SuppressWarnings("unchecked")
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
@ -653,7 +673,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
}
}
List<Exporter<?>> exporters = new ArrayList<>(bounds.values());
List<Exporter<?>> exporters = bounds.values().stream().flatMap(e -> e.values().stream()).collect(Collectors.toList());
for (Exporter<?> exporter : exporters) {
exporter.unexport();
}
@ -712,6 +732,11 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
exporter.unexport();
}
@Override
public void register() {
exporter.register();
}
@Override
public void unregister() {
exporter.unregister();
@ -777,8 +802,14 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
}
//The origin invoker
URL originUrl = RegistryProtocol.this.getProviderUrl(invoker);
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper<?> exporter = bounds.get(key);
String providerUrlKey = getProviderUrlKey(originInvoker);
String registryUrlKey = getRegistryUrlKey(originInvoker);
Map<String, ExporterChangeableWrapper<?>> exporterMap = bounds.get(providerUrlKey);
if (exporterMap == null) {
logger.warn(INTERNAL_ERROR, "error state, exporterMap can not be null", "", "error state, exporterMap can not be null", new IllegalStateException("error state, exporterMap can not be null"));
return;
}
ExporterChangeableWrapper<?> exporter = exporterMap.get(registryUrlKey);
if (exporter == null) {
logger.warn(INTERNAL_ERROR, "unknown error in registry module", "", "error state, exporter should not be null", new IllegalStateException("error state, exporter should not be null"));
return;
@ -920,7 +951,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
private URL registerUrl;
private NotifyListener notifyListener;
private final AtomicBoolean unregistered = new AtomicBoolean(false);
private final AtomicBoolean registered = new AtomicBoolean(false);
public ExporterChangeableWrapper(Exporter<T> exporter, Invoker<T> originInvoker) {
this.exporter = exporter;
@ -943,9 +974,28 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
this.exporter = exporter;
}
@Override
public void register() {
if (registered.compareAndSet(false, true)) {
URL registryUrl = getRegistryUrl(originInvoker);
Registry registry = getRegistry(registryUrl);
RegistryProtocol.register(registry, getRegisterUrl());
ProviderModel providerModel = frameworkModel.getServiceRepository()
.lookupExportedService(getRegisterUrl().getServiceKey());
List<ProviderModel.RegisterStatedURL> statedUrls = providerModel.getStatedUrl();
statedUrls.stream()
.filter(u -> u.getRegistryUrl().equals(registryUrl)
&& u.getProviderUrl().getProtocol().equals(getRegisterUrl().getProtocol()))
.forEach(u -> u.setRegistered(true));
logger.info("Registered dubbo service " + getRegisterUrl().getServiceKey() + " url " + getRegisterUrl() + " to registry " + registryUrl);
}
}
@Override
public synchronized void unregister() {
if (unregistered.compareAndSet(false, true)) {
if (registered.compareAndSet(true, false)) {
Registry registry = RegistryProtocol.this.getRegistry(getRegistryUrl(originInvoker));
try {
registry.unregister(registerUrl);
@ -987,13 +1037,25 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
@Override
public synchronized void unexport() {
String key = getCacheKey(this.originInvoker);
bounds.remove(key);
String providerUrlKey = getProviderUrlKey(this.originInvoker);
String registryUrlKey = getRegistryUrlKey(this.originInvoker);
Map<String, ExporterChangeableWrapper<?>> exporterMap = bounds.remove(providerUrlKey);
if (exporterMap != null) {
exporterMap.remove(registryUrlKey);
}
unregister();
doUnExport();
}
public void setRegistered(boolean registered) {
this.registered.set(registered);
}
public boolean isRegistered() {
return registered.get();
}
private void doUnExport() {
try {
exporter.unexport();

View File

@ -28,6 +28,11 @@ public class Response {
*/
public static final byte OK = 20;
/**
* serialization error
*/
public static final byte SERIALIZATION_ERROR = 25;
/**
* client side timeout.
*/

View File

@ -360,6 +360,7 @@ public class ExchangeCodec extends TelnetCodec {
logger.warn(TRANSPORT_EXCEED_PAYLOAD_LIMIT, "", "", t.getMessage(), t);
try {
r.setErrorMessage(t.getMessage());
r.setStatus(Response.SERIALIZATION_ERROR);
channel.send(r);
return;
} catch (RemotingException e) {

View File

@ -26,6 +26,7 @@ import org.apache.dubbo.common.timer.TimerTask;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.common.serialize.SerializationException;
import org.apache.dubbo.remoting.TimeoutException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
@ -215,7 +216,9 @@ public class DefaultFuture extends CompletableFuture<Object> {
this.complete(res.getResult());
} else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
this.completeExceptionally(new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()));
} else {
} else if(res.getStatus() == Response.SERIALIZATION_ERROR){
this.completeExceptionally(new SerializationException(res.getErrorMessage()));
}else {
this.completeExceptionally(new RemotingException(channel, res.getErrorMessage()));
}
}

View File

@ -282,7 +282,11 @@ final class DeprecatedExchangeCodec extends DeprecatedTelnetCodec implements Cod
logger.warn(TRANSPORT_FAILED_RESPONSE, "", "", "Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t);
Response r = new Response(res.getId(), res.getVersion());
r.setStatus(Response.BAD_RESPONSE);
if (t instanceof IOException) {
r.setStatus(Response.SERIALIZATION_ERROR);
} else {
r.setStatus(Response.BAD_RESPONSE);
}
r.setErrorMessage("Failed to send response: " + res + ", cause: " + StringUtils.toString(t));
channel.send(r);

View File

@ -512,7 +512,7 @@ class ExchangeCodecTest extends TelnetCodecTest {
codec.encode(channel, encodeBuffer, response);
Assertions.assertTrue(channel.getReceivedMessage() instanceof Response);
Response receiveMessage = (Response) channel.getReceivedMessage();
Assertions.assertEquals(Response.BAD_RESPONSE, receiveMessage.getStatus());
Assertions.assertEquals(Response.SERIALIZATION_ERROR, receiveMessage.getStatus());
Assertions.assertTrue(receiveMessage.getErrorMessage().contains("Data length too large: "));
}
}

View File

@ -17,7 +17,10 @@
package org.apache.dubbo.remoting.transport.netty4;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.EncoderException;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
@ -33,9 +36,6 @@ import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.AbstractChannel;
import org.apache.dubbo.remoting.transport.codec.CodecAdapter;
import org.apache.dubbo.remoting.utils.PayloadDropper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import org.apache.dubbo.rpc.model.FrameworkModel;
import java.net.InetSocketAddress;
@ -344,7 +344,11 @@ final class NettyChannel extends AbstractChannel {
*/
private static Response buildErrorResponse(Request request, Throwable t) {
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.BAD_REQUEST);
if(t instanceof EncoderException){
response.setStatus(Response.SERIALIZATION_ERROR);
}else{
response.setStatus(Response.BAD_REQUEST);
}
response.setErrorMessage(StringUtils.toString(t));
return response;
}

View File

@ -41,6 +41,11 @@ public interface Exporter<T> {
*/
void unexport();
/**
* register to registry
*/
void register();
/**
* unregister from registry
*/

View File

@ -62,6 +62,11 @@ public class ListenerExporterWrapper<T> implements Exporter<T> {
}
}
@Override
public void register() {
exporter.register();
}
@Override
public void unregister() {
exporter.unregister();

View File

@ -60,6 +60,11 @@ public abstract class AbstractExporter<T> implements Exporter<T> {
afterUnExport();
}
@Override
public void register() {
}
@Override
public void unregister() {

View File

@ -28,6 +28,7 @@ import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.common.serialize.SerializationException;
import org.apache.dubbo.remoting.TimeoutException;
import org.apache.dubbo.remoting.utils.UrlUtils;
import org.apache.dubbo.rpc.AsyncRpcResult;
@ -112,7 +113,7 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
}
this.type = type;
this.url = url;
this.attachment = attachment == null
? null
: Collections.unmodifiableMap(attachment);
@ -293,6 +294,9 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else if (rootCause instanceof RemotingException) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else if (rootCause instanceof SerializationException) {
throw new RpcException(RpcException.SERIALIZATION_EXCEPTION, "Invoke remote method failed cause by serialization error. remote method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else {
throw new RpcException(RpcException.UNKNOWN_EXCEPTION, "Fail to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}

View File

@ -17,8 +17,8 @@
package org.apache.dubbo.rpc.support;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.ToStringUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
@ -248,7 +248,7 @@ public final class AccessLogData {
Object[] args = get(ARGUMENTS) != null ? (Object[]) get(ARGUMENTS) : null;
if (args != null && args.length > 0) {
sn.append(JsonUtils.toJson(args));
sn.append(ToStringUtils.printToString(args));
}
return sn.toString();

Some files were not shown because too many files have changed in this diff Show More