Merge branch 'apache-3.3' into 3.3.0-beta.1-release

# Conflicts:
#	dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
#	dubbo-plugin/dubbo-native/pom.xml
#	dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/PortUnificationServerTest.java
#	dubbo-test/dubbo-test-modules/src/test/java/org/apache/dubbo/dependency/FileTest.java
This commit is contained in:
Albumen Kevin 2023-09-26 16:37:37 +08:00
commit a0e7ebc735
172 changed files with 1976 additions and 1065 deletions

View File

@ -21,7 +21,6 @@ dubbo-auth
dubbo-apache-release
dubbo-all-shaded
dubbo-bom
dubbo-build-tools
dubbo-cluster
dubbo-common
dubbo-compatible
@ -66,6 +65,7 @@ dubbo-metrics-prometheus
dubbo-metrics-registry
dubbo-metrics-config-center
dubbo-metrics-netty
dubbo-metrics-event
dubbo-monitor
dubbo-monitor-api
dubbo-monitor-common
@ -141,3 +141,4 @@ dubbo-plugin-context
dubbo-plugin-classloader-filter
dubbo-plugin-proxy-bytebuddy
dubbo-plugin-qos-trace
dubbo-plugin-loom

View File

@ -96,9 +96,9 @@ header:
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java'
- 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
- 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java'
- 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java'
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java'
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboAbstractTDigest.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/FormattingTuple.java'

View File

@ -101,7 +101,7 @@ check 2.7.5 milestone for details.
* In consumer side the app cannot catch the exception from provider that is configured serialization="kryo". #4238
* fix StringUtils#isBlank #4725
* when the interfaceName of the Reference annotation has duplicated,the exception is puzzled #4160
* when anonymity bean is defined in spirng contextdubbo throw npe #
* when anonymity bean is defined in spring contextdubbo throw npe #
* add Thread ContextClassLoader #4712
* Fix judgment ipv4 address #4729
* The compilation of static methods should be excluded when generating the proxy. #4647

View File

@ -224,10 +224,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
logger.warn(CLUSTER_NO_VALID_PROVIDER, "provider server or registry center crashed", "",
"No provider available after connectivity filter for the service " + getConsumerUrl().getServiceKey()
+ " All validInvokers' size: " + validInvokers.size()
+ " All routed invokers' size: " + routedResult.size()
+ " All invokers' size: " + invokers.size()
+ " from registry " + getUrl().getAddress()
+ " from registry " + this
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ".");
}
@ -350,6 +348,7 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
if (!invokersToReconnect.isEmpty()) {
checkConnectivity();
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
}, reconnectTaskPeriod, TimeUnit.MILLISECONDS);
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));

View File

@ -27,11 +27,12 @@ import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.SingleRouterChain;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
/**
@ -130,6 +131,9 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
@Override
protected Map<String, String> getDirectoryMeta() {
return Collections.singletonMap(REGISTRY_KEY, "static");
Map<String, String> metas = new HashMap<>();
metas.put(REGISTRY_KEY, "static");
metas.put(REGISTER_MODE_KEY, "static");
return metas;
}
}

View File

@ -60,7 +60,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;

View File

@ -21,10 +21,10 @@ import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.filter.DemoService;
import org.apache.dubbo.rpc.RpcException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -56,6 +56,7 @@ class FailSafeClusterInvokerTest {
@BeforeEach
public void setUp() throws Exception {
RpcContext.removeServiceContext();
dic = mock(Directory.class);

View File

@ -24,10 +24,10 @@ import org.apache.dubbo.common.utils.LogUtil;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.log4j.Level;
import org.junit.jupiter.api.AfterEach;
@ -38,7 +38,6 @@ import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.function.Executable;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -47,7 +46,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -72,6 +71,7 @@ class FailbackClusterInvokerTest {
@BeforeEach
public void setUp() throws Exception {
RpcContext.removeServiceContext();
dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url);

View File

@ -128,6 +128,8 @@ public interface CommonConstants {
String THREAD_POOL_EXHAUSTED_LISTENERS_KEY = "thread-pool-exhausted-listeners";
String JSON_CHECK_LEVEL_KEY = "jsonCheckLevel";
String THREADS_KEY = "threads";
String QUEUES_KEY = "queues";
@ -643,7 +645,7 @@ public interface CommonConstants {
String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer";
String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest";
String DUBBO_MANUAL_REGISTER_KEY = "dubbo.application.manual-register";

View File

@ -40,17 +40,19 @@ public interface MetricsConstants {
String TAG_VERSION_KEY = "version";
String TAG_APPLICATION_VERSION_KEY = "application.version";
String TAG_KEY_KEY = "key";
String TAG_CONFIG_CENTER = "config.center";
String TAG_CHANGE_TYPE = "change.type";
String TAG_ERROR_CODE = "error";
String ENABLE_JVM_METRICS_KEY = "enable.jvm";
String ENABLE_COLLECTOR_SYNC_KEY = "enable.collector.sync";
String AGGREGATION_COLLECTOR_KEY = "aggregation";
String AGGREGATION_ENABLED_KEY = "aggregation.enabled";

View File

@ -24,6 +24,8 @@ public interface QosConstants {
String QOS_ENABLE = "qos.enable";
String QOS_CHECK = "qos.check";
String QOS_HOST = "qos.host";
String QOS_PORT = "qos.port";

View File

@ -17,8 +17,23 @@
package org.apache.dubbo.common.logger;
import org.apache.dubbo.common.constants.LoggerCodeConstants;
/**
* Logger interface with the ability of displaying solution of different types of error.
*
* <p>
* This logger will log a message like this:
*
* <blockquote><pre>
* ... (original logging message) This may be caused by (... cause),
* go to https://dubbo.apache.org/faq/[Cat]/[X] to find instructions. (... extendedInformation)
* </pre></blockquote>
*
* Where "[Cat]/[X]" is the error code ("code" in arguments). The link is clickable, leading user to
* the "Error code and its corresponding solutions" page.
*
* @see LoggerCodeConstants Detailed Format of Error Code and Error Code Constants
*/
public interface ErrorTypeAwareLogger extends Logger {

View File

@ -145,6 +145,10 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
if (!guard.tryAcquire()) {
return;
}
// To avoid multiple dump, check again
if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) {
return;
}
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(() -> {
@ -169,9 +173,9 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
} catch (Exception t) {
logger.error(COMMON_UNEXPECTED_CREATE_DUMP, "", "", "dump jStack error", t);
} finally {
lastPrintTime = System.currentTimeMillis();
guard.release();
}
lastPrintTime = System.currentTimeMillis();
});
//must shutdown thread pool ,if not will lead to OOM
pool.shutdown();

View File

@ -103,6 +103,11 @@ public abstract class AbstractConfig implements Serializable {
protected final AtomicBoolean refreshed = new AtomicBoolean(false);
/**
* Indicate that if current config needs to being refreshed, default is true
*/
protected transient volatile boolean needRefresh = true;
/**
* Is default config or not
*/
@ -679,16 +684,18 @@ public abstract class AbstractConfig implements Serializable {
* Dubbo config property override
*/
public void refresh() {
try {
// check and init before do refresh
preProcessRefresh();
refreshWithPrefixes(getPrefixes(), getConfigMode());
} catch (Exception e) {
logger.error(COMMON_FAILED_OVERRIDE_FIELD, "", "", "Failed to override field value of config bean: " + this, e);
throw new IllegalStateException("Failed to override field value of config bean: " + this, e);
}
if (needRefresh) {
try {
// check and init before do refresh
preProcessRefresh();
refreshWithPrefixes(getPrefixes(), getConfigMode());
} catch (Exception e) {
logger.error(COMMON_FAILED_OVERRIDE_FIELD, "", "", "Failed to override field value of config bean: " + this, e);
throw new IllegalStateException("Failed to override field value of config bean: " + this, e);
}
postProcessRefresh();
postProcessRefresh();
}
refreshed.set(true);
}
@ -949,6 +956,17 @@ public abstract class AbstractConfig implements Serializable {
this.isDefault = isDefault;
}
@Transient
@Parameter(excluded = true, attribute = false)
public boolean isNeedRefresh() {
return needRefresh;
}
@Transient
public void setNeedRefresh(boolean needRefresh) {
this.needRefresh = needRefresh;
}
@Override
public String toString() {
try {

View File

@ -60,6 +60,7 @@ import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_W
import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_ALLOW_COMMANDS;
import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL;
import static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE;
import static org.apache.dubbo.common.constants.QosConstants.QOS_CHECK;
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE_COMPATIBLE;
import static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;
@ -151,6 +152,11 @@ public class ApplicationConfig extends AbstractConfig {
*/
private Boolean qosEnable;
/**
* Whether qos should start success or not, will check qosEnable first
*/
private Boolean qosCheck;
/**
* The qos host to listen
*/
@ -448,6 +454,15 @@ public class ApplicationConfig extends AbstractConfig {
this.qosEnable = qosEnable;
}
@Parameter(key = QOS_CHECK)
public Boolean getQosCheck() {
return qosCheck;
}
public void setQosCheck(Boolean qosCheck) {
this.qosCheck = qosCheck;
}
@Parameter(key = QOS_HOST)
public String getQosHost() {
return qosHost;

View File

@ -66,6 +66,16 @@ public class MetricsConfig extends AbstractConfig {
*/
private Boolean enableNetty;
/**
* Enable metrics init.
*/
private Boolean enableMetricsInit;
/**
* Enable collector sync.
*/
private Boolean enableCollectorSync;
/**
* @deprecated After metrics config is refactored.
* This parameter should no longer use and will be deleted in the future.
@ -99,6 +109,12 @@ public class MetricsConfig extends AbstractConfig {
private Boolean enableRpc;
/**
* The level of the metrics, the value can be "SERVICE", "METHOD", default is method.
*/
private String rpcLevel;
public MetricsConfig() {
}
@ -129,6 +145,14 @@ public class MetricsConfig extends AbstractConfig {
return enableJvm;
}
public String getRpcLevel() {
return rpcLevel;
}
public void setRpcLevel(String rpcLevel) {
this.rpcLevel = rpcLevel;
}
public void setEnableJvm(Boolean enableJvm) {
this.enableJvm = enableJvm;
}
@ -213,6 +237,22 @@ public class MetricsConfig extends AbstractConfig {
this.enableThreadpool = enableThreadpool;
}
public Boolean getEnableMetricsInit() {
return enableMetricsInit;
}
public void setEnableMetricsInit(Boolean enableMetricsInit) {
this.enableMetricsInit = enableMetricsInit;
}
public Boolean getEnableCollectorSync() {
return enableCollectorSync;
}
public void setEnableCollectorSync(Boolean enableCollectorSync) {
this.enableCollectorSync = enableCollectorSync;
}
public Boolean getUseGlobalRegistry() {
return useGlobalRegistry;
}

View File

@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.JSON_CHECK_LEVEL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREAD_POOL_EXHAUSTED_LISTENERS_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;
@ -229,6 +230,8 @@ public class ProtocolConfig extends AbstractConfig {
*/
private String extProtocol;
private String jsonCheckLevel;
public ProtocolConfig() {
}
@ -331,6 +334,15 @@ public class ProtocolConfig extends AbstractConfig {
this.threadname = threadname;
}
@Parameter(key = JSON_CHECK_LEVEL_KEY)
public String getJsonCheckLevel() {
return jsonCheckLevel;
}
public void setJsonCheckLevel(String jsonCheckLevel) {
this.jsonCheckLevel = jsonCheckLevel;
}
@Parameter(key = THREAD_POOL_EXHAUSTED_LISTENERS_KEY)
public String getThreadPoolExhaustedListeners() {
return threadPoolExhaustedListeners;

View File

@ -83,6 +83,7 @@ java.util.Collections$EmptyList
java.util.Collections$EmptyMap
java.util.Collections$SingletonSet
java.util.Collections$SingletonList
java.util.Collections$SingletonMap
java.util.Collections$UnmodifiableCollection
java.util.Collections$UnmodifiableList
java.util.Collections$UnmodifiableMap

View File

@ -249,7 +249,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.3</version>
<version>1.19.0</version>
<scope>test</scope>
</dependency>

View File

@ -228,8 +228,13 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
}
if (ref == null) {
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
if (getScopeModel().isLifeCycleManagedExternally()) {
// prepare model for reference
getScopeModel().getDeployer().prepare();
} else {
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
}
init(check);
}

View File

@ -38,11 +38,15 @@ import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
import org.apache.dubbo.config.support.Parameter;
import org.apache.dubbo.config.utils.ConfigValidationUtils;
import org.apache.dubbo.metadata.ServiceNameMapping;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.MetricsInitEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.registry.client.metadata.MetadataUtils;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.ServerService;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
import org.apache.dubbo.rpc.model.ModuleModel;
@ -61,6 +65,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -294,8 +299,13 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
return;
}
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
if (getScopeModel().isLifeCycleManagedExternally()) {
// prepare model for reference
getScopeModel().getDeployer().prepare();
} else {
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
}
synchronized (this) {
if (this.exported) {
@ -558,6 +568,17 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
registerType = RegisterTypeEnum.NEVER_REGISTER;
}
exportUrl(url, registryURLs, registerType);
initServiceMethodMetrics(url);
}
private void initServiceMethodMetrics(URL url) {
String[] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i -> i.split(",")).orElse(new String[]{});
boolean serviceLevel = MethodMetric.isServiceLevel(application.getApplicationModel());
Arrays.stream(methods).forEach(method -> {
RpcInvocation invocation = new RpcInvocation(url.getServiceKey(), url.getServiceModel(), method, interfaceName, url.getProtocolServiceKey(), null, null, null, null, null, null);
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(), invocation, serviceLevel));
});
}
private void processServiceExecutor(URL url) {

View File

@ -391,6 +391,7 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
collector.setCollectEnabled(true);
collector.collectApplication();
collector.setThreadpoolCollectEnabled(Optional.ofNullable(metricsConfig.getEnableThreadpool()).orElse(true));
collector.setMetricsInitEnabled(Optional.ofNullable(metricsConfig.getEnableMetricsInit()).orElse(true));
MetricsReporterFactory metricsReporterFactory = getExtensionLoader(MetricsReporterFactory.class).getAdaptiveExtension();
MetricsReporter metricsReporter = null;
try {

View File

@ -27,7 +27,7 @@
<description>The spring config module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
<spring-boot.version>2.7.14</spring-boot.version>
<spring-boot.version>2.7.15</spring-boot.version>
<!-- Uncomment spring_version property to check Spring 4.x compatibility -->
<!-- <spring_version>4.3.30.RELEASE</spring_version> -->
</properties>
@ -73,7 +73,7 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.20</version>
<version>1.9.20.1</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -25,6 +25,7 @@ import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.spring.aot.AotWithSpringDetector;
import org.apache.dubbo.config.spring.context.DubboConfigApplicationListener;
import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
@ -54,6 +55,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED;
@ -143,6 +145,9 @@ public class ReferenceBean<T> implements FactoryBean<T>,
//actual reference config
private ReferenceConfig referenceConfig;
// ReferenceBeanManager
private ReferenceBeanManager referenceBeanManager;
// Registration sources of this reference, may be xml file or annotation location
private List<Map<String, Object>> sources = new ArrayList<>();
@ -256,7 +261,7 @@ public class ReferenceBean<T> implements FactoryBean<T>,
}
Assert.notNull(this.interfaceName, "The interface name of ReferenceBean is not initialized");
ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
this.referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
referenceBeanManager.addReference(this);
}
@ -393,7 +398,9 @@ public class ReferenceBean<T> implements FactoryBean<T>,
private Object getCallProxy() throws Exception {
if (referenceConfig == null) {
throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");
referenceBeanManager.initReferenceBean(this);
applicationContext.getBean(DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class).init();
logger.warn(CONFIG_DUBBO_BEAN_INITIALIZER, "", "", "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.

View File

@ -110,10 +110,10 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private ApplicationContext applicationContext;
protected ApplicationContext applicationContext;
private ReferenceBeanManager referenceBeanManager;
private BeanDefinitionRegistry beanDefinitionRegistry;
protected ReferenceBeanManager referenceBeanManager;
protected BeanDefinitionRegistry beanDefinitionRegistry;
/**
* {@link com.alibaba.dubbo.config.annotation.Reference @com.alibaba.dubbo.config.annotation.Reference} has been supported since 2.7.3
@ -211,7 +211,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
* @param beanName
* @param beanDefinition
*/
private void processReferenceAnnotatedBeanDefinition(String beanName, AnnotatedBeanDefinition beanDefinition) {
protected void processReferenceAnnotatedBeanDefinition(String beanName, AnnotatedBeanDefinition beanDefinition) {
MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(beanDefinition);
@ -500,6 +500,9 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean
// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()
GenericBeanDefinition targetDefinition = new GenericBeanDefinition();

View File

@ -238,7 +238,7 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(CONFIG_NO_ANNOTATIONS_FOUND, "No annotations were found on the class", "", "No class annotated by Dubbo @Service was found under package ["
logger.warn(CONFIG_NO_ANNOTATIONS_FOUND, "No annotations were found on the class", "", "No class annotated by Dubbo @DubboService or @Service was found under package ["
+ packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
}
}

View File

@ -16,21 +16,22 @@
*/
package org.apache.dubbo.config.spring.context;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_NOT_FOUND;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_NOT_FOUND;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
/**
* An ApplicationListener to load config beans
*/
@ -53,11 +54,15 @@ public class DubboConfigApplicationListener implements ApplicationListener<Dubbo
@Override
public void onApplicationEvent(DubboConfigInitEvent event) {
if (nullSafeEquals(applicationContext, event.getSource())) {
// It's expected to be notified at org.springframework.context.support.AbstractApplicationContext.registerListeners(),
// before loading non-lazy singleton beans. At this moment, all BeanFactoryPostProcessor have been processed,
if (initialized.compareAndSet(false, true)) {
initDubboConfigBeans();
}
init();
}
}
public void init() {
// It's expected to be notified at org.springframework.context.support.AbstractApplicationContext.registerListeners(),
// before loading non-lazy singleton beans. At this moment, all BeanFactoryPostProcessor have been processed,
if (initialized.compareAndSet(false, true)) {
initDubboConfigBeans();
}
}

View File

@ -43,7 +43,7 @@ public class DubboSpringInitializer {
private static final Logger logger = LoggerFactory.getLogger(DubboSpringInitializer.class);
private static final Map<BeanDefinitionRegistry, DubboSpringInitContext> contextMap = new ConcurrentHashMap<>();
private static final Map<BeanDefinitionRegistry, DubboSpringInitContext> REGISTRY_CONTEXT_MAP = new ConcurrentHashMap<>();
public DubboSpringInitializer() {
}
@ -54,7 +54,7 @@ public class DubboSpringInitializer {
DubboSpringInitContext context = new DubboSpringInitContext();
// Spring ApplicationContext may not ready at this moment (e.g. load from xml), so use registry as key
if (contextMap.putIfAbsent(registry, context) != null) {
if (REGISTRY_CONTEXT_MAP.putIfAbsent(registry, context) != null) {
return;
}
@ -66,18 +66,18 @@ public class DubboSpringInitializer {
}
public static boolean remove(BeanDefinitionRegistry registry) {
return contextMap.remove(registry) != null;
return REGISTRY_CONTEXT_MAP.remove(registry) != null;
}
public static boolean remove(ApplicationContext springContext) {
AutowireCapableBeanFactory autowireCapableBeanFactory = springContext.getAutowireCapableBeanFactory();
for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : contextMap.entrySet()) {
for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : REGISTRY_CONTEXT_MAP.entrySet()) {
DubboSpringInitContext initContext = entry.getValue();
if (initContext.getApplicationContext() == springContext ||
initContext.getBeanFactory() == autowireCapableBeanFactory ||
initContext.getRegistry() == autowireCapableBeanFactory
) {
DubboSpringInitContext context = contextMap.remove(entry.getKey());
DubboSpringInitContext context = REGISTRY_CONTEXT_MAP.remove(entry.getKey());
logger.info("Unbind " + safeGetModelDesc(context.getModuleModel()) + " from spring container: " +
ObjectUtils.identityToString(entry.getKey()));
return true;
@ -87,11 +87,11 @@ public class DubboSpringInitializer {
}
static Map<BeanDefinitionRegistry, DubboSpringInitContext> getContextMap() {
return contextMap;
return REGISTRY_CONTEXT_MAP;
}
static DubboSpringInitContext findBySpringContext(ApplicationContext applicationContext) {
for (DubboSpringInitContext initContext : contextMap.values()) {
for (DubboSpringInitContext initContext : REGISTRY_CONTEXT_MAP.values()) {
if (initContext.getApplicationContext() == applicationContext) {
return initContext;
}
@ -184,7 +184,7 @@ public class DubboSpringInitializer {
}
private static DubboSpringInitContext findContextForApplication(ApplicationModel applicationModel) {
for (DubboSpringInitContext initializationContext : contextMap.values()) {
for (DubboSpringInitContext initializationContext : REGISTRY_CONTEXT_MAP.values()) {
if (initializationContext.getApplicationModel() == applicationModel) {
return initializationContext;
}

View File

@ -157,7 +157,7 @@ public class ReferenceBeanManager implements ApplicationContextAware {
* @param referenceBean
* @throws Exception
*/
private synchronized void initReferenceBean(ReferenceBean referenceBean) throws Exception {
public synchronized void initReferenceBean(ReferenceBean referenceBean) throws Exception {
if (referenceBean.getReferenceConfig() != null) {
return;

View File

@ -520,6 +520,11 @@
<xsd:documentation><![CDATA[ Whether to enable qos or not. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="qos-check" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[ Whether qos should start success or not, will check qosEnable first. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="qos-host" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The qos host to listen. ]]></xsd:documentation>
@ -1115,6 +1120,11 @@
<xsd:documentation><![CDATA[ Enable record rpc metrics. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="rpc-level" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ Is the metric for rpc requests at the METHOD level or SERVICE level ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="tracingType">
@ -1692,6 +1702,11 @@
<xsd:documentation><![CDATA[ The protocol context path. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="json-check-level" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The level of json compatibility check. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="register" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The protocol can be register to registry. ]]></xsd:documentation>

View File

@ -27,7 +27,7 @@
<dubbo:config-center address="zookeeper://127.0.0.1:2181"/>
<dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
<dubbo:registry id="registry1" address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:registry id="registry1" address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="dubbo" port="-1"/>
<dubbo:protocol name="tri" port="-1"/>

View File

@ -19,26 +19,17 @@ package org.apache.dubbo.config.spring6.beans.factory.annotation;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
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.SpringCompatUtils;
import org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedFieldValueResolver;
import org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedMethodArgumentsResolver;
import org.apache.dubbo.config.spring6.utils.AotUtils;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aot.generate.AccessControl;
@ -51,100 +42,44 @@ import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.support.ClassHintUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.aot.AutowiredArgumentsCodeGenerator;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.MethodMetadata;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
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;
/**
* <p>
* Step 1:
* The purpose of implementing {@link BeanFactoryPostProcessor} is to scan the registration reference bean definition earlier,
* so that it can be shared with the xml bean configuration.
* </p>
* The purpose of implementing {@link BeanRegistrationAotProcessor} is to
* supplement for {@link ReferenceAnnotationBeanPostProcessor} ability of AOT.
*
* <p>
* Step 2:
* By implementing {@link org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor},
* inject the reference bean instance into the fields and setter methods which annotated with {@link DubboReference}.
* </p>
*
* @see DubboReference
* @see Reference
* @see com.alibaba.dubbo.config.annotation.Reference
* @since 2.5.7
* @since 3.3
*/
public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotationBeanPostProcessor
implements ApplicationContextAware, BeanRegistrationAotProcessor, BeanFactoryPostProcessor {
/**
* The bean name of {@link ReferenceAnnotationWithAotBeanPostProcessor}
*/
public static final String BEAN_NAME = ReferenceAnnotationWithAotBeanPostProcessor.class.getName();
/**
* Cache size
*/
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
public class ReferenceAnnotationWithAotBeanPostProcessor extends ReferenceAnnotationBeanPostProcessor
implements BeanRegistrationAotProcessor {
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedFieldReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private ApplicationContext applicationContext;
private ReferenceBeanManager referenceBeanManager;
private BeanDefinitionRegistry beanDefinitionRegistry;
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@ -155,7 +90,7 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
* {@link DubboReference @DubboReference} has been supported since 2.7.7
*/
public ReferenceAnnotationWithAotBeanPostProcessor() {
super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
super();
}
@Override
@ -192,18 +127,6 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
}
}
// if (beanFactory instanceof AbstractBeanFactory) {
// List<BeanPostProcessor> beanPostProcessors = ((AbstractBeanFactory) beanFactory).getBeanPostProcessors();
// for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
// if (beanPostProcessor == this) {
// // This bean has been registered as BeanPostProcessor at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()
// // so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause BeanPostProcessorChecker detection error
// beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME);
// break;
// }
// }
// }
try {
// this is an early event, it will be notified at org.springframework.context.support.AbstractApplicationContext.registerListeners()
applicationContext.publishEvent(new DubboConfigInitEvent(applicationContext));
@ -227,157 +150,6 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
return false;
}
/**
* process @DubboReference at java-config @bean method
* <pre class="code">
* &#064;Configuration
* public class ConsumerConfig {
*
* &#064;Bean
* &#064;DubboReference(group="demo", version="1.2.3")
* public ReferenceBean&lt;DemoService&gt; demoService() {
* return new ReferenceBean();
* }
*
* }
* </pre>
*
* @param beanName
* @param beanDefinition
*/
private void processReferenceAnnotatedBeanDefinition(String beanName, AnnotatedBeanDefinition beanDefinition) {
MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(beanDefinition);
// Extract beanClass from generic return type of java-config bean method: ReferenceBean<DemoService>
// see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBeanFromMethod
Class beanClass = getBeanFactory().getType(beanName);
if (beanClass == Object.class) {
beanClass = SpringCompatUtils.getGenericTypeOfReturnType(factoryMethodMetadata);
}
if (beanClass == Object.class) {
// bean class is invalid, ignore it
return;
}
if (beanClass == null) {
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName() + "#" + factoryMethodMetadata.getMethodName() + "()";
throw new BeanCreationException("The ReferenceBean is missing necessary generic type, which returned by the @Bean method of Java-config class. " +
"The generic type of the returned ReferenceBean must be specified as the referenced interface type, " +
"such as ReferenceBean<DemoService>. Please check bean method: " + beanMethodSignature);
}
// get dubbo reference annotation attributes
Map<String, Object> annotationAttributes = null;
// try all dubbo reference annotation types
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
// Since Spring 5.2
// return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();
// Compatible with Spring 4.x
annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
annotationAttributes = filterDefaultValues(annotationType, annotationAttributes);
break;
}
}
if (annotationAttributes != null) {
// @DubboReference on @Bean method
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>(annotationAttributes);
// reset id attribute
attributes.put(ReferenceAttributes.ID, beanName);
// convert annotation props
ReferenceBeanSupport.convertReferenceProps(attributes, beanClass);
// get interface
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
// check beanClass and reference interface class
if (!StringUtils.isEquals(interfaceName, beanClass.getName()) && beanClass != GenericService.class) {
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName() + "#" + factoryMethodMetadata.getMethodName() + "()";
throw new BeanCreationException("The 'interfaceClass' or 'interfaceName' attribute value of @DubboReference annotation " +
"is inconsistent with the generic type of the ReferenceBean returned by the bean method. " +
"The interface class of @DubboReference is: " + interfaceName + ", but return ReferenceBean<" + beanClass.getName() + ">. " +
"Please remove the 'interfaceClass' and 'interfaceName' attributes from @DubboReference annotation. " +
"Please check bean method: " + beanMethodSignature);
}
Class interfaceClass = beanClass;
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
} else {
// raw reference bean
// the ReferenceBean is not yet initialized
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, beanClass);
if (beanClass != GenericService.class) {
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, beanClass.getName());
}
}
// set id
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, beanName);
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
if (isReferenceBean(beanDefinition)) {
//mark property value as optional
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();
for (PropertyValue propertyValue : propertyValues) {
propertyValue.setOptional(true);
}
} else if (isAnnotatedReferenceBean(beanDefinition)) {
// extract beanClass from java-config bean method generic return type: ReferenceBean<DemoService>
//Class beanClass = getBeanFactory().getType(beanName);
} else {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
try {
prepareInjection(metadata);
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
}
/**
* Alternatives to the {@link #postProcessProperties(PropertyValues, Object, String)}, that removed as of Spring
* Framework 6.0.0, and in favor of {@link #postProcessProperties(PropertyValues, Object, String)}.
* <p>In order to be compatible with the lower version of Spring, it is still retained.
*
* @see #postProcessProperties
*/
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return postProcessProperties(pvs, bean, beanName);
}
/**
* Alternatives to the {@link #postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)}.
*
* @see #postProcessPropertyValues
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
try {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
prepareInjection(metadata);
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
private boolean isReferenceBean(BeanDefinition beanDefinition) {
return ReferenceBean.class.getName().equals(beanDefinition.getBeanClassName());
}
@ -401,238 +173,6 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
return metadata;
}
protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {
try {
//find and register bean definition for @DubboReference/@Reference
for (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {
if (fieldElement.injectedObject != null) {
continue;
}
Class<?> injectedType = fieldElement.field.getType();
AnnotationAttributes attributes = fieldElement.attributes;
String referenceBeanName = registerReferenceBean(fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);
//associate fieldElement and reference bean
fieldElement.injectedObject = referenceBeanName;
injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);
}
for (AnnotatedMethodElement methodElement : metadata.getMethodElements()) {
if (methodElement.injectedObject != null) {
continue;
}
Class<?> injectedType = methodElement.getInjectedType();
AnnotationAttributes attributes = methodElement.attributes;
String referenceBeanName = registerReferenceBean(methodElement.getPropertyName(), injectedType, attributes, methodElement.method);
//associate methodElement and reference bean
methodElement.injectedObject = referenceBeanName;
injectedMethodReferenceBeanCache.put(methodElement, referenceBeanName);
}
} catch (ClassNotFoundException e) {
throw new BeanCreationException("prepare reference annotation failed", e);
}
}
public String registerReferenceBean(String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member) throws BeansException {
boolean renameable = true;
// referenceBeanName
String referenceBeanName = getAttribute(attributes, ReferenceAttributes.ID);
if (hasText(referenceBeanName)) {
renameable = false;
} else {
referenceBeanName = propertyName;
}
String checkLocation = "Please check " + member.toString();
// convert annotation props
ReferenceBeanSupport.convertReferenceProps(attributes, injectedType);
// get interface
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
if (StringUtils.isBlank(interfaceName)) {
throw new BeanCreationException("Need to specify the 'interfaceName' or 'interfaceClass' attribute of '@DubboReference' if enable generic. " + checkLocation);
}
// check reference key
String referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext);
// find reference bean name by reference key
List<String> registeredReferenceBeanNames = referenceBeanManager.getBeanNamesByKey(referenceKey);
if (registeredReferenceBeanNames.size() > 0) {
// found same name and reference key
if (registeredReferenceBeanNames.contains(referenceBeanName)) {
return referenceBeanName;
}
}
//check bean definition
boolean isContains;
if ((isContains = beanDefinitionRegistry.containsBeanDefinition(referenceBeanName)) || beanDefinitionRegistry.isAlias(referenceBeanName)) {
String preReferenceBeanName = referenceBeanName;
if (!isContains) {
// Look in the alias for the origin bean name
String[] aliases = beanDefinitionRegistry.getAliases(referenceBeanName);
if (ArrayUtils.isNotEmpty(aliases)) {
for (String alias : aliases) {
if (beanDefinitionRegistry.containsBeanDefinition(alias)) {
preReferenceBeanName = alias;
break;
}
}
}
}
BeanDefinition prevBeanDefinition = beanDefinitionRegistry.getBeanDefinition(preReferenceBeanName);
String prevBeanType = prevBeanDefinition.getBeanClassName();
String prevBeanDesc = referenceBeanName + "[" + prevBeanType + "]";
String newBeanDesc = referenceBeanName + "[" + referenceKey + "]";
if (isReferenceBean(prevBeanDefinition)) {
//check reference key
String prevReferenceKey = ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext);
if (StringUtils.isEquals(prevReferenceKey, referenceKey)) {
//found matched dubbo reference bean, ignore register
return referenceBeanName;
}
//get interfaceName from attribute
Assert.notNull(prevBeanDefinition, "The interface class of ReferenceBean is not initialized");
prevBeanDesc = referenceBeanName + "[" + prevReferenceKey + "]";
}
// bean name from attribute 'id' or java-config bean, cannot be renamed
if (!renameable) {
throw new BeanCreationException("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
"but cannot rename the reference bean name (specify the id attribute or java-config bean), " +
"please modify the name of one of the beans: " +
"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
}
// the prev bean type is different, rename the new reference bean
int index = 2;
String newReferenceBeanName = null;
while (newReferenceBeanName == null || beanDefinitionRegistry.containsBeanDefinition(newReferenceBeanName)
|| beanDefinitionRegistry.isAlias(newReferenceBeanName)) {
newReferenceBeanName = referenceBeanName + "#" + index;
index++;
// double check found same name and reference key
if (registeredReferenceBeanNames.contains(newReferenceBeanName)) {
return newReferenceBeanName;
}
}
newBeanDesc = newReferenceBeanName + "[" + referenceKey + "]";
logger.warn(CONFIG_DUBBO_BEAN_INITIALIZER, "", "", "Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
"rename dubbo reference bean to [" + newReferenceBeanName + "]. " +
"It is recommended to modify the name of one of the beans to avoid injection problems. " +
"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
referenceBeanName = newReferenceBeanName;
}
attributes.put(ReferenceAttributes.ID, referenceBeanName);
// If registered matched reference before, just register alias
if (registeredReferenceBeanNames.size() > 0) {
beanDefinitionRegistry.registerAlias(registeredReferenceBeanNames.get(0), referenceBeanName);
referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
return referenceBeanName;
}
Class interfaceClass = injectedType;
// TODO Only register one reference bean for same (group, interface, version)
// Register the reference bean definition to the beanFactory
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(ReferenceBean.class.getName());
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// beanDefinition.getPropertyValues().add(Constants.REFERENCE_PROPS,attributes);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean
// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()
GenericBeanDefinition targetDefinition = new GenericBeanDefinition();
targetDefinition.setBeanClass(interfaceClass);
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, referenceBeanName + "_decorated"));
// signal object type since Spring 5.2
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
logger.info("Register dubbo reference bean: " + referenceBeanName + " = " + referenceKey + " at " + member);
return referenceBeanName;
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
if (injectedElement.injectedObject == null) {
throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");
}
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.referenceBeanManager = applicationContext.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
this.beanDefinitionRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
}
@Override
public void destroy() throws Exception {
super.destroy();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
/**
* Gets all beans of {@link ReferenceBean}
*
* @deprecated use {@link ReferenceBeanManager#getReferences()} instead
*/
@Deprecated
public Collection<ReferenceBean<?>> getReferenceBeans() {
return Collections.emptyList();
}
/**
* Get {@link ReferenceBean} {@link Map} in injected field.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();
for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedFieldReferenceBeanCache.entrySet()) {
map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));
}
return Collections.unmodifiableMap(map);
}
/**
* Get {@link ReferenceBean} {@link Map} in injected method.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();
for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedMethodReferenceBeanCache.entrySet()) {
map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));
}
return Collections.unmodifiableMap(map);
}
@Nullable
private AutowireCandidateResolver getAutowireCandidateResolver() {
if (this.beanFactory instanceof DefaultListableBeanFactory) {
@ -665,19 +205,19 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
.addForFeatureComponent("DubboReference", this.target, type -> {
type.addJavadoc("DubboReference for {@link $T}.", this.target);
type.addModifiers(javax.lang.model.element.Modifier.PUBLIC);
});
.addForFeatureComponent("DubboReference", this.target, type -> {
type.addJavadoc("DubboReference for {@link $T}.", this.target);
type.addModifiers(javax.lang.model.element.Modifier.PUBLIC);
});
GeneratedMethod generateMethod = generatedClass.getMethods().add("apply", method -> {
method.addJavadoc("Apply the dubbo reference.");
method.addModifiers(javax.lang.model.element.Modifier.PUBLIC,
javax.lang.model.element.Modifier.STATIC);
javax.lang.model.element.Modifier.STATIC);
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
method.addParameter(this.target, INSTANCE_PARAMETER);
method.returns(this.target);
method.addCode(generateMethodCode(generatedClass.getName(),
generationContext.getRuntimeHints()));
generationContext.getRuntimeHints()));
});
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
@ -691,13 +231,13 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getFieldElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getFieldElements()) {
code.addStatement(generateMethodStatementForElement(
targetClassName, referenceElement, hints));
targetClassName, referenceElement, hints));
}
}
if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getMethodElements())) {
for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getMethodElements()) {
code.addStatement(generateMethodStatementForElement(
targetClassName, referenceElement, hints));
targetClassName, referenceElement, hints));
}
}
code.addStatement("return $L", INSTANCE_PARAMETER);
@ -723,14 +263,14 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
if (member instanceof Field) {
return generateMethodStatementForField(
targetClassName, (Field) member, attributes, injectedObject, hints);
targetClassName, (Field) member, attributes, injectedObject, hints);
}
if (member instanceof Method) {
return generateMethodStatementForMethod(
targetClassName, (Method) member, attributes, injectedObject, hints);
targetClassName, (Method) member, attributes, injectedObject, hints);
}
throw new IllegalStateException(
"Unsupported member type " + member.getClass().getName());
"Unsupported member type " + member.getClass().getName());
}
private CodeBlock generateMethodStatementForField(ClassName targetClassName,
@ -738,17 +278,17 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
hints.reflection().registerField(field);
CodeBlock resolver = CodeBlock.of("$T.$L($S)",
ReferencedFieldValueResolver.class,
"forRequiredField", field.getName());
ReferencedFieldValueResolver.class,
"forRequiredField", field.getName());
CodeBlock shortcutResolver = CodeBlock.of("$L.withShortcut($S)", resolver, injectedObject);
AccessControl accessControl = AccessControl.forMember(field);
if (!accessControl.isAccessibleFrom(targetClassName)) {
return CodeBlock.of("$L.resolveAndSet($L, $L)", shortcutResolver,
REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
}
return CodeBlock.of("$L.$L = $L.resolve($L)", INSTANCE_PARAMETER,
field.getName(), shortcutResolver, REGISTERED_BEAN_PARAMETER);
field.getName(), shortcutResolver, REGISTERED_BEAN_PARAMETER);
}
private CodeBlock generateMethodStatementForMethod(ClassName targetClassName,
@ -776,9 +316,9 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
} else {
hints.reflection().registerMethod(method, ExecutableMode.INTROSPECT);
CodeBlock arguments = new AutowiredArgumentsCodeGenerator(this.target,
method).generateCode(method.getParameterTypes());
method).generateCode(method.getParameterTypes());
CodeBlock injectionCode = CodeBlock.of("args -> $L.$L($L)",
INSTANCE_PARAMETER, method.getName(), arguments);
INSTANCE_PARAMETER, method.getName(), arguments);
code.add(".resolve($L, $L)", REGISTERED_BEAN_PARAMETER, injectionCode);
}
return code.build();
@ -832,7 +372,7 @@ public class ReferenceAnnotationWithAotBeanPostProcessor extends AbstractAnnotat
private void registerProxyIfNecessary(RuntimeHints runtimeHints, DependencyDescriptor dependencyDescriptor) {
if (this.candidateResolver != null) {
Class<?> proxyClass =
this.candidateResolver.getLazyResolutionProxyClass(dependencyDescriptor, null);
this.candidateResolver.getLazyResolutionProxyClass(dependencyDescriptor, null);
if (proxyClass != null) {
ClassHintUtils.registerProxyIfNecessary(proxyClass, runtimeHints);
}

View File

@ -18,7 +18,6 @@ package org.apache.dubbo.config.spring6.beans.factory.annotation;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
@ -29,21 +28,19 @@ import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import java.util.Collection;
/**
* A {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes and annotated bean in java config classes.
* It's also the infrastructure class of XML {@link BeanDefinitionParser} on &lt;dubbo:annotation /&gt;
* The purpose of implementing {@link BeanRegistrationAotProcessor} is to
* supplement for {@link ServiceAnnotationPostProcessor} ability of AOT.
*
* @see AnnotationBeanDefinitionParser
* @see BeanDefinitionRegistryPostProcessor
* @since 3.2
* @since 3.3
*/
public class ServiceAnnotationWithAotPostProcessor extends ServiceAnnotationPostProcessor implements BeanRegistrationAotProcessor {

View File

@ -30,7 +30,7 @@
<properties>
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot-maven-plugin.version>2.7.14</spring-boot-maven-plugin.version>
<spring-boot-maven-plugin.version>2.7.15</spring-boot-maven-plugin.version>
</properties>
<modules>

View File

@ -36,7 +36,7 @@
<properties>
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot-maven-plugin.version>2.7.14</spring-boot-maven-plugin.version>
<spring-boot-maven-plugin.version>2.7.15</spring-boot-maven-plugin.version>
</properties>
<artifactId>dubbo-demo-api</artifactId>

View File

@ -224,7 +224,7 @@
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.24</version>
<version>0.9.27</version>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>

View File

@ -222,7 +222,7 @@
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.24</version>
<version>0.9.27</version>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>

View File

@ -31,7 +31,7 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<slf4j-log4j12.version>1.7.33</slf4j-log4j12.version>
<spring-boot.version>2.7.14</spring-boot.version>
<spring-boot.version>2.7.15</spring-boot.version>
<skip_maven_deploy>true</skip_maven_deploy>
</properties>

View File

@ -31,7 +31,7 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<slf4j-log4j12.version>1.7.33</slf4j-log4j12.version>
<spring-boot.version>2.7.14</spring-boot.version>
<spring-boot.version>2.7.15</spring-boot.version>
<skip_maven_deploy>true</skip_maven_deploy>
</properties>

View File

@ -36,9 +36,9 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot.version>2.7.14</spring-boot.version>
<spring-boot-maven-plugin.version>2.7.14</spring-boot-maven-plugin.version>
<micrometer-core.version>1.11.3</micrometer-core.version>
<spring-boot.version>2.7.15</spring-boot.version>
<spring-boot-maven-plugin.version>2.7.15</spring-boot-maven-plugin.version>
<micrometer-core.version>1.11.4</micrometer-core.version>
</properties>
<dependencyManagement>
<dependencies>

View File

@ -32,7 +32,7 @@
<properties>
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot-maven-plugin.version>2.7.14</spring-boot-maven-plugin.version>
<spring-boot-maven-plugin.version>2.7.15</spring-boot-maven-plugin.version>
</properties>
<modules>

View File

@ -92,17 +92,17 @@
<!-- Common libs -->
<!-- <spring_version>4.3.30.RELEASE</spring_version> -->
<spring_version>5.3.25</spring_version>
<spring_security_version>5.8.5</spring_security_version>
<spring_security_version>5.8.6</spring_security_version>
<javassist_version>3.29.2-GA</javassist_version>
<bytebuddy.version>1.14.6</bytebuddy.version>
<bytebuddy.version>1.14.8</bytebuddy.version>
<netty_version>3.2.10.Final</netty_version>
<netty4_version>4.1.95.Final</netty4_version>
<netty4_version>4.1.97.Final</netty4_version>
<mina_version>2.2.1</mina_version>
<grizzly_version>2.4.4</grizzly_version>
<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.39</fastjson2_version>
<fastjson2_version>2.0.40</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>
@ -112,12 +112,12 @@
<consul_client_version>1.5.3</consul_client_version>
<xmemcached_version>1.4.3</xmemcached_version>
<cxf_version>3.5.5</cxf_version>
<thrift_version>0.18.1</thrift_version>
<thrift_version>0.19.0</thrift_version>
<hessian_version>4.0.66</hessian_version>
<protobuf-java_version>3.24.1</protobuf-java_version>
<protobuf-java_version>3.24.3</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>
<jetty_version>9.4.52.v20230823</jetty_version>
<validation_new_version>3.0.2</validation_new_version>
<validation_version>1.1.0.Final</validation_version>
<hibernate_validator_version>5.4.3.Final</hibernate_validator_version>
@ -129,18 +129,18 @@
<fst_version>2.57</fst_version>
<avro_version>1.11.1</avro_version>
<apollo_client_version>2.1.0</apollo_client_version>
<snakeyaml_version>2.1</snakeyaml_version>
<snakeyaml_version>2.2</snakeyaml_version>
<commons_lang3_version>3.12.0</commons_lang3_version>
<protostuff_version>1.8.0</protostuff_version>
<envoy_api_version>0.1.35</envoy_api_version>
<micrometer.version>1.11.3</micrometer.version>
<micrometer.version>1.11.4</micrometer.version>
<opentelemetry.version>1.26.0</opentelemetry.version>
<zipkin-reporter.version>2.16.4</zipkin-reporter.version>
<micrometer-tracing.version>1.1.4</micrometer-tracing.version>
<micrometer-tracing.version>1.1.5</micrometer-tracing.version>
<t_digest.version>3.3</t_digest.version>
<prometheus_client.version>0.16.0</prometheus_client.version>
<reactive.version>1.0.4</reactive.version>
<reactor.version>3.5.9</reactor.version>
<reactor.version>3.5.10</reactor.version>
<rxjava.version>2.2.21</rxjava.version>
<okhttp_version>3.14.9</okhttp_version>
@ -152,7 +152,7 @@
<nacos_version>2.2.4</nacos_version>
<sentinel.version>1.8.6</sentinel.version>
<seata.version>1.6.1</seata.version>
<grpc.version>1.57.2</grpc.version>
<grpc.version>1.58.0</grpc.version>
<grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>
<jprotoc_version>1.2.2</jprotoc_version>
<!-- Log libs -->
@ -177,7 +177,7 @@
<jaxb_version>2.2.7</jaxb_version>
<activation_version>1.2.0</activation_version>
<test_container_version>1.18.3</test_container_version>
<test_container_version>1.19.0</test_container_version>
<etcd_launcher_version>0.7.6</etcd_launcher_version>
<hessian_lite_version>3.2.13</hessian_lite_version>
<swagger_version>1.6.11</swagger_version>

View File

@ -190,6 +190,13 @@
</dependency>
<!-- metrics -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-event</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-api</artifactId>
@ -697,6 +704,7 @@
<include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
<include>org.apache.dubbo:dubbo-metadata-report-redis</include>
<include>org.apache.dubbo:dubbo-metadata-report-zookeeper</include>
<include>org.apache.dubbo:dubbo-metrics-event</include>
<include>org.apache.dubbo:dubbo-metrics-api</include>
<include>org.apache.dubbo:dubbo-metrics-default</include>
<include>org.apache.dubbo:dubbo-metrics-registry</include>

View File

@ -251,6 +251,11 @@
<artifactId>dubbo-metrics-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-event</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-default</artifactId>

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.validation.filter;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.rpc.AsyncRpcResult;
@ -82,8 +83,7 @@ public class ValidationFilter implements Filter {
*/
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (validation != null && !invocation.getMethodName().startsWith("$")
&& ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), VALIDATION_KEY))) {
if (needValidate(invoker.getUrl(), invocation.getMethodName())) {
try {
Validator validator = validation.getValidator(invoker.getUrl());
if (validator != null) {
@ -98,4 +98,8 @@ public class ValidationFilter implements Filter {
return invoker.invoke(invocation);
}
private boolean needValidate(URL url, String methodName) {
return validation != null && !methodName.startsWith("$") && ConfigUtils.isNotEmpty(url.getMethodParameter(methodName, VALIDATION_KEY));
}
}

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.validation.MethodValidated;
import org.apache.dubbo.validation.Validator;
@ -57,6 +58,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -89,7 +91,7 @@ public class JValidator implements Validator {
this.clazz = ReflectUtils.forName(url.getServiceInterface());
String jvalidation = url.getParameter("jvalidation");
ValidatorFactory factory;
if (jvalidation != null && jvalidation.length() > 0) {
if (StringUtils.isNotEmpty(jvalidation)) {
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
} else {
factory = Validation.buildDefaultValidatorFactory();
@ -111,8 +113,9 @@ public class JValidator implements Validator {
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
}
Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();
for (int i = 0; i < args.length; i++) {
Field field = parameterClass.getField(method.getName() + "Argument" + i);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Field field = parameterClass.getField(parameters[i].getName());
field.set(parameterBean, args[i]);
}
return parameterBean;
@ -129,10 +132,9 @@ public class JValidator implements Validator {
* @param method invoke method
* @param parameterClassName generated parameterClassName
* @return Class<?> generated methodParameterClass
* @throws Exception
*/
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
throws Exception {
throws Exception {
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
synchronized (parameterClassName.intern()) {
CtClass ctClass = null;
@ -144,28 +146,26 @@ public class JValidator implements Validator {
if (null == ctClass) {
ctClass = pool.makeClass(parameterClassName);
ClassFile classFile = ctClass.getClassFile();
classFile.setVersionToJava5();
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
// parameter fields
Class<?>[] parameterTypes = method.getParameterTypes();
Parameter[] parameters = method.getParameters();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> type = parameterTypes[i];
for (int i = 0; i < parameters.length; i++) {
Annotation[] annotations = parameterAnnotations[i];
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
Method[] members = annotation.annotationType().getMethods();
for (Method member : members) {
if (Modifier.isPublic(member.getModifiers())
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
Object value = member.invoke(annotation);
if (null != value) {
MemberValue memberValue = createMemberValue(
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
ja.addMemberValue(member.getName(), memberValue);
}
}
@ -173,12 +173,14 @@ public class JValidator implements Validator {
attribute.addAnnotation(ja);
}
}
String fieldName = method.getName() + "Argument" + i;
Parameter parameter = parameters[i];
Class<?> type = parameter.getType();
String fieldName = parameter.getName();
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
ctField.getFieldInfo().addAttribute(attribute);
ctClass.addField(ctField);
}
return ctClass.toClass(clazz.getClassLoader(), null);
return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());
} else {
return Class.forName(parameterClassName, true, clazz.getClassLoader());
}
@ -187,13 +189,16 @@ public class JValidator implements Validator {
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
StringBuilder builder = new StringBuilder().append(clazz.getName())
.append('_')
.append(toUpperMethoName(method.getName()))
.append("Parameter");
.append('_')
.append(toUpperMethodName(method.getName()))
.append("Parameter");
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
builder.append('_').append(parameterType.getName());
// In order to ensure that the parameter class can be generated correctly,
// replace "." with "_" to make the package name of the generated parameter class
// consistent with the package name of the actual parameter class.
builder.append('_').append(parameterType.getName().replace(".", "_"));
}
return builder.toString();
@ -201,19 +206,17 @@ public class JValidator implements Validator {
private static boolean hasConstraintParameter(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations != null && parameterAnnotations.length > 0) {
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
}
}
return false;
}
private static String toUpperMethoName(String methodName) {
private static String toUpperMethodName(String methodName) {
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
}
@ -263,7 +266,7 @@ public class JValidator implements Validator {
if (methodClass != null) {
groups.add(methodClass);
}
Set<ConstraintViolation<?>> violations = new HashSet<>();
Method method = clazz.getMethod(methodName, parameterTypes);
Class<?>[] methodClasses;
if (method.isAnnotationPresent(MethodValidated.class)) {
@ -275,15 +278,16 @@ public class JValidator implements Validator {
groups.add(1, clazz);
// convert list to array
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
Class<?>[] classGroups = groups.toArray(new Class[0]);
Set<ConstraintViolation<?>> violations = new HashSet<>();
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
if (parameterBean != null) {
violations.addAll(validator.validate(parameterBean, classgroups));
violations.addAll(validator.validate(parameterBean, classGroups));
}
for (Object arg : arguments) {
validate(violations, arg, classgroups);
validate(violations, arg, classGroups);
}
if (!violations.isEmpty()) {
@ -294,7 +298,7 @@ public class JValidator implements Validator {
private Class<?> methodClass(String methodName) {
Class<?> methodClass = null;
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName);
Class<?> cached = methodClassMap.get(methodClassName);
if (cached != null) {
return cached == clazz ? null : cached;

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.validation.MethodValidated;
import org.apache.dubbo.validation.Validator;
@ -57,6 +58,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -89,7 +91,7 @@ public class JValidatorNew implements Validator {
this.clazz = ReflectUtils.forName(url.getServiceInterface());
String jvalidation = url.getParameter("jvalidationNew");
ValidatorFactory factory;
if (jvalidation != null && jvalidation.length() > 0) {
if (StringUtils.isNotEmpty(jvalidation)) {
factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation)).configure().buildValidatorFactory();
} else {
factory = Validation.buildDefaultValidatorFactory();
@ -111,8 +113,9 @@ public class JValidatorNew implements Validator {
parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);
}
Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();
for (int i = 0; i < args.length; i++) {
Field field = parameterClass.getField(method.getName() + "Argument" + i);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Field field = parameterClass.getField(parameters[i].getName());
field.set(parameterBean, args[i]);
}
return parameterBean;
@ -129,10 +132,9 @@ public class JValidatorNew implements Validator {
* @param method invoke method
* @param parameterClassName generated parameterClassName
* @return Class<?> generated methodParameterClass
* @throws Exception
*/
private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)
throws Exception {
throws Exception {
ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());
synchronized (parameterClassName.intern()) {
CtClass ctClass = null;
@ -144,28 +146,26 @@ public class JValidatorNew implements Validator {
if (null == ctClass) {
ctClass = pool.makeClass(parameterClassName);
ClassFile classFile = ctClass.getClassFile();
classFile.setVersionToJava5();
ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));
// parameter fields
Class<?>[] parameterTypes = method.getParameterTypes();
Parameter[] parameters = method.getParameters();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> type = parameterTypes[i];
for (int i = 0; i < parameters.length; i++) {
Annotation[] annotations = parameterAnnotations[i];
AnnotationsAttribute attribute = new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
classFile.getConstPool(), pool.getCtClass(annotation.annotationType().getName()));
Method[] members = annotation.annotationType().getMethods();
for (Method member : members) {
if (Modifier.isPublic(member.getModifiers())
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
&& member.getParameterTypes().length == 0
&& member.getDeclaringClass() == annotation.annotationType()) {
Object value = member.invoke(annotation);
if (null != value) {
MemberValue memberValue = createMemberValue(
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
classFile.getConstPool(), pool.get(member.getReturnType().getName()), value);
ja.addMemberValue(member.getName(), memberValue);
}
}
@ -173,12 +173,14 @@ public class JValidatorNew implements Validator {
attribute.addAnnotation(ja);
}
}
String fieldName = method.getName() + "Argument" + i;
Parameter parameter = parameters[i];
Class<?> type = parameter.getType();
String fieldName = parameter.getName();
CtField ctField = CtField.make("public " + type.getCanonicalName() + " " + fieldName + ";", pool.getCtClass(parameterClassName));
ctField.getFieldInfo().addAttribute(attribute);
ctClass.addField(ctField);
}
return ctClass.toClass(clazz.getClassLoader(), null);
return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());
} else {
return Class.forName(parameterClassName, true, clazz.getClassLoader());
}
@ -187,13 +189,16 @@ public class JValidatorNew implements Validator {
private static String generateMethodParameterClassName(Class<?> clazz, Method method) {
StringBuilder builder = new StringBuilder().append(clazz.getName())
.append('_')
.append(toUpperMethoName(method.getName()))
.append("Parameter");
.append('_')
.append(toUpperMethodName(method.getName()))
.append("Parameter");
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
builder.append('_').append(parameterType.getName());
// In order to ensure that the parameter class can be generated correctly,
// replace "." with "_" to make the package name of the generated parameter class
// consistent with the package name of the actual parameter class.
builder.append('_').append(parameterType.getName().replace(".", "_"));
}
return builder.toString();
@ -201,19 +206,17 @@ public class JValidatorNew implements Validator {
private static boolean hasConstraintParameter(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations.length > 0) {
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {
return true;
}
}
}
return false;
}
private static String toUpperMethoName(String methodName) {
private static String toUpperMethodName(String methodName) {
return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
}
@ -263,7 +266,7 @@ public class JValidatorNew implements Validator {
if (methodClass != null) {
groups.add(methodClass);
}
Set<ConstraintViolation<?>> violations = new HashSet<>();
Method method = clazz.getMethod(methodName, parameterTypes);
Class<?>[] methodClasses;
if (method.isAnnotationPresent(MethodValidated.class)) {
@ -275,15 +278,16 @@ public class JValidatorNew implements Validator {
groups.add(1, clazz);
// convert list to array
Class<?>[] classgroups = groups.toArray(new Class[groups.size()]);
Class<?>[] classGroups = groups.toArray(new Class[0]);
Set<ConstraintViolation<?>> violations = new HashSet<>();
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
if (parameterBean != null) {
violations.addAll(validator.validate(parameterBean, classgroups));
violations.addAll(validator.validate(parameterBean, classGroups));
}
for (Object arg : arguments) {
validate(violations, arg, classgroups);
validate(violations, arg, classGroups);
}
if (!violations.isEmpty()) {
@ -294,7 +298,7 @@ public class JValidatorNew implements Validator {
private Class<?> methodClass(String methodName) {
Class<?> methodClass = null;
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
String methodClassName = clazz.getName() + "$" + toUpperMethodName(methodName);
Class<?> cached = methodClassMap.get(methodClassName);
if (cached != null) {
return cached == clazz ? null : cached;

View File

@ -17,17 +17,24 @@
package org.apache.dubbo.validation.support.jvalidation;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget;
import org.apache.dubbo.validation.support.jvalidation.mock.ValidationParameter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
class JValidatorTest {
@Test
void testItWithNonExistMethod() {
@ -72,7 +79,7 @@ class JValidatorTest {
void testItWithCollectionArg() throws Exception {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod4", new Class<?>[]{List.class}, new Object[]{Arrays.asList("parameter")});
jValidator.validate("someMethod4", new Class<?>[]{List.class}, new Object[]{Collections.singletonList("parameter")});
}
@Test
@ -83,4 +90,83 @@ class JValidatorTest {
map.put("key", "value");
jValidator.validate("someMethod5", new Class<?>[]{Map.class}, new Object[]{map});
}
}
@Test
void testItWithPrimitiveArg() {
Assertions.assertThrows(ValidationException.class, () -> {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, null, null});
});
}
@Test
void testItWithPrimitiveArgWithProvidedMessage() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null});
Assertions.fail();
} catch (Exception e) {
assertThat(e.getMessage(), containsString("string must not be blank"));
assertThat(e.getMessage(), containsString("longValue must not be null"));
}
}
@Test
void testItWithPartialParameterValidation() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
jValidator.validate("someMethod6", new Class<?>[]{Integer.class, String.class, Long.class}, new Object[]{null, "", null});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(2));
}
}
@Test
void testItWithNestedParameterValidationWithNullParam() {
Assertions.assertThrows(ValidationException.class, () -> {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{null});
});
}
@Test
void testItWithNestedParameterValidationWithNullNestedParam() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(1));
assertThat(e1.getMessage(), containsString("body must not be null"));
}
}
@Test
void testItWithNestedParameterValidationWithNullNestedParams() {
URL url = URL.valueOf("test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget");
JValidator jValidator = new JValidator(url);
try {
JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();
param.setBody(new JValidatorTestTarget.Param());
jValidator.validate("someMethod7", new Class<?>[]{JValidatorTestTarget.BaseParam.class}, new Object[]{param});
Assertions.fail();
} catch (Exception e) {
assertThat(e, instanceOf(ConstraintViolationException.class));
ConstraintViolationException e1 = (ConstraintViolationException) e;
assertThat(e1.getConstraintViolations().size(), is(1));
assertThat(e1.getMessage(), containsString("name must not be null"));
}
}
}

View File

@ -18,6 +18,9 @@ package org.apache.dubbo.validation.support.jvalidation.mock;
import org.apache.dubbo.validation.MethodValidated;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@ -35,7 +38,42 @@ public interface JValidatorTestTarget {
void someMethod5(Map<String, String> map);
void someMethod6(Integer intValue,
@NotBlank(message = "string must not be blank") String string,
@NotNull(message = "longValue must not be null") Long longValue);
void someMethod7(@NotNull BaseParam<Param> baseParam);
@interface Test2 {
}
class BaseParam<T> {
@Valid
@NotNull(message = "body must not be null")
private T body;
public T getBody() {
return body;
}
public void setBody(T body) {
this.body = body;
}
}
class Param {
@NotNull(message = "name must not be null")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -36,6 +36,11 @@
<artifactId>dubbo-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-event</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId>

View File

@ -28,7 +28,7 @@ public class TimeWindowCounter {
private final LongAdderSlidingWindow slidingWindow;
public TimeWindowCounter(int bucketNum, int timeWindowSeconds) {
public TimeWindowCounter(int bucketNum, long timeWindowSeconds) {
this.slidingWindow = new LongAdderSlidingWindow(bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds));
}

View File

@ -89,6 +89,12 @@ public abstract class CombMetricsCollector<E extends TimeCounterEvent> extends A
this.stats.incrementMethodKey(wrapper, methodMetric, size);
}
@Override
public void init(Invocation invocation, MetricsKeyWrapper wrapper) {
this.stats.initMethodKey(wrapper, invocation);
}
protected List<MetricSample> export(MetricsCategory category) {
return stats.export(category);
}

View File

@ -30,5 +30,7 @@ public interface MethodMetricsCollector<E extends TimeCounterEvent> extends Metr
void increment(MethodMetric methodMetric, MetricsKeyWrapper wrapper, int size);
void addMethodRt(Invocation invocation, String registryOpType, Long responseTime);
void init(Invocation invocation, MetricsKeyWrapper wrapper);
}

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.listener.MetricsLifeListener;
import org.apache.dubbo.metrics.model.sample.MetricSample;
@ -42,4 +43,6 @@ public interface MetricsCollector<E extends TimeCounterEvent> extends MetricsLif
*/
List<MetricSample> collect();
default void initMetrics(MetricsEvent event) {};
}

View File

@ -112,6 +112,10 @@ public abstract class BaseStatComposite implements MetricsExport {
methodStatComposite.incrementMethodKey(metricsKeyWrapper, methodMetric, size);
}
public void initMethodKey(MetricsKeyWrapper metricsKeyWrapper, Invocation invocation) {
methodStatComposite.initMethodKey(metricsKeyWrapper, invocation);
}
@Override
public List<MetricSample> export(MetricsCategory category) {
List<MetricSample> list = new ArrayList<>();

View File

@ -26,6 +26,7 @@ import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.report.AbstractMetricsExport;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
@ -40,9 +41,11 @@ import java.util.concurrent.atomic.AtomicLong;
* the key will not be displayed when exporting (to be optimized)
*/
public class MethodStatComposite extends AbstractMetricsExport {
private boolean serviceLevel;
public MethodStatComposite(ApplicationModel applicationModel) {
super(applicationModel);
this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
}
private final Map<MetricsKeyWrapper, Map<MethodMetric, AtomicLong>> methodNumStats = new ConcurrentHashMap<>();
@ -54,6 +57,14 @@ public class MethodStatComposite extends AbstractMetricsExport {
metricsKeyWrappers.forEach(appKey -> methodNumStats.put(appKey, new ConcurrentHashMap<>()));
}
public void initMethodKey(MetricsKeyWrapper wrapper, Invocation invocation) {
if (!methodNumStats.containsKey(wrapper)) {
return;
}
methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation, serviceLevel), k -> new AtomicLong(0L));
}
public void incrementMethodKey(MetricsKeyWrapper wrapper, MethodMetric methodMetric, int size) {
if (!methodNumStats.containsKey(wrapper)) {
return;

View File

@ -50,9 +50,11 @@ import java.util.stream.Collectors;
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class RtStatComposite extends AbstractMetricsExport {
private boolean serviceLevel;
public RtStatComposite(ApplicationModel applicationModel) {
super(applicationModel);
this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
}
private final Map<String, List<LongContainer<? extends Number>>> rtStats = new ConcurrentHashMap<>();
@ -168,7 +170,7 @@ public class RtStatComposite extends AbstractMetricsExport {
List<Action> actions;
actions = new LinkedList<>();
for (LongContainer container : rtStats.get(registryOpType)) {
MethodMetric key = new MethodMetric(getApplicationModel(), invocation);
MethodMetric key = new MethodMetric(getApplicationModel(), invocation, serviceLevel);
Number current = (Number) container.get(key);
if (current == null) {
container.putIfAbsent(key, container.getInitFunc().apply(key));

View File

@ -0,0 +1,48 @@
/*
* 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.metrics.event;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;
public class MetricsInitEvent extends TimeCounterEvent {
private static final TypeWrapper METRIC_EVENT = new TypeWrapper(MetricsLevel.SERVICE, METRIC_REQUESTS);
public MetricsInitEvent(ApplicationModel source,TypeWrapper typeWrapper) {
super(source,typeWrapper);
}
public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
MetricsInitEvent initEvent = new MetricsInitEvent(applicationModel, METRIC_EVENT);
initEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
initEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);
initEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
initEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));
return initEvent;
}
}

View File

@ -40,9 +40,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public void publishEvent(MetricsEvent event) {
if (event instanceof EmptyEvent) {
return;
}
if (validateIfApplicationConfigExist(event)) return;
for (MetricsListener listener : listeners) {
if (listener.isSupport(event)) {
@ -74,9 +71,6 @@ public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {
@SuppressWarnings({"rawtypes"})
private void publishTimeEvent(MetricsEvent event, Consumer<MetricsLifeListener> consumer) {
if (validateIfApplicationConfigExist(event)) return;
if (event instanceof EmptyEvent) {
return;
}
if (event instanceof TimeCounterEvent) {
((TimeCounterEvent) event).getTimePair().end();
}

View File

@ -17,12 +17,17 @@
package org.apache.dubbo.metrics.model;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
@ -36,12 +41,31 @@ public class MethodMetric extends ServiceKeyMetric {
private String group;
private String version;
public MethodMetric(ApplicationModel applicationModel, Invocation invocation) {
public MethodMetric(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
super(applicationModel, MetricsSupport.getInterfaceName(invocation));
this.methodName = RpcUtils.getMethodName(invocation);
this.side = MetricsSupport.getSide(invocation);
this.group = MetricsSupport.getGroup(invocation);
this.version = MetricsSupport.getVersion(invocation);
this.methodName = serviceLevel ? null : RpcUtils.getMethodName(invocation);
}
public static boolean isServiceLevel(ApplicationModel applicationModel) {
if(applicationModel == null){
return false;
}
ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager();
if (applicationConfigManager == null) {
return false;
}
Optional<MetricsConfig> metrics = applicationConfigManager.getMetrics();
if (!metrics.isPresent()) {
return false;
}
String rpcLevel = metrics.map(MetricsConfig::getRpcLevel).orElse(MetricsLevel.METHOD.name());
rpcLevel = StringUtils.isBlank(rpcLevel) ? MetricsLevel.METHOD.name() : rpcLevel;
return MetricsLevel.SERVICE.name().equalsIgnoreCase(rpcLevel);
}
public String getGroup() {
@ -82,13 +106,13 @@ public class MethodMetric extends ServiceKeyMetric {
@Override
public String toString() {
return "MethodMetric{" +
"applicationName='" + getApplicationName() + '\'' +
", side='" + side + '\'' +
", interfaceName='" + getServiceKey() + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
"applicationName='" + getApplicationName() + '\'' +
", side='" + side + '\'' +
", interfaceName='" + getServiceKey() + '\'' +
", methodName='" + methodName + '\'' +
", group='" + group + '\'' +
", version='" + version + '\'' +
'}';
}
@Override
@ -100,6 +124,7 @@ public class MethodMetric extends ServiceKeyMetric {
}
private volatile int hashCode = 0;
@Override
public int hashCode() {
if (hashCode == 0) {

View File

@ -222,6 +222,11 @@ public class MetricsSupport {
collector.increment(event.getAttachmentValue(METHOD_METRICS), new MetricsKeyWrapper(metricsKey, placeType), SELF_INCREMENT_SIZE);
}
public static void init(MetricsKey metricsKey, MetricsPlaceValue placeType, MethodMetricsCollector<TimeCounterEvent> collector, MetricsEvent event) {
collector.init(event.getAttachmentValue(INVOCATION), new MetricsKeyWrapper(metricsKey, placeType));
}
/**
* Dec method num
*/

View File

@ -1,176 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.metrics.model.key;
/**
* Please follow a unified naming format as follows:
* dubbo_type_action_unit_otherfun
*/
public enum MetricsKey {
APPLICATION_METRIC_INFO("application.info.total", "Total Application Info"),
CONFIGCENTER_METRIC_TOTAL("configcenter.total", "Config Changed Total"),
// provider metrics key
METRIC_REQUESTS("requests.total", "Total Requests"),
METRIC_REQUESTS_SUCCEED("requests.succeed.total", "Total Succeed Requests"),
METRIC_REQUEST_BUSINESS_FAILED("requests.business.failed.total", "Total Failed Business Requests"),
METRIC_REQUESTS_PROCESSING("requests.processing.total", "Processing Requests"),
METRIC_REQUESTS_TIMEOUT("requests.timeout.total", "Total Timeout Failed Requests"),
METRIC_REQUESTS_LIMIT("requests.limit.total", "Total Limit Failed Requests"),
METRIC_REQUESTS_FAILED("requests.unknown.failed.total", "Total Unknown Failed Requests"),
METRIC_REQUESTS_TOTAL_FAILED("requests.failed.total", "Total Failed Requests"),
METRIC_REQUESTS_NETWORK_FAILED("requests.failed.network.total", "Total network Failed Requests"),
METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED("requests.failed.service.unavailable.total", "Total Service Unavailable Failed Requests"),
METRIC_REQUESTS_CODEC_FAILED("requests.failed.codec.total", "Total Codec Failed Requests"),
METRIC_REQUESTS_TOTAL_AGG("requests.total.aggregate", "Aggregated Total Requests"),
METRIC_REQUESTS_SUCCEED_AGG("requests.succeed.aggregate", "Aggregated Succeed Requests"),
METRIC_REQUESTS_FAILED_AGG("requests.failed.aggregate", "Aggregated Failed Requests"),
METRIC_REQUEST_BUSINESS_FAILED_AGG("requests.business.failed.aggregate", "Aggregated Business Failed Requests"),
METRIC_REQUESTS_TIMEOUT_AGG("requests.timeout.failed.aggregate", "Aggregated timeout Failed Requests"),
METRIC_REQUESTS_LIMIT_AGG("requests.limit.aggregate", "Aggregated limit Requests"),
METRIC_REQUESTS_TOTAL_FAILED_AGG("requests.failed.total.aggregate", "Aggregated failed total Requests"),
METRIC_REQUESTS_NETWORK_FAILED_AGG("requests.failed.network.total.aggregate", "Aggregated failed network total Requests"),
METRIC_REQUESTS_CODEC_FAILED_AGG("requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG("requests.failed.service.unavailable.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_QPS("qps.total", "Query Per Seconds"),
METRIC_RT_LAST("rt.milliseconds.last", "Last Response Time"),
METRIC_RT_MIN("rt.milliseconds.min", "Min Response Time"),
METRIC_RT_MAX("rt.milliseconds.max", "Max Response Time"),
METRIC_RT_SUM("rt.milliseconds.sum", "Sum Response Time"),
METRIC_RT_AVG("rt.milliseconds.avg", "Average Response Time"),
METRIC_RT_P99("rt.milliseconds.p99", "Response Time P99"),
METRIC_RT_P95("rt.milliseconds.p95", "Response Time P95"),
METRIC_RT_P90("rt.milliseconds.p90", "Response Time P90"),
METRIC_RT_P50("rt.milliseconds.p50", "Response Time P50"),
METRIC_RT_MIN_AGG("rt.milliseconds.min.aggregate", "Aggregated Min Response"),
METRIC_RT_MAX_AGG("rt.milliseconds.max.aggregate", "Aggregated Max Response"),
METRIC_RT_AVG_AGG("rt.milliseconds.avg.aggregate", "Aggregated Avg Response"),
// register metrics key
REGISTER_METRIC_REQUESTS("registry.register.requests.total", "Total Register Requests"),
REGISTER_METRIC_REQUESTS_SUCCEED("registry.register.requests.succeed.total", "Succeed Register Requests"),
REGISTER_METRIC_REQUESTS_FAILED("registry.register.requests.failed.total", "Failed Register Requests"),
METRIC_RT_HISTOGRAM("rt.milliseconds.histogram", "Response Time Histogram"),
GENERIC_METRIC_REQUESTS("requests.total", "Total %s Requests"),
GENERIC_METRIC_REQUESTS_SUCCEED("requests.succeed.total", "Succeed %s Requests"),
GENERIC_METRIC_REQUESTS_FAILED("requests.failed.total", "Failed %s Requests"),
// subscribe metrics key
SUBSCRIBE_METRIC_NUM("registry.subscribe.num.total", "Total Subscribe Num"),
SUBSCRIBE_METRIC_NUM_SUCCEED("registry.subscribe.num.succeed.total", "Succeed Subscribe Num"),
SUBSCRIBE_METRIC_NUM_FAILED("registry.subscribe.num.failed.total", "Failed Subscribe Num"),
// directory metrics key
DIRECTORY_METRIC_NUM_ALL("registry.directory.num.all", "All Directory Urls"),
DIRECTORY_METRIC_NUM_VALID("registry.directory.num.valid.total", "Valid Directory Urls"),
DIRECTORY_METRIC_NUM_TO_RECONNECT("registry.directory.num.to_reconnect.total", "ToReconnect Directory Urls"),
DIRECTORY_METRIC_NUM_DISABLE("registry.directory.num.disable.total", "Disable Directory Urls"),
NOTIFY_METRIC_REQUESTS("registry.notify.requests.total", "Total Notify Requests"),
NOTIFY_METRIC_NUM_LAST("registry.notify.num.last", "Last Notify Nums"),
THREAD_POOL_CORE_SIZE("thread.pool.core.size", "Thread Pool Core Size"),
THREAD_POOL_LARGEST_SIZE("thread.pool.largest.size", "Thread Pool Largest Size"),
THREAD_POOL_MAX_SIZE("thread.pool.max.size", "Thread Pool Max Size"),
THREAD_POOL_ACTIVE_SIZE("thread.pool.active.size", "Thread Pool Active Size"),
THREAD_POOL_THREAD_COUNT("thread.pool.thread.count", "Thread Pool Thread Count"),
THREAD_POOL_QUEUE_SIZE("thread.pool.queue.size", "Thread Pool Queue Size"),
THREAD_POOL_THREAD_REJECT_COUNT("thread.pool.reject.thread.count", "Thread Pool Reject Thread Count"),
// metadata push metrics key
METADATA_PUSH_METRIC_NUM("metadata.push.num.total", "Total Push Num"),
METADATA_PUSH_METRIC_NUM_SUCCEED("metadata.push.num.succeed.total", "Succeed Push Num"),
METADATA_PUSH_METRIC_NUM_FAILED("metadata.push.num.failed.total", "Failed Push Num"),
// metadata subscribe metrics key
METADATA_SUBSCRIBE_METRIC_NUM("metadata.subscribe.num.total", "Total Metadata Subscribe Num"),
METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED("metadata.subscribe.num.succeed.total", "Succeed Metadata Subscribe Num"),
METADATA_SUBSCRIBE_METRIC_NUM_FAILED("metadata.subscribe.num.failed.total", "Failed Metadata Subscribe Num"),
// register service metrics key
SERVICE_REGISTER_METRIC_REQUESTS("registry.total", "Total Service-Level Register Requests"),
SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED("registry.succeed.total", "Succeed Service-Level Register Requests"),
SERVICE_REGISTER_METRIC_REQUESTS_FAILED("registry.failed.total", "Failed Service-Level Register Requests"),
// subscribe metrics key
SERVICE_SUBSCRIBE_METRIC_NUM("registry.subscribe.service.num.total", "Total Service-Level Subscribe Num"),
SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED("registry.subscribe.service.num.succeed.total", "Succeed Service-Level Num"),
SERVICE_SUBSCRIBE_METRIC_NUM_FAILED("registry.subscribe.service.num.failed.total", "Failed Service-Level Num"),
// store provider metadata service key
STORE_PROVIDER_METADATA("metadata.store.provider.total", "Store Provider Metadata"),
STORE_PROVIDER_METADATA_SUCCEED("metadata.store.provider.succeed.total", "Succeed Store Provider Metadata"),
STORE_PROVIDER_METADATA_FAILED("metadata.store.provider.failed.total", "Failed Store Provider Metadata"),
METADATA_GIT_COMMITID_METRIC("git.commit.id", "Git Commit Id Metrics"),
// consumer metrics key
INVOKER_NO_AVAILABLE_COUNT("consumer.invoker.no.available.count", "Request Throw No Invoker Available Exception Count"),
// count the number of occurrences of each error code
ERROR_CODE_COUNT("dubbo.error.code.count","The Count Of Occurrences for Each Error Code"),
// netty metrics key
NETTY_ALLOCATOR_HEAP_MEMORY_USED("netty.allocator.memory.used", "Netty Allocator Memory Used"),
NETTY_ALLOCATOR_DIRECT_MEMORY_USED("netty.allocator.direct.memory.used", "Netty Allocator Direct Memory Used"),
NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY("netty.allocator.pinned.direct.memory", "Netty Allocator Pinned Direct Memory"),
NETTY_ALLOCATOR_PINNED_HEAP_MEMORY("netty.allocator.pinned.heap.memory", "Netty Allocator Pinned Heap Memory"),
NETTY_ALLOCATOR_HEAP_ARENAS_NUM("netty.allocator.heap.arenas.num", "Netty Allocator Heap Arenas Num"),
NETTY_ALLOCATOR_DIRECT_ARENAS_NUM("netty.allocator.direct.arenas.num", "Netty Allocator Direct Arenas Num"),
NETTY_ALLOCATOR_NORMAL_CACHE_SIZE("netty.allocator.normal.cache.size", "Netty Allocator Normal Cache Size"),
NETTY_ALLOCATOR_SMALL_CACHE_SIZE("netty.allocator.small.cache.size", "Netty Allocator Small Cache Size"),
NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM("netty.allocator.thread.local.caches.num", "Netty Allocator Thread Local Caches Num"),
NETTY_ALLOCATOR_CHUNK_SIZE("netty.allocator.chunk.size", "Netty Allocator Chunk Size"),
;
private String nameSuffix;
private String description;
public final String getName() {
return "dubbo." + nameSuffix;
}
public final String getNameByType(String type) {
return "dubbo." + type + "." + nameSuffix;
}
public static MetricsKey getMetricsByName(String name){
for (MetricsKey metricsKey : MetricsKey.values()) {
if (metricsKey.getName().equals(name)) {
return metricsKey;
}
}
return null;
}
public final String getDescription() {
return this.description;
}
MetricsKey(String nameSuffix, String description) {
this.nameSuffix = nameSuffix;
this.description = description;
}
}

View File

@ -85,7 +85,7 @@ public class MetricsKeyWrapper {
return metricsKey.getName();
}
try {
return metricsKey.getNameByType(getType());
return String.format(metricsKey.getName(), getType());
} catch (Exception ignore) {
return metricsKey.getName();
}

View File

@ -58,16 +58,6 @@ public class SimpleMetricsEventMulticasterTest {
}
@Test
void testPublishEvent() {
// emptyEvent do nothing
MetricsEvent emptyEvent = EmptyEvent.instance();
eventMulticaster.publishEvent(emptyEvent);
Assertions.assertSame(obj, objects[0]);
}
@Test
void testPublishFinishEvent() {

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.metrics;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
@ -69,4 +70,28 @@ public interface DefaultConstants {
new MetricsKeyWrapper(METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),
new MetricsKeyWrapper(METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD))
);
List<MetricsKey> INIT_AGG_METHOD_KEYS = Arrays.asList(
MetricsKey.METRIC_REQUESTS_TOTAL_AGG,
MetricsKey.METRIC_REQUESTS_SUCCEED_AGG,
MetricsKey.METRIC_REQUESTS_FAILED_AGG,
MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG,
MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG,
MetricsKey.METRIC_REQUESTS_LIMIT_AGG,
MetricsKey.METRIC_REQUESTS_TOTAL_FAILED_AGG,
MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG,
MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG,
MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG
);
List<MetricsKey> INIT_DEFAULT_METHOD_KEYS = Arrays.asList(
MetricsKey.METRIC_REQUESTS,
MetricsKey.METRIC_REQUESTS_PROCESSING,
MetricsKey.METRIC_REQUESTS_FAILED_AGG,
MetricsKey.METRIC_REQUESTS_SUCCEED,
MetricsKey.METRIC_REQUESTS_TOTAL_FAILED,
MetricsKey.METRIC_REQUEST_BUSINESS_FAILED
);
}

View File

@ -43,9 +43,11 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.metrics.DefaultConstants.INIT_AGG_METHOD_KEYS;
import static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;
import static org.apache.dubbo.metrics.model.MetricsCategory.QPS;
import static org.apache.dubbo.metrics.model.MetricsCategory.REQUESTS;
@ -75,6 +77,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
private final ConcurrentMap<MethodMetric, TimeWindowAggregator> rtAgr = new ConcurrentHashMap<>();
private boolean serviceLevel;
public AggregateMetricsCollector(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
@ -95,6 +98,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
this.enableRt = Optional.ofNullable(aggregation.getEnableRt()).orElse(true);
this.enableRequest = Optional.ofNullable(aggregation.getEnableRequest()).orElse(true);
}
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
}
@ -124,7 +128,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
if (enableQps) {
MethodMetric metric = calcWindowCounter(event, MetricsKey.METRIC_REQUESTS);
TimeWindowCounter qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(qps, metric,
methodMetric -> new TimeWindowCounter(bucketNum, qpsTimeWindowMillSeconds));
methodMetric -> new TimeWindowCounter(bucketNum, TimeUnit.MILLISECONDS.toSeconds(qpsTimeWindowMillSeconds)));
qpsCounter.increment();
}
}
@ -156,7 +160,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
}
private void onRTEvent(RequestEvent event) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
long responseTime = event.getTimePair().calc();
if (enableRt) {
TimeWindowQuantile quantile = ConcurrentHashMapUtils.computeIfAbsent(rt, metric,
@ -175,7 +179,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
private MethodMetric calcWindowCounter(RequestEvent event, MetricsKey targetKey) {
MetricsPlaceValue placeType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE);
MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, placeType);
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
@ -188,7 +192,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
@Override
public List<MetricSample> collect() {
List<MetricSample> list = new ArrayList<>();
if (!isCollectEnabled()){
if (!isCollectEnabled()) {
return list;
}
collectRequests(list);
@ -262,4 +266,47 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).getEventMulticaster().addListener(this);
}
@Override
public void initMetrics(MetricsEvent event) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
if (enableQps) {
initMethodMetric(event);
initQpsMetric(metric);
}
if (enableRt) {
initRtMetric(metric);
}
if (enableRtPxx) {
initRtAgrMetric(metric);
}
}
public void initMethodMetric(MetricsEvent event) {
INIT_AGG_METHOD_KEYS.stream().forEach(key -> initWindowCounter(event, key));
}
public void initQpsMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
}
public void initRtMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));
}
public void initRtAgrMetric(MethodMetric metric) {
ConcurrentHashMapUtils.computeIfAbsent(rtAgr, metric, k -> new TimeWindowAggregator(bucketNum, timeWindowSeconds));
}
public void initWindowCounter(MetricsEvent event, MetricsKey targetKey) {
MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
ConcurrentHashMapUtils.computeIfAbsent(counter, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
}
}

View File

@ -20,6 +20,7 @@ package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.DefaultConstants;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler;
import org.apache.dubbo.metrics.collector.sample.MetricsSampler;
import org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler;
@ -30,9 +31,12 @@ import org.apache.dubbo.metrics.data.MethodStatComposite;
import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.event.DefaultSubDispatcher;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.MetricsInitEvent;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.event.TimeCounterEvent;
import org.apache.dubbo.metrics.model.ApplicationMetric;
import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
@ -41,9 +45,12 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.metrics.DefaultConstants.INIT_DEFAULT_METHOD_KEYS;
import static org.apache.dubbo.metrics.model.MetricsCategory.APPLICATION;
import static org.apache.dubbo.metrics.model.key.MetricsKey.APPLICATION_METRIC_INFO;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;
/**
* Default implementation of {@link MetricsCollector}
@ -55,6 +62,8 @@ public class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent>
private volatile boolean threadpoolCollectEnabled = false;
private volatile boolean metricsInitEnabled = true;
private final ThreadPoolMetricsSampler threadPoolSampler = new ThreadPoolMetricsSampler(this);
private final ErrorCodeSampler errorCodeSampler;
@ -65,6 +74,11 @@ public class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent>
private final List<MetricsSampler> samplers = new ArrayList<>();
private final List<MetricsCollector> collectors = new ArrayList<>();
private final AtomicBoolean initialized = new AtomicBoolean();
public DefaultMetricsCollector(ApplicationModel applicationModel) {
super(new BaseStatComposite(applicationModel) {
@Override
@ -120,6 +134,14 @@ public class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent>
this.threadpoolCollectEnabled = threadpoolCollectEnabled;
}
public boolean isMetricsInitEnabled() {
return metricsInitEnabled;
}
public void setMetricsInitEnabled(boolean metricsInitEnabled) {
this.metricsInitEnabled = metricsInitEnabled;
}
public void collectApplication() {
this.setApplicationName(applicationModel.getApplicationName());
applicationSampler.inc(applicationName, MetricsEvent.Type.APPLICATION_INFO);
@ -146,7 +168,29 @@ public class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent>
@Override
public boolean isSupport(MetricsEvent event) {
return event instanceof RequestEvent;
return event instanceof RequestEvent || event instanceof MetricsInitEvent;
}
@Override
public void onEvent(TimeCounterEvent event) {
if(event instanceof MetricsInitEvent){
if (!metricsInitEnabled) {
return;
}
if(initialized.compareAndSet(false,true)) {
collectors.addAll(applicationModel.getBeanFactory().getBeansOfType(MetricsCollector.class));
}
collectors.stream().forEach(collector->collector.initMetrics(event));
return;
}
super.onEvent(event);
}
@Override
public void initMetrics(MetricsEvent event) {
MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);
INIT_DEFAULT_METHOD_KEYS.stream().forEach(key->MetricsSupport.init(key, dynamicPlaceType, (MethodMetricsCollector) this, event));
MetricsSupport.init(METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD), (MethodMetricsCollector) this, event);
}
public SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric> applicationSampler = new SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric>() {

View File

@ -48,6 +48,8 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
private static final Integer[] DEFAULT_BUCKETS_MS = new Integer[]{100, 300, 500, 1000, 3000, 5000, 10000};
private boolean serviceLevel;
public HistogramMetricsCollector(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
@ -68,6 +70,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
}
metricRegister = new HistogramMetricRegister(MetricsGlobalRegistry.getCompositeRegistry(applicationModel), histogram);
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
}
@ -92,7 +95,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
private void onRTEvent(RequestEvent event) {
if (metricRegister != null) {
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
long responseTime = event.getTimePair().calc();
HistogramMetricSample sample = new HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),

View File

@ -34,10 +34,10 @@ public class MetricThreadPoolExhaustedListener implements ThreadPoolExhaustedLis
public MetricThreadPoolExhaustedListener(String threadPoolExecutorName,ThreadRejectMetricsCountSampler sampler) {
this.threadPoolExecutorName=threadPoolExecutorName;
this.threadRejectMetricsCountSampler=sampler;
this.threadRejectMetricsCountSampler.addMetricName(threadPoolExecutorName);
}
@Override
public void onEvent(ThreadPoolExhaustedEvent event) {
threadRejectMetricsCountSampler.addMetricName(threadPoolExecutorName);
threadRejectMetricsCountSampler.inc(threadPoolExecutorName,threadPoolExecutorName);
}
}

View File

@ -56,8 +56,8 @@ public class RequestEvent extends TimeCounterEvent {
public static RequestEvent toRequestEvent(ApplicationModel applicationModel, String appName,
MetricsDispatcher metricsDispatcher, DefaultMetricsCollector collector,
Invocation invocation, String side) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
Invocation invocation, String side, boolean serviceLevel) {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
RequestEvent requestEvent = new RequestEvent(applicationModel, appName, metricsDispatcher, collector, REQUEST_EVENT);
requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
requestEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);
@ -80,13 +80,13 @@ public class RequestEvent extends TimeCounterEvent {
/**
* Acts on MetricsClusterFilter to monitor exceptions that occur before request execution
*/
public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code) {
public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code, boolean serviceLevel) {
RequestEvent event = new RequestEvent(applicationModel, appName, metricsDispatcher, null, REQUEST_ERROR_EVENT);
event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
event.putAttachment(MetricsConstants.INVOCATION_SIDE, side);
event.putAttachment(MetricsConstants.INVOCATION, invocation);
event.putAttachment(MetricsConstants.INVOCATION_REQUEST_ERROR, code);
event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation));
event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation, serviceLevel));
return event;
}

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -45,6 +46,7 @@ public class MetricsFilter implements ScopeModelAware {
private String appName;
private MetricsDispatcher metricsDispatcher;
private DefaultMetricsCollector defaultMetricsCollector;
private boolean serviceLevel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
@ -53,6 +55,7 @@ public class MetricsFilter implements ScopeModelAware {
this.appName = applicationModel.tryGetApplicationName();
this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
this.defaultMetricsCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
@ -63,7 +66,7 @@ public class MetricsFilter implements ScopeModelAware {
if (rpcMetricsEnable) {
try {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, appName, metricsDispatcher,
defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER);
defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER, serviceLevel);
MetricsEventBus.before(requestEvent);
invocation.put(METRIC_FILTER_EVENT, requestEvent);
} catch (Throwable t) {

View File

@ -17,26 +17,26 @@
package org.apache.dubbo.metrics.report;
import io.micrometer.core.instrument.FunctionCounter;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.metrics.MetricsGlobalRegistry;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.metrics.MetricsGlobalRegistry;
import org.apache.dubbo.metrics.collector.AggregateMetricsCollector;
import org.apache.dubbo.metrics.collector.MetricsCollector;
import org.apache.dubbo.metrics.collector.HistogramMetricsCollector;
import org.apache.dubbo.metrics.collector.MetricsCollector;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.model.ApplicationModel;
import io.micrometer.core.instrument.FunctionCounter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
@ -53,6 +53,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;
import static org.apache.dubbo.common.constants.MetricsConstants.ENABLE_COLLECTOR_SYNC_KEY;
import static org.apache.dubbo.common.constants.MetricsConstants.ENABLE_JVM_METRICS_KEY;
/**
@ -140,9 +141,12 @@ public abstract class AbstractMetricsReporter implements MetricsReporter {
}
private void scheduleMetricsCollectorSyncJob() {
NamedThreadFactory threadFactory = new NamedThreadFactory("metrics-collector-sync-job", true);
collectorSyncJobExecutor = Executors.newScheduledThreadPool(1, threadFactory);
collectorSyncJobExecutor.scheduleWithFixedDelay(this::refreshData, DEFAULT_SCHEDULE_INITIAL_DELAY, DEFAULT_SCHEDULE_PERIOD, TimeUnit.SECONDS);
boolean enableCollectorSync = url.getParameter(ENABLE_COLLECTOR_SYNC_KEY, true);
if (enableCollectorSync) {
NamedThreadFactory threadFactory = new NamedThreadFactory("metrics-collector-sync-job", true);
collectorSyncJobExecutor = Executors.newScheduledThreadPool(1, threadFactory);
collectorSyncJobExecutor.scheduleWithFixedDelay(this::refreshData, DEFAULT_SCHEDULE_INITIAL_DELAY, DEFAULT_SCHEDULE_PERIOD, TimeUnit.SECONDS);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -42,6 +43,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
private DefaultMetricsCollector collector;
private String appName;
private MetricsDispatcher metricsDispatcher;
private boolean serviceLevel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
@ -49,6 +51,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
this.appName = applicationModel.tryGetApplicationName();
this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
@Override
@ -73,7 +76,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
if (t instanceof RpcException) {
RpcException e = (RpcException) t;
if (e.isForbidden()) {
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode()));
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode(), serviceLevel));
}
}
}

View File

@ -38,7 +38,6 @@ import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.TimePair;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
@ -90,7 +89,7 @@ class AggregateMetricsCollectorTest {
public MethodMetric getTestMethodMetric() {
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
methodMetric.setGroup("TestGroup");
methodMetric.setVersion("1.0.0");
methodMetric.setSide("PROVIDER");
@ -141,8 +140,8 @@ class AggregateMetricsCollectorTest {
@Test
void testListener() {
AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
@ -200,7 +199,8 @@ class AggregateMetricsCollectorTest {
when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector(applicationModel));
DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel);
when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(defaultMetricsCollector);
when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig));
when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);
when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE);
@ -249,7 +249,7 @@ class AggregateMetricsCollectorTest {
rtList.add(30L);
for (Long requestTime: rtList) {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
@ -299,7 +299,7 @@ class AggregateMetricsCollectorTest {
double manualP99 = requestTimes.get((int) Math.round(p99Index));
for (Long requestTime : requestTimes) {
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));

View File

@ -19,18 +19,21 @@ package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.common.URL;
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.config.ApplicationConfig;
import org.apache.dubbo.metrics.MetricsConstants;
import org.apache.dubbo.metrics.TestMetricsInvoker;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.filter.MetricsFilter;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.MetricsSupport;
import org.apache.dubbo.metrics.model.ServiceKeyMetric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
@ -112,8 +115,8 @@ class DefaultCollectorTest {
@Test
void testListener() {
DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertTrue(metricsCollector.isSupport(event));
Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
@ -134,6 +137,9 @@ class DefaultCollectorTest {
DefaultMetricsCollector collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);
collector.setCollectEnabled(true);
ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultCollectorTest.class);
logger.warn("0-99","","","Test error code message.");
metricsFilter.invoke(new TestMetricsInvoker(side), invocation);
try {
Thread.sleep(50);
@ -150,8 +156,8 @@ class DefaultCollectorTest {
// push finish rt +1
List<MetricSample> metricSamples = collector.collect();
//num(total+success+processing) + rt(5) = 8
Assertions.assertEquals(8, metricSamples.size());
//num(total+success+processing) + rt(5) + error code = 9
Assertions.assertEquals(metricSamples.size(),9);
List<String> metricsNames = metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());
// No error will contain total+success+processing
String REQUESTS = new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
@ -192,8 +198,8 @@ class DefaultCollectorTest {
long c2 = eventObj.getTimePair().calc();
metricSamples = collector.collect();
// num(total+success+error+total_error+processing) + rt(5) = 5
Assertions.assertEquals(10, metricSamples.size());
// num(total+success+error+total_error+processing) + rt(5) + error code = 11
Assertions.assertEquals(11, metricSamples.size());
String TIMEOUT = new MetricsKeyWrapper(METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
String TOTAL_FAILED = new MetricsKeyWrapper(METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();

View File

@ -0,0 +1,153 @@
/*
* 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.metrics.collector;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.MetricsInitEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.ServiceKeyMetric;
import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import static org.apache.dubbo.metrics.DefaultConstants.INIT_AGG_METHOD_KEYS;
import static org.apache.dubbo.metrics.DefaultConstants.INIT_DEFAULT_METHOD_KEYS;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;
import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;
class InitServiceMetricsTest {
private ApplicationModel applicationModel;
private String interfaceName;
private String methodName;
private String group;
private String version;
private String side;
private DefaultMetricsCollector defaultCollector;
private AggregateMetricsCollector aggregateMetricsCollector;
@BeforeEach
public void setup() {
FrameworkModel frameworkModel = FrameworkModel.defaultModel();
applicationModel = frameworkModel.newApplication();
ApplicationConfig config = new ApplicationConfig();
config.setName("MockMetrics");
MetricsConfig metricsConfig = new MetricsConfig();
AggregationConfig aggregationConfig = new AggregationConfig();
aggregationConfig.setEnabled(true);
aggregationConfig.setBucketNum(12);
aggregationConfig.setTimeWindowSeconds(120);
metricsConfig.setAggregation(aggregationConfig);
applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);
applicationModel.getApplicationConfigManager().setApplication(config);
defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
defaultCollector.setCollectEnabled(true);
aggregateMetricsCollector = applicationModel.getBeanFactory().getOrRegisterBean(AggregateMetricsCollector.class);
aggregateMetricsCollector.setCollectEnabled(true);
interfaceName = "org.apache.dubbo.MockInterface";
methodName = "mockMethod";
group = "mockGroup";
version = "1.0.0";
side = CommonConstants.PROVIDER_SIDE;
String serviceKey=group+"/"+interfaceName+":"+version;
String protocolServiceKey=serviceKey+":dubbo";
RpcInvocation invocation = new RpcInvocation(serviceKey,null,methodName,interfaceName, protocolServiceKey, null, null,null,null,null,null);
MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation, MethodMetric.isServiceLevel(applicationModel)));
}
@AfterEach
public void teardown() {
applicationModel.destroy();
}
@Test
void testMetricsInitEvent() {
List<MetricSample> metricSamples = defaultCollector.collect();
//INIT_DEFAULT_METHOD_KEYS.size() = 6
Assertions.assertEquals(INIT_DEFAULT_METHOD_KEYS.size(), metricSamples.size());
List<String> metricsNames = metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());
String REQUESTS = new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
String PROCESSING = new MetricsKeyWrapper(METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
Assertions.assertTrue(metricsNames.contains(REQUESTS));
Assertions.assertTrue(metricsNames.contains(PROCESSING));
for (MetricSample metricSample : metricSamples) {
if (metricSample instanceof GaugeMetricSample) {
GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;
Object objVal = gaugeMetricSample.getValue();
if (objVal instanceof Map) {
Map<ServiceKeyMetric, AtomicLong> value = (Map<ServiceKeyMetric, AtomicLong>) objVal;
Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));
}
} else {
AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();
Assertions.assertEquals(0, value.intValue());
}
}
List<MetricSample> samples = aggregateMetricsCollector.collect();
//INIT_AGG_METHOD_KEYS.size(10) + qps(1) + rt(4) +rtAgr(3)= 18
Assertions.assertEquals(INIT_AGG_METHOD_KEYS.size()+ 1+ 4+ 3, samples.size());
for (MetricSample metricSample : samples) {
if (metricSample instanceof GaugeMetricSample) {
GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;
Object objVal = gaugeMetricSample.getValue();
if (objVal instanceof TimeWindowCounter) {
Assertions.assertEquals(0.0,((TimeWindowCounter) objVal).get());
}
}
}
}
}

View File

@ -19,7 +19,9 @@ package org.apache.dubbo.metrics.metrics.model;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.key.MetricsLevel;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -72,7 +74,7 @@ class MethodMetricTest {
@Test
void test() {
MethodMetric metric = new MethodMetric(applicationModel, invocation);
MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertEquals(metric.getServiceKey(), interfaceName);
Assertions.assertEquals(metric.getMethodName(), methodName);
Assertions.assertEquals(metric.getGroup(), group);
@ -88,4 +90,24 @@ class MethodMetricTest {
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
@Test
void testServiceMetrics() {
MetricsConfig metricConfig = new MetricsConfig();
applicationModel.getApplicationConfigManager().setMetrics(metricConfig);
metricConfig.setRpcLevel(MetricsLevel.SERVICE.name());
MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
Assertions.assertEquals(metric.getServiceKey(), interfaceName);
Assertions.assertNull(metric.getMethodName(), methodName);
Assertions.assertEquals(metric.getGroup(), group);
Assertions.assertEquals(metric.getVersion(), version);
Map<String, String> tags = metric.getTags();
Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());
Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
Assertions.assertNull(tags.get(TAG_METHOD_KEY));
Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
}
}

View File

@ -0,0 +1,42 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>dubbo-metrics-event</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>The metrics event-related api module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -19,7 +19,6 @@ package org.apache.dubbo.metrics.event;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.metrics.exception.MetricsNeverHappenException;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.key.TypeWrapper;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -33,13 +32,13 @@ import java.util.Map;
public abstract class MetricsEvent {
/**
* Metric object. (eg. {@link MethodMetric})
* Metric object. (eg. MethodMetric)
*/
protected transient final ApplicationModel source;
private boolean available = true;
private final TypeWrapper typeWrapper;
private final String appName;
private final MetricsDispatcher metricsDispatcher;
private final MetricsEventMulticaster metricsEventMulticaster;
private final Map<String, Object> attachments = new IdentityHashMap<>(8);
@ -47,7 +46,7 @@ public abstract class MetricsEvent {
this(source, null, null, typeWrapper);
}
public MetricsEvent(ApplicationModel source, String appName, MetricsDispatcher metricsDispatcher, TypeWrapper typeWrapper) {
public MetricsEvent(ApplicationModel source, String appName, MetricsEventMulticaster metricsEventMulticaster, TypeWrapper typeWrapper) {
this.typeWrapper = typeWrapper;
if (source == null) {
this.source = ApplicationModel.defaultModel();
@ -56,20 +55,20 @@ public abstract class MetricsEvent {
} else {
this.source = source;
}
if (metricsDispatcher == null) {
if (metricsEventMulticaster == null) {
if (this.source.isDestroyed()) {
this.metricsDispatcher = null;
this.metricsEventMulticaster = null;
} else {
ScopeBeanFactory beanFactory = this.source.getBeanFactory();
if (beanFactory.isDestroyed()) {
this.metricsDispatcher = null;
this.metricsEventMulticaster = null;
} else {
MetricsDispatcher dispatcher = beanFactory.getBean(MetricsDispatcher.class);
this.metricsDispatcher = dispatcher;
MetricsEventMulticaster dispatcher = beanFactory.getBean(MetricsEventMulticaster.class);
this.metricsEventMulticaster = dispatcher;
}
}
} else {
this.metricsDispatcher = metricsDispatcher;
this.metricsEventMulticaster = metricsEventMulticaster;
}
if (appName == null) {
this.appName = this.source.tryGetApplicationName();
@ -115,8 +114,8 @@ public abstract class MetricsEvent {
return source;
}
public MetricsDispatcher getMetricsDispatcher() {
return metricsDispatcher;
public MetricsEventMulticaster getMetricsEventMulticaster() {
return metricsEventMulticaster;
}
public String appName() {

View File

@ -42,7 +42,7 @@ public class MetricsEventBus {
if (event.getSource() == null) {
return;
}
MetricsDispatcher dispatcher = event.getMetricsDispatcher();
MetricsEventMulticaster dispatcher = event.getMetricsEventMulticaster();
Optional.ofNullable(dispatcher).ifPresent(d -> {
tryInvoke(() -> d.publishEvent(event));
});
@ -106,13 +106,14 @@ public class MetricsEventBus {
* eventSaveRunner saves the event, so that the calculation rt is introverted
*/
public static void before(MetricsEvent event) {
MetricsDispatcher dispatcher = validate(event);
MetricsEventMulticaster dispatcher = validate(event);
if (dispatcher == null) return;
tryInvoke(() -> dispatcher.publishEvent(event));
}
public static void after(MetricsEvent event, Object result) {
MetricsDispatcher dispatcher = validate(event);
MetricsEventMulticaster dispatcher = validate(event);
if (dispatcher == null) return;
tryInvoke(() -> {
event.customAfterPost(result);
@ -121,13 +122,13 @@ public class MetricsEventBus {
}
public static void error(MetricsEvent event) {
MetricsDispatcher dispatcher = validate(event);
MetricsEventMulticaster dispatcher = validate(event);
if (dispatcher == null) return;
tryInvoke(() -> dispatcher.publishErrorEvent((TimeCounterEvent) event));
}
private static MetricsDispatcher validate(MetricsEvent event) {
MetricsDispatcher dispatcher = event.getMetricsDispatcher();
private static MetricsEventMulticaster validate(MetricsEvent event) {
MetricsEventMulticaster dispatcher = event.getMetricsEventMulticaster();
if (dispatcher == null) {
return null;
}

View File

@ -33,7 +33,7 @@ public abstract class TimeCounterEvent extends MetricsEvent {
this.timePair = TimePair.start();
}
public TimeCounterEvent(ApplicationModel source, String appName, MetricsDispatcher metricsDispatcher, TypeWrapper typeWrapper) {
public TimeCounterEvent(ApplicationModel source, String appName,MetricsEventMulticaster metricsDispatcher, TypeWrapper typeWrapper) {
super(source, appName, metricsDispatcher, typeWrapper);
this.timePair = TimePair.start();
}

View File

@ -0,0 +1,171 @@
/*
* 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.metrics.model.key;
public enum MetricsKey {
APPLICATION_METRIC_INFO("dubbo.application.info.total", "Total Application Info"),
CONFIGCENTER_METRIC_TOTAL("dubbo.configcenter.total", "Config Changed Total"),
// provider metrics key
METRIC_REQUESTS("dubbo.%s.requests.total", "Total Requests"),
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.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"),
METRIC_REQUESTS_TOTAL_FAILED("dubbo.%s.requests.failed.total", "Total Failed Requests"),
METRIC_REQUESTS_NETWORK_FAILED("dubbo.%s.requests.failed.network.total", "Total network Failed Requests"),
METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED("dubbo.%s.requests.failed.service.unavailable.total", "Total Service Unavailable Failed Requests"),
METRIC_REQUESTS_CODEC_FAILED("dubbo.%s.requests.failed.codec.total", "Total Codec Failed Requests"),
METRIC_REQUESTS_TOTAL_AGG("dubbo.%s.requests.total.aggregate", "Aggregated Total Requests"),
METRIC_REQUESTS_SUCCEED_AGG("dubbo.%s.requests.succeed.aggregate", "Aggregated Succeed Requests"),
METRIC_REQUESTS_FAILED_AGG("dubbo.%s.requests.failed.aggregate", "Aggregated Failed Requests"),
METRIC_REQUEST_BUSINESS_FAILED_AGG("dubbo.%s.requests.business.failed.aggregate", "Aggregated Business Failed Requests"),
METRIC_REQUESTS_TIMEOUT_AGG("dubbo.%s.requests.timeout.failed.aggregate", "Aggregated timeout Failed Requests"),
METRIC_REQUESTS_LIMIT_AGG("dubbo.%s.requests.limit.aggregate", "Aggregated limit Requests"),
METRIC_REQUESTS_TOTAL_FAILED_AGG("dubbo.%s.requests.failed.total.aggregate", "Aggregated failed total Requests"),
METRIC_REQUESTS_NETWORK_FAILED_AGG("dubbo.%s.requests.failed.network.total.aggregate", "Aggregated failed network total Requests"),
METRIC_REQUESTS_CODEC_FAILED_AGG("dubbo.%s.requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG("dubbo.%s.requests.failed.service.unavailable.total.aggregate", "Aggregated failed codec total Requests"),
METRIC_QPS("dubbo.%s.qps.total", "Query Per Seconds"),
METRIC_RT_LAST("dubbo.%s.rt.milliseconds.last", "Last Response Time"),
METRIC_RT_MIN("dubbo.%s.rt.milliseconds.min", "Min Response Time"),
METRIC_RT_MAX("dubbo.%s.rt.milliseconds.max", "Max Response Time"),
METRIC_RT_SUM("dubbo.%s.rt.milliseconds.sum", "Sum Response Time"),
METRIC_RT_AVG("dubbo.%s.rt.milliseconds.avg", "Average Response Time"),
METRIC_RT_P99("dubbo.%s.rt.milliseconds.p99", "Response Time P99"),
METRIC_RT_P95("dubbo.%s.rt.milliseconds.p95", "Response Time P95"),
METRIC_RT_P90("dubbo.%s.rt.milliseconds.p90", "Response Time P90"),
METRIC_RT_P50("dubbo.%s.rt.milliseconds.p50", "Response Time P50"),
METRIC_RT_MIN_AGG("dubbo.%s.rt.min.milliseconds.aggregate", "Aggregated Min Response"),
METRIC_RT_MAX_AGG("dubbo.%s.rt.max.milliseconds.aggregate", "Aggregated Max Response"),
METRIC_RT_AVG_AGG("dubbo.%s.rt.avg.milliseconds.aggregate", "Aggregated Avg Response"),
// register metrics key
REGISTER_METRIC_REQUESTS("dubbo.registry.register.requests.total", "Total Register Requests"),
REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.requests.succeed.total", "Succeed Register Requests"),
REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.requests.failed.total", "Failed Register Requests"),
METRIC_RT_HISTOGRAM("dubbo.%s.rt.milliseconds.histogram", "Response Time Histogram"),
GENERIC_METRIC_REQUESTS("dubbo.%s.requests.total", "Total %s Requests"),
GENERIC_METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Succeed %s Requests"),
GENERIC_METRIC_REQUESTS_FAILED("dubbo.%s.requests.failed.total", "Failed %s Requests"),
// subscribe metrics key
SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.num.total", "Total Subscribe Num"),
SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.num.succeed.total", "Succeed Subscribe Num"),
SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.num.failed.total", "Failed Subscribe Num"),
// directory metrics key
DIRECTORY_METRIC_NUM_ALL("dubbo.registry.directory.num.all", "All Directory Urls"),
DIRECTORY_METRIC_NUM_VALID("dubbo.registry.directory.num.valid.total", "Valid Directory Urls"),
DIRECTORY_METRIC_NUM_TO_RECONNECT("dubbo.registry.directory.num.to_reconnect.total", "ToReconnect Directory Urls"),
DIRECTORY_METRIC_NUM_DISABLE("dubbo.registry.directory.num.disable.total", "Disable Directory Urls"),
NOTIFY_METRIC_REQUESTS("dubbo.registry.notify.requests.total", "Total Notify Requests"),
NOTIFY_METRIC_NUM_LAST("dubbo.registry.notify.num.last", "Last Notify Nums"),
THREAD_POOL_CORE_SIZE("dubbo.thread.pool.core.size", "Thread Pool Core Size"),
THREAD_POOL_LARGEST_SIZE("dubbo.thread.pool.largest.size", "Thread Pool Largest Size"),
THREAD_POOL_MAX_SIZE("dubbo.thread.pool.max.size", "Thread Pool Max Size"),
THREAD_POOL_ACTIVE_SIZE("dubbo.thread.pool.active.size", "Thread Pool Active Size"),
THREAD_POOL_THREAD_COUNT("dubbo.thread.pool.thread.count", "Thread Pool Thread Count"),
THREAD_POOL_QUEUE_SIZE("dubbo.thread.pool.queue.size", "Thread Pool Queue Size"),
THREAD_POOL_THREAD_REJECT_COUNT("dubbo.thread.pool.reject.thread.count", "Thread Pool Reject Thread Count"),
// metadata push metrics key
METADATA_PUSH_METRIC_NUM("dubbo.metadata.push.num.total", "Total Push Num"),
METADATA_PUSH_METRIC_NUM_SUCCEED("dubbo.metadata.push.num.succeed.total", "Succeed Push Num"),
METADATA_PUSH_METRIC_NUM_FAILED("dubbo.metadata.push.num.failed.total", "Failed Push Num"),
// metadata subscribe metrics key
METADATA_SUBSCRIBE_METRIC_NUM("dubbo.metadata.subscribe.num.total", "Total Metadata Subscribe Num"),
METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.metadata.subscribe.num.succeed.total", "Succeed Metadata Subscribe Num"),
METADATA_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.metadata.subscribe.num.failed.total", "Failed Metadata Subscribe Num"),
// register service metrics key
SERVICE_REGISTER_METRIC_REQUESTS("dubbo.registry.register.service.total", "Total Service-Level Register Requests"),
SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.service.succeed.total", "Succeed Service-Level Register Requests"),
SERVICE_REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.service.failed.total", "Failed Service-Level Register Requests"),
// subscribe metrics key
SERVICE_SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.service.num.total", "Total Service-Level Subscribe Num"),
SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.service.num.succeed.total", "Succeed Service-Level Num"),
SERVICE_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.service.num.failed.total", "Failed Service-Level Num"),
// store provider metadata service key
STORE_PROVIDER_METADATA("dubbo.metadata.store.provider.total", "Store Provider Metadata"),
STORE_PROVIDER_METADATA_SUCCEED("dubbo.metadata.store.provider.succeed.total", "Succeed Store Provider Metadata"),
STORE_PROVIDER_METADATA_FAILED("dubbo.metadata.store.provider.failed.total", "Failed Store Provider Metadata"),
METADATA_GIT_COMMITID_METRIC("git.commit.id", "Git Commit Id Metrics"),
// consumer metrics key
INVOKER_NO_AVAILABLE_COUNT("dubbo.consumer.invoker.no.available.count", "Request Throw No Invoker Available Exception Count"),
// count the number of occurrences of each error code
ERROR_CODE_COUNT("dubbo.error.code.count","The Count Of Occurrences for Each Error Code"),
// netty metrics key
NETTY_ALLOCATOR_HEAP_MEMORY_USED("netty.allocator.memory.used", "Netty Allocator Memory Used"),
NETTY_ALLOCATOR_DIRECT_MEMORY_USED("netty.allocator.direct.memory.used", "Netty Allocator Direct Memory Used"),
NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY("netty.allocator.pinned.direct.memory", "Netty Allocator Pinned Direct Memory"),
NETTY_ALLOCATOR_PINNED_HEAP_MEMORY("netty.allocator.pinned.heap.memory", "Netty Allocator Pinned Heap Memory"),
NETTY_ALLOCATOR_HEAP_ARENAS_NUM("netty.allocator.heap.arenas.num", "Netty Allocator Heap Arenas Num"),
NETTY_ALLOCATOR_DIRECT_ARENAS_NUM("netty.allocator.direct.arenas.num", "Netty Allocator Direct Arenas Num"),
NETTY_ALLOCATOR_NORMAL_CACHE_SIZE("netty.allocator.normal.cache.size", "Netty Allocator Normal Cache Size"),
NETTY_ALLOCATOR_SMALL_CACHE_SIZE("netty.allocator.small.cache.size", "Netty Allocator Small Cache Size"),
NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM("netty.allocator.thread.local.caches.num", "Netty Allocator Thread Local Caches Num"),
NETTY_ALLOCATOR_CHUNK_SIZE("netty.allocator.chunk.size", "Netty Allocator Chunk Size"),
;
private String name;
private String description;
public final String getName() {
return this.name;
}
public final String getNameByType(String type) {
return String.format(name, type);
}
public static MetricsKey getMetricsByName(String name){
for (MetricsKey metricsKey : MetricsKey.values()) {
if (metricsKey.getName().equals(name)) {
return metricsKey;
}
}
return null;
}
public final String getDescription() {
return this.description;
}
MetricsKey(String name, String description) {
this.name = name;
this.description = description;
}
}

View File

@ -25,7 +25,6 @@ import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.metrics.registry.RegistryMetricsConstants;
import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;
import org.apache.dubbo.metrics.registry.event.RegistryEvent;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -222,9 +221,9 @@ public class RegistryMetricsTest {
}
List<MetricSample> samples = collector.collect();
GaugeMetricSample<?> succeedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples);
GaugeMetricSample<?> failedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples);
GaugeMetricSample<?> totalRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples);
GaugeMetricSample<?> succeedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED.getName(), samples);
GaugeMetricSample<?> failedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED.getName(), samples);
GaugeMetricSample<?> totalRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS.getName(), samples);
Assertions.assertEquals(5L, succeedRequests.applyAsLong());
Assertions.assertEquals(5L, failedRequests.applyAsLong());

View File

@ -19,6 +19,7 @@
<modelVersion>4.0.0</modelVersion>
<modules>
<module>dubbo-metrics-api</module>
<module>dubbo-metrics-event</module>
<module>dubbo-metrics-default</module>
<module>dubbo-metrics-registry</module>
<module>dubbo-metrics-metadata</module>

View File

@ -19,7 +19,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<artifactId>dubbo-plugin</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -35,6 +35,6 @@
<artifactId>dubbo-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</dependencies>
</project>

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